Merge branch 'v3.0.x-release' into docs-layout
This commit is contained in:
commit
a441d70226
2
.github/actions/merge-branches/action.yml
vendored
2
.github/actions/merge-branches/action.yml
vendored
@ -6,7 +6,7 @@ runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Checkout ${{ github.event.pull_request.base.ref || 'master' }}
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.base.ref || '' }}
|
||||
fetch-depth: 0 # Fetch all history
|
||||
|
108
.github/workflows/automated-tests.yml
vendored
108
.github/workflows/automated-tests.yml
vendored
@ -75,7 +75,7 @@ jobs:
|
||||
- package: others
|
||||
build-list: bbb-mkclean bbb-pads bbb-libreoffice-docker bbb-transcription-controller bigbluebutton bbb-livekit
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Merge branches
|
||||
uses: ./.github/actions/merge-branches
|
||||
- name: Set cache-key vars
|
||||
@ -90,7 +90,7 @@ jobs:
|
||||
- name: Handle cache
|
||||
if: matrix.cache-files-list != ''
|
||||
id: cache-action
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: artifacts.tar
|
||||
key: ${{ runner.os }}-${{ matrix.package }}-${{ env.BIGBLUEBUTTON_RELEASE }}-commits-${{ env.CACHE_KEY_FILES }}-urls-${{ env.CACHE_KEY_URLS }}
|
||||
@ -102,7 +102,7 @@ jobs:
|
||||
echo "${{ matrix.build-list || matrix.package }}" | xargs -n 1 ./build/setup.sh
|
||||
tar cvf artifacts.tar artifacts/
|
||||
- name: Archive packages
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: artifacts_${{ matrix.package }}.tar
|
||||
path: artifacts.tar
|
||||
@ -112,74 +112,76 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
shard: [1/8, 2/8, 3/8, 4/8, 5/8, 6/8, 7/8, 8/8]
|
||||
shard: [1, 2, 3, 4, 5, 6, 7, 8]
|
||||
env:
|
||||
shard: ${{ matrix.shard }}/8
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Merge branches
|
||||
uses: ./.github/actions/merge-branches
|
||||
- run: ./build/get_external_dependencies.sh
|
||||
- name: Download artifacts_bbb-apps-akka
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: artifacts_bbb-apps-akka.tar
|
||||
- run: tar xf artifacts.tar
|
||||
- name: Download artifacts_bbb-config
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: artifacts_bbb-config.tar
|
||||
- run: tar xf artifacts.tar
|
||||
- name: Download artifacts_bbb-export-annotations
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: artifacts_bbb-export-annotations.tar
|
||||
- run: tar xf artifacts.tar
|
||||
- name: Download artifacts_bbb-learning-dashboard
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: artifacts_bbb-learning-dashboard.tar
|
||||
- run: tar xf artifacts.tar
|
||||
- name: Download artifacts_bbb-playback-record
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: artifacts_bbb-playback-record.tar
|
||||
- run: tar xf artifacts.tar
|
||||
- name: Download artifacts_bbb-graphql-server
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: artifacts_bbb-graphql-server.tar
|
||||
- run: tar xf artifacts.tar
|
||||
- name: Download artifacts_bbb-etherpad
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: artifacts_bbb-etherpad.tar
|
||||
- run: tar xf artifacts.tar
|
||||
- name: Download artifacts_bbb-freeswitch
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: artifacts_bbb-freeswitch.tar
|
||||
- run: tar xf artifacts.tar
|
||||
- name: Download artifacts_bbb-webrtc
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: artifacts_bbb-webrtc.tar
|
||||
- run: tar xf artifacts.tar
|
||||
- name: Download artifacts_bbb-web
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: artifacts_bbb-web.tar
|
||||
- run: tar xf artifacts.tar
|
||||
- name: Download artifacts_bbb-fsesl-akka
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: artifacts_bbb-fsesl-akka.tar
|
||||
- run: tar xf artifacts.tar
|
||||
- name: Download artifacts_bbb-html5
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: artifacts_bbb-html5.tar
|
||||
- run: tar xf artifacts.tar
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: artifacts_others.tar
|
||||
- run: tar xf artifacts.tar
|
||||
@ -253,17 +255,22 @@ jobs:
|
||||
apt --purge -y remove apache2-bin
|
||||
'
|
||||
- name: Install BBB
|
||||
timeout-minutes: 25
|
||||
run: |
|
||||
sudo -i <<EOF
|
||||
set -e
|
||||
cd /root/ && wget -nv https://raw.githubusercontent.com/bigbluebutton/bbb-install/v3.0.x-release/bbb-install.sh -O bbb-install.sh
|
||||
cat bbb-install.sh | sed "s|> /etc/apt/sources.list.d/bigbluebutton.list||g" | bash -s -- -v jammy-30-dev -s bbb-ci.test -j -d /certs/
|
||||
bbb-conf --salt bbbci
|
||||
echo "NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/bbb-dev/bbb-dev-ca.crt" >> /usr/share/meteor/bundle/bbb-html5-with-roles.conf
|
||||
sed -i "s/\"minify\": true,/\"minify\": false,/" /usr/share/etherpad-lite/settings.json
|
||||
bbb-conf --restart
|
||||
EOF
|
||||
uses: nick-fields/retry@v3
|
||||
env:
|
||||
NODE_EXTRA_CA_CERTS: /usr/local/share/ca-certificates/bbb-dev/bbb-dev-ca.crt
|
||||
ACTIONS_RUNNER_DEBUG: true
|
||||
with:
|
||||
timeout_minutes: 25
|
||||
max_attempts: 2
|
||||
command: |
|
||||
sudo -i <<EOF
|
||||
set -e
|
||||
cd /root/ && wget -nv https://raw.githubusercontent.com/bigbluebutton/bbb-install/v3.0.x-release/bbb-install.sh -O bbb-install.sh
|
||||
cat bbb-install.sh | sed "s|> /etc/apt/sources.list.d/bigbluebutton.list||g" | bash -s -- -v jammy-30-dev -s bbb-ci.test -j -d /certs/
|
||||
bbb-conf --salt bbbci
|
||||
sed -i "s/\"minify\": true,/\"minify\": false,/" /usr/share/etherpad-lite/settings.json
|
||||
bbb-conf --restart
|
||||
EOF
|
||||
- name: List systemctl services
|
||||
timeout-minutes: 1
|
||||
run: |
|
||||
@ -279,13 +286,13 @@ jobs:
|
||||
npx playwright install
|
||||
'
|
||||
- name: Run tests
|
||||
uses: nick-fields/retry@v2
|
||||
uses: nick-fields/retry@v3
|
||||
with:
|
||||
timeout_minutes: 25
|
||||
max_attempts: 3
|
||||
max_attempts: 2
|
||||
command: |
|
||||
cd ./bigbluebutton-tests/playwright
|
||||
npm run test-chromium-ci -- --shard ${{ matrix.shard }}
|
||||
npm run test-chromium-ci -- --shard ${{ env.shard }}
|
||||
env:
|
||||
NODE_EXTRA_CA_CERTS: /usr/local/share/ca-certificates/bbb-dev/bbb-dev-ca.crt
|
||||
ACTIONS_RUNNER_DEBUG: true
|
||||
@ -305,13 +312,13 @@ jobs:
|
||||
run: |
|
||||
sh -c '
|
||||
find $HOME/.cache/ms-playwright -name libnssckbi.so -exec rm {} \; -exec ln -s /usr/lib/x86_64-linux-gnu/pkcs11/p11-kit-trust.so {} \;
|
||||
npm run test-firefox-ci -- --shard ${{ matrix.shard }}
|
||||
npm run test-firefox-ci -- --shard ${{ env.shard }}
|
||||
'
|
||||
- if: always() && github.event_name == 'pull_request'
|
||||
name: Upload blob report to GitHub Actions Artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: all-blob-reports
|
||||
name: blob-report-${{ matrix.shard }}
|
||||
path: bigbluebutton-tests/playwright/blob-report
|
||||
- if: failure()
|
||||
name: Prepare artifacts (configs and logs)
|
||||
@ -337,42 +344,55 @@ jobs:
|
||||
chmod a+r -R /home/runner/work/bigbluebutton/bigbluebutton/configs
|
||||
bbb-conf --zip
|
||||
ls -t /root/*.tar.gz | head -1 | xargs -I '{}' cp '{}' /home/runner/work/bigbluebutton/bigbluebutton/bbb-logs.tar.gz
|
||||
echo "MATRIX_SHARD=$(echo ${{ matrix.shard }} | tr '/' '_')" >> $GITHUB_ENV
|
||||
echo "MATRIX_SHARD=${{ matrix.shard }}_8" >> $GITHUB_ENV
|
||||
EOF
|
||||
- if: failure()
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: bbb-configs-${{ env.MATRIX_SHARD }}
|
||||
path: configs
|
||||
- if: failure()
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: bbb-logs-${{ env.MATRIX_SHARD }}
|
||||
path: ./bbb-logs.tar.gz
|
||||
upload-report:
|
||||
if: always()
|
||||
if: always() && !contains(github.event.head_commit.message, 'Merge pull request')
|
||||
needs: install-and-run-tests
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
hasReportData: ${{ needs.install-and-run-tests.result == 'success' || needs.install-and-run-tests.result == 'failure' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
- name: Install dependencies
|
||||
if: ${{ env.hasReportData }}
|
||||
working-directory: ./bigbluebutton-tests/playwright
|
||||
run: npm ci
|
||||
- name: Merge artifacts
|
||||
uses: actions/upload-artifact/merge@v4
|
||||
with:
|
||||
name: all-blob-reports
|
||||
pattern: blob-report-*
|
||||
delete-merged: true
|
||||
- name: Download all blob reports from GitHub Actions Artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
if: ${{ env.hasReportData }}
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: all-blob-reports
|
||||
path: bigbluebutton-tests/playwright/all-blob-reports
|
||||
- name: Merge into HTML Report
|
||||
if: ${{ env.hasReportData }}
|
||||
working-directory: ./bigbluebutton-tests/playwright
|
||||
run: npx playwright merge-reports --reporter html ./all-blob-reports
|
||||
- name: Upload HTML tests report
|
||||
uses: actions/upload-artifact@v3
|
||||
if: ${{ env.hasReportData }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: tests-report
|
||||
overwrite: true
|
||||
path: |
|
||||
bigbluebutton-tests/playwright/playwright-report
|
||||
bigbluebutton-tests/playwright/test-results
|
||||
@ -385,7 +405,7 @@ jobs:
|
||||
echo ${{ github.run_id }} > ./pr-comment-data/workflow_id
|
||||
- name: Upload PR data for auto-comment
|
||||
if: github.event_name == 'pull_request'
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: pr-comment-data
|
||||
path: pr-comment-data
|
||||
|
2
.github/workflows/check-merge-conflict.yml
vendored
2
.github/workflows/check-merge-conflict.yml
vendored
@ -16,7 +16,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check for dirty pull requests
|
||||
uses: eps1lon/actions-label-merge-conflict@releases/2.x
|
||||
uses: eps1lon/actions-label-merge-conflict@v3
|
||||
with:
|
||||
dirtyLabel: "status: conflict"
|
||||
repoToken: "${{ secrets.GITHUB_TOKEN }}"
|
||||
|
4
.github/workflows/deploy-docs.yml
vendored
4
.github/workflows/deploy-docs.yml
vendored
@ -22,8 +22,8 @@ jobs:
|
||||
working-directory: ./docs
|
||||
steps:
|
||||
# Setup
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
cache: yarn
|
||||
|
2
.github/workflows/ts-code-compilation.yml
vendored
2
.github/workflows/ts-code-compilation.yml
vendored
@ -23,7 +23,7 @@ jobs:
|
||||
ts-code-compilation:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
- name: Merge branches
|
||||
|
2
.github/workflows/ts-code-validation.yml
vendored
2
.github/workflows/ts-code-validation.yml
vendored
@ -23,7 +23,7 @@ jobs:
|
||||
ts-code-validation:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
- name: Merge branches
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -24,3 +24,4 @@ artifacts/*
|
||||
bbb-presentation-video.zip
|
||||
bbb-presentation-video
|
||||
bbb-graphql-actions-adapter-server/
|
||||
bigbluebutton-html5/public/locales/index.json
|
||||
|
@ -5,7 +5,7 @@ import org.slf4j.LoggerFactory
|
||||
|
||||
import java.io.{ ByteArrayInputStream, File }
|
||||
import scala.io.BufferedSource
|
||||
import scala.util.{ Failure, Success, Try }
|
||||
import scala.util.{ Failure, Success }
|
||||
|
||||
object ClientSettings extends SystemConfiguration {
|
||||
var clientSettingsFromFile: Map[String, Object] = Map("" -> "")
|
||||
@ -82,6 +82,24 @@ object ClientSettings extends SystemConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
def getConfigPropertyValueByPathAsListOfStringOrElse(map: Map[String, Any], path: String, alternativeValue: List[String]): List[String] = {
|
||||
getConfigPropertyValueByPath(map, path) match {
|
||||
case Some(configValue: List[String]) => configValue
|
||||
case _ =>
|
||||
logger.debug(s"Config `$path` with type List[String] not found in clientSettings.")
|
||||
alternativeValue
|
||||
}
|
||||
}
|
||||
|
||||
def getConfigPropertyValueByPathAsListOfIntOrElse(map: Map[String, Any], path: String, alternativeValue: List[Int]): List[Int] = {
|
||||
getConfigPropertyValueByPath(map, path) match {
|
||||
case Some(configValue: List[Int]) => configValue
|
||||
case _ =>
|
||||
logger.debug(s"Config `$path` with type List[Int] not found in clientSettings.")
|
||||
alternativeValue
|
||||
}
|
||||
}
|
||||
|
||||
def getConfigPropertyValueByPath(map: Map[String, Any], path: String): Option[Any] = {
|
||||
val keys = path.split("\\.")
|
||||
|
||||
|
@ -14,6 +14,7 @@ import org.bigbluebutton.SystemConfiguration
|
||||
import java.util.concurrent.TimeUnit
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.db.{ DatabaseConnection, MeetingDAO }
|
||||
import org.bigbluebutton.core.domain.MeetingEndReason
|
||||
import org.bigbluebutton.core.running.RunningMeeting
|
||||
import org.bigbluebutton.core.util.ColorPicker
|
||||
import org.bigbluebutton.core2.RunningMeetings
|
||||
@ -57,6 +58,9 @@ class BigBlueButtonActor(
|
||||
override def preStart() {
|
||||
bbbMsgBus.subscribe(self, meetingManagerChannel)
|
||||
DatabaseConnection.initialize()
|
||||
|
||||
//Terminate all previous meetings, as they will not function following the akka-apps restart
|
||||
MeetingDAO.setAllMeetingsEnded(MeetingEndReason.ENDED_DUE_TO_SERVICE_INTERRUPTION, "system")
|
||||
}
|
||||
|
||||
override def postStop() {
|
||||
@ -150,7 +154,7 @@ class BigBlueButtonActor(
|
||||
}
|
||||
|
||||
private def handleGetAllMeetingsReqMsg(msg: GetAllMeetingsReqMsg): Unit = {
|
||||
RunningMeetings.meetings(meetings).filter(_.props.systemProps.html5InstanceId == msg.body.html5InstanceId).foreach(m => {
|
||||
RunningMeetings.meetings(meetings).foreach(m => {
|
||||
m.actorRef ! msg
|
||||
})
|
||||
}
|
||||
|
@ -120,13 +120,6 @@ case class CapturePresentationReqInternalMsg(userId: String, parentMeetingId: St
|
||||
*/
|
||||
case class SetPresenterInDefaultPodInternalMsg(presenterId: String) extends InMessage
|
||||
|
||||
/**
|
||||
* Sent by breakout room to parent meeting to obtain padId
|
||||
* @param breakoutId
|
||||
* @param filename
|
||||
*/
|
||||
case class CaptureSharedNotesReqInternalMsg(breakoutId: String, filename: String) extends InMessage
|
||||
|
||||
/**
|
||||
* Sent by GraphqlActionsActor to inform MeetingActor that user disconnected
|
||||
* @param userId
|
||||
@ -138,10 +131,3 @@ case class UserClosedAllGraphqlConnectionsInternalMsg(userId: String) extends In
|
||||
* @param userId
|
||||
*/
|
||||
case class UserEstablishedGraphqlConnectionInternalMsg(userId: String) extends InMessage
|
||||
|
||||
// DeskShare
|
||||
case class DeskShareStartedRequest(conferenceName: String, callerId: String, callerIdName: String) extends InMessage
|
||||
case class DeskShareStoppedRequest(conferenceName: String, callerId: String, callerIdName: String) extends InMessage
|
||||
case class DeskShareRTMPBroadcastStartedRequest(conferenceName: String, streamname: String, videoWidth: Int, videoHeight: Int, timestamp: String) extends InMessage
|
||||
case class DeskShareRTMPBroadcastStoppedRequest(conferenceName: String, streamname: String, videoWidth: Int, videoHeight: Int, timestamp: String) extends InMessage
|
||||
case class DeskShareGetDeskShareInfoRequest(conferenceName: String, requesterID: String, replyTo: String) extends InMessage
|
||||
|
@ -46,7 +46,7 @@ class WhiteboardModel extends SystemConfiguration {
|
||||
k -> newValue
|
||||
}).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] = {
|
||||
val wb = getWhiteboard(wbId)
|
||||
|
||||
var annotationsAdded = Array[AnnotationVO]()
|
||||
@ -70,7 +70,6 @@ class WhiteboardModel extends SystemConfiguration {
|
||||
val newAnnotation = oldAnnotation.get.copy(annotationInfo = finalAnnotationInfo)
|
||||
newAnnotationsMap += (annotation.id -> newAnnotation)
|
||||
annotationsAdded :+= newAnnotation
|
||||
PresAnnotationDAO.insertOrUpdate(newAnnotation, newAnnotation)
|
||||
println(s"Updated annotation on page [${wb.id}]. After numAnnotations=[${newAnnotationsMap.size}].")
|
||||
} else {
|
||||
println(s"User $userId doesn't have permission to edit annotation ${annotation.id}, ignoring...")
|
||||
@ -78,13 +77,14 @@ class WhiteboardModel extends SystemConfiguration {
|
||||
} else if (annotation.annotationInfo.contains("type")) {
|
||||
newAnnotationsMap += (annotation.id -> annotation)
|
||||
annotationsAdded :+= annotation
|
||||
PresAnnotationDAO.insertOrUpdate(annotation, annotation)
|
||||
println(s"Adding annotation to page [${wb.id}]. After numAnnotations=[${newAnnotationsMap.size}].")
|
||||
} else {
|
||||
println(s"New annotation [${annotation.id}] with no type, ignoring...")
|
||||
}
|
||||
}
|
||||
|
||||
PresAnnotationDAO.insertOrUpdateMap(meetingId, annotationsAdded)
|
||||
|
||||
val newWb = wb.copy(annotationsMap = newAnnotationsMap)
|
||||
saveWhiteboard(newWb)
|
||||
annotationsAdded
|
||||
@ -106,7 +106,7 @@ class WhiteboardModel extends SystemConfiguration {
|
||||
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") // Remove unwanted properties for 'point' type
|
||||
case Some("point") => props - ("boundShapeId", "normalizedAnchor", "isExact", "isPrecise") // Remove unwanted properties for 'point' type
|
||||
case _ => props
|
||||
}
|
||||
}
|
||||
@ -116,7 +116,7 @@ class WhiteboardModel extends SystemConfiguration {
|
||||
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] = {
|
||||
val wb = getWhiteboard(wbId)
|
||||
|
||||
var annotationsIdsRemoved = Array[String]()
|
||||
@ -143,15 +143,15 @@ class WhiteboardModel extends SystemConfiguration {
|
||||
val updatedWb = wb.copy(annotationsMap = newAnnotationsMap)
|
||||
saveWhiteboard(updatedWb)
|
||||
|
||||
annotationsIdsRemoved.map(PresAnnotationDAO.delete(wbId, userId, _))
|
||||
PresAnnotationDAO.delete(meetingId, userId, annotationsIdsRemoved)
|
||||
|
||||
annotationsIdsRemoved
|
||||
}
|
||||
|
||||
def modifyWhiteboardAccess(wbId: String, multiUser: Array[String]) {
|
||||
def modifyWhiteboardAccess(meetingId: String, wbId: String, multiUser: Array[String]) {
|
||||
val wb = getWhiteboard(wbId)
|
||||
val newWb = wb.copy(multiUser = multiUser, oldMultiUser = wb.multiUser, changedModeOn = System.currentTimeMillis())
|
||||
PresPageWritersDAO.updateMultiuser(newWb)
|
||||
PresPageWritersDAO.updateMultiuser(meetingId, newWb)
|
||||
saveWhiteboard(newWb)
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ import org.apache.pekko.actor.ActorContext
|
||||
|
||||
class AudioCaptionsApp2x(implicit val context: ActorContext)
|
||||
extends UpdateTranscriptPubMsgHdlr
|
||||
with TranscriptionProviderErrorMsgHdlr
|
||||
with AudioFloorChangedVoiceConfEvtMsgHdlr {
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,31 @@
|
||||
package org.bigbluebutton.core.apps.audiocaptions
|
||||
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.bus.MessageBus
|
||||
import org.bigbluebutton.core.db.UserTranscriptionErrorDAO
|
||||
import org.bigbluebutton.core.models.AudioCaptions
|
||||
import org.bigbluebutton.core.running.LiveMeeting
|
||||
|
||||
trait TranscriptionProviderErrorMsgHdlr {
|
||||
this: AudioCaptionsApp2x =>
|
||||
|
||||
def handleTranscriptionProviderErrorMsg(msg: TranscriptionProviderErrorMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||
val meetingId = liveMeeting.props.meetingProp.intId
|
||||
|
||||
def broadcastEvent(userId: String, errorCode: String, errorMessage: String): Unit = {
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, meetingId, "nodeJSapp")
|
||||
val envelope = BbbCoreEnvelope(TranscriptionProviderErrorEvtMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(TranscriptionProviderErrorEvtMsg.NAME, meetingId, userId)
|
||||
val body = TranscriptionProviderErrorEvtMsgBody(errorCode, errorMessage)
|
||||
val event = TranscriptionProviderErrorEvtMsg(header, body)
|
||||
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
|
||||
|
||||
bus.outGW.send(msgEvent)
|
||||
}
|
||||
|
||||
broadcastEvent(msg.header.userId, msg.body.errorCode, msg.body.errorMessage)
|
||||
|
||||
UserTranscriptionErrorDAO.insert(msg.header.userId, msg.header.meetingId, msg.body.errorCode, msg.body.errorMessage)
|
||||
|
||||
}
|
||||
}
|
@ -1,12 +1,13 @@
|
||||
package org.bigbluebutton.core.apps.audiocaptions
|
||||
|
||||
import org.bigbluebutton.ClientSettings.getConfigPropertyValueByPathAsStringOrElse
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.bus.MessageBus
|
||||
import org.bigbluebutton.core.db.CaptionDAO
|
||||
import org.bigbluebutton.core.models.{AudioCaptions, Users2x}
|
||||
import org.bigbluebutton.core.models.{AudioCaptions, UserState, Users2x}
|
||||
import org.bigbluebutton.core.running.LiveMeeting
|
||||
|
||||
import java.sql.Timestamp
|
||||
import java.time.LocalDateTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
|
||||
trait UpdateTranscriptPubMsgHdlr {
|
||||
this: AudioCaptionsApp2x =>
|
||||
@ -25,6 +26,17 @@ trait UpdateTranscriptPubMsgHdlr {
|
||||
bus.outGW.send(msgEvent)
|
||||
}
|
||||
|
||||
def sendPadUpdatePubMsg(userId: String, defaultPad: String, text: String, transcript: Boolean): Unit = {
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, meetingId, "nodeJSapp")
|
||||
val envelope = BbbCoreEnvelope(PadUpdatePubMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(PadUpdatePubMsg.NAME, meetingId, userId)
|
||||
val body = PadUpdatePubMsgBody(defaultPad, text, transcript)
|
||||
val event = PadUpdatePubMsg(header, body)
|
||||
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
|
||||
|
||||
bus.outGW.send(msgEvent)
|
||||
}
|
||||
|
||||
// Adapt to the current captions' recording process
|
||||
def editTranscript(
|
||||
userId: String,
|
||||
@ -80,6 +92,28 @@ trait UpdateTranscriptPubMsgHdlr {
|
||||
msg.body.locale,
|
||||
msg.body.result,
|
||||
)
|
||||
|
||||
if(msg.body.result) {
|
||||
val userName = Users2x.findWithIntId(liveMeeting.users2x, msg.header.userId).get match {
|
||||
case u: UserState => u.name
|
||||
case _ => "???"
|
||||
}
|
||||
|
||||
val now = LocalDateTime.now()
|
||||
val formatter = DateTimeFormatter.ofPattern("HH:mm:ss")
|
||||
val formattedTime = now.format(formatter)
|
||||
|
||||
val userSpoke = s"\n $userName ($formattedTime): $transcript"
|
||||
|
||||
val defaultPad = getConfigPropertyValueByPathAsStringOrElse(
|
||||
liveMeeting.clientSettings,
|
||||
"public.captions.defaultPad",
|
||||
alternativeValue = ""
|
||||
)
|
||||
|
||||
sendPadUpdatePubMsg(msg.header.userId, defaultPad, userSpoke, transcript = true)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package org.bigbluebutton.core.apps.breakout
|
||||
|
||||
import org.bigbluebutton.core.api.BreakoutRoomEndedInternalMsg
|
||||
import org.bigbluebutton.core.db.BreakoutRoomDAO
|
||||
import org.bigbluebutton.core.db.{ BreakoutRoomDAO, NotificationDAO }
|
||||
import org.bigbluebutton.core.domain.MeetingState2x
|
||||
import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter }
|
||||
import org.bigbluebutton.core2.message.senders.MsgBuilder
|
||||
@ -37,6 +37,7 @@ trait BreakoutRoomEndedInternalMsgHdlr {
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
|
||||
BreakoutRoomDAO.updateRoomsEnded(liveMeeting.props.meetingProp.intId)
|
||||
state.update(None)
|
||||
|
@ -53,8 +53,8 @@ trait BreakoutRoomUsersUpdateMsgHdlr {
|
||||
breakoutRoomUser <- updatedRoom.users
|
||||
u <- RegisteredUsers.findWithBreakoutRoomId(breakoutRoomUser.id, liveMeeting.registeredUsers)
|
||||
} yield u.id
|
||||
UserBreakoutRoomDAO.updateLastBreakoutRoom(usersInRoom, updatedRoom)
|
||||
BreakoutRoomUserDAO.updateUserJoined(usersInRoom, updatedRoom)
|
||||
UserBreakoutRoomDAO.updateLastBreakoutRoom(props.meetingProp.intId, usersInRoom, updatedRoom)
|
||||
BreakoutRoomUserDAO.updateUserJoined(props.meetingProp.intId, usersInRoom, updatedRoom)
|
||||
model.update(updatedRoom)
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ import org.bigbluebutton.core.api.EjectUserFromBreakoutInternalMsg
|
||||
import org.bigbluebutton.core.apps.breakout.BreakoutHdlrHelpers.getRedirectUrls
|
||||
import org.bigbluebutton.core.apps.{PermissionCheck, RightsManagementTrait}
|
||||
import org.bigbluebutton.core.bus.BigBlueButtonEvent
|
||||
import org.bigbluebutton.core.db.BreakoutRoomUserDAO
|
||||
import org.bigbluebutton.core.db.{BreakoutRoomUserDAO, NotificationDAO}
|
||||
import org.bigbluebutton.core.domain.MeetingState2x
|
||||
import org.bigbluebutton.core.models.EjectReasonCode
|
||||
import org.bigbluebutton.core.running.{MeetingActor, OutMsgRouter}
|
||||
@ -57,7 +57,7 @@ trait ChangeUserBreakoutReqMsgHdlr extends RightsManagementTrait {
|
||||
)
|
||||
|
||||
//Update database
|
||||
BreakoutRoomUserDAO.updateRoomChanged(msg.body.userId, msg.body.fromBreakoutId, msg.body.toBreakoutId, redirectToHtml5JoinURL)
|
||||
BreakoutRoomUserDAO.updateRoomChanged(meetingId, msg.body.userId, msg.body.fromBreakoutId, msg.body.toBreakoutId, redirectToHtml5JoinURL)
|
||||
|
||||
|
||||
//Send notification to moved User
|
||||
@ -75,6 +75,7 @@ trait ChangeUserBreakoutReqMsgHdlr extends RightsManagementTrait {
|
||||
Vector(roomTo.shortName)
|
||||
)
|
||||
outGW.send(notifyUserEvent)
|
||||
NotificationDAO.insert(notifyUserEvent)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,7 @@ trait EjectUserFromBreakoutInternalMsgHdlr {
|
||||
)
|
||||
|
||||
//TODO inform reason
|
||||
UserDAO.softDelete(registeredUser.id)
|
||||
UserDAO.softDelete(registeredUser.meetingId, registeredUser.id)
|
||||
|
||||
// send a system message to force disconnection
|
||||
Sender.sendDisconnectClientSysMsg(msg.breakoutId, registeredUser.id, msg.ejectedBy, msg.reasonCode, outGW)
|
||||
|
@ -6,9 +6,8 @@ import org.bigbluebutton.core.bus.BigBlueButtonEvent
|
||||
import org.bigbluebutton.core.domain.{ MeetingEndReason, MeetingState2x }
|
||||
import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter }
|
||||
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
|
||||
import org.bigbluebutton.core.db.UserBreakoutRoomDAO
|
||||
import org.bigbluebutton.core.db.{ BreakoutRoomDAO, NotificationDAO, UserBreakoutRoomDAO }
|
||||
import org.bigbluebutton.core2.message.senders.MsgBuilder
|
||||
import org.bigbluebutton.core.db.BreakoutRoomDAO
|
||||
|
||||
trait EndAllBreakoutRoomsMsgHdlr extends RightsManagementTrait {
|
||||
this: MeetingActor =>
|
||||
@ -22,24 +21,19 @@ trait EndAllBreakoutRoomsMsgHdlr extends RightsManagementTrait {
|
||||
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, outGW, liveMeeting)
|
||||
state
|
||||
} else {
|
||||
for {
|
||||
model <- state.breakout
|
||||
} yield {
|
||||
model.rooms.values.foreach { room =>
|
||||
eventBus.publish(BigBlueButtonEvent(room.id, EndBreakoutRoomInternalMsg(meetingId, room.id, MeetingEndReason.BREAKOUT_ENDED_BY_MOD)))
|
||||
UserBreakoutRoomDAO.updateLastBreakoutRoom(Vector(), room)
|
||||
}
|
||||
endAllBreakoutRooms(eventBus, liveMeeting, state, MeetingEndReason.BREAKOUT_ENDED_BY_MOD)
|
||||
|
||||
val notifyEvent = MsgBuilder.buildNotifyAllInMeetingEvtMsg(
|
||||
meetingId,
|
||||
"info",
|
||||
"rooms",
|
||||
"app.toast.breakoutRoomEnded",
|
||||
"Message when the breakout room is ended",
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
|
||||
val notifyEvent = MsgBuilder.buildNotifyAllInMeetingEvtMsg(
|
||||
meetingId,
|
||||
"info",
|
||||
"rooms",
|
||||
"app.toast.breakoutRoomEnded",
|
||||
"Message when the breakout room is ended",
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
}
|
||||
BreakoutRoomDAO.updateRoomsEnded(meetingId)
|
||||
state.update(None)
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
package org.bigbluebutton.core.apps.breakout
|
||||
|
||||
import org.bigbluebutton.core.api.{ CaptureSharedNotesReqInternalMsg, CapturePresentationReqInternalMsg, EndBreakoutRoomInternalMsg }
|
||||
import org.bigbluebutton.common2.msgs.{ BbbClientMsgHeader, BbbCommonEnvCoreMsg, BbbCoreEnvelope, BbbCoreHeaderWithMeetingId, ExportJob, MessageTypes, PresentationConversionUpdateEvtMsg, PresentationConversionUpdateEvtMsgBody, PresentationConversionUpdateSysPubMsg, PresentationUploadTokenSysPubMsg, PresentationUploadTokenSysPubMsgBody, Routing, StoreExportJobInRedisSysMsg, StoreExportJobInRedisSysMsgBody }
|
||||
import org.bigbluebutton.core.api.{ CapturePresentationReqInternalMsg, EndBreakoutRoomInternalMsg }
|
||||
import org.bigbluebutton.core.apps.presentationpod.PresentationPodsApp
|
||||
import org.bigbluebutton.core.bus.{ BigBlueButtonEvent, InternalEventBus }
|
||||
import org.bigbluebutton.core.models.Pads
|
||||
import org.bigbluebutton.core.running.{ BaseMeetingActor, HandlerHelpers, LiveMeeting, OutMsgRouter }
|
||||
|
||||
trait EndBreakoutRoomInternalMsgHdlr extends HandlerHelpers {
|
||||
@ -19,12 +22,68 @@ trait EndBreakoutRoomInternalMsgHdlr extends HandlerHelpers {
|
||||
}
|
||||
|
||||
if (liveMeeting.props.breakoutProps.captureNotes) {
|
||||
val filename = liveMeeting.props.breakoutProps.captureNotesFilename
|
||||
val captureNotesEvent = BigBlueButtonEvent(msg.parentId, CaptureSharedNotesReqInternalMsg(msg.breakoutId, filename))
|
||||
eventBus.publish(captureNotesEvent)
|
||||
for {
|
||||
group <- Pads.getGroup(liveMeeting.pads, "notes")
|
||||
} yield {
|
||||
val filename = liveMeeting.props.breakoutProps.captureNotesFilename
|
||||
val userId: String = "system"
|
||||
val jobId: String = s"${msg.breakoutId}-notes" // Used as the temporaryPresentationId upon upload
|
||||
val presentationId = PresentationPodsApp.generatePresentationId(filename)
|
||||
|
||||
if (group.rev > 0) {
|
||||
//Request upload of the sharedNotes of breakoutRoom
|
||||
val presentationUploadToken: String = PresentationPodsApp.generateToken("DEFAULT_PRESENTATION_POD", userId)
|
||||
outGW.send(buildPresentationUploadTokenSysPubMsg(msg.parentId, userId, presentationUploadToken, filename, presentationId))
|
||||
|
||||
val exportJob = ExportJob(jobId, "PadCaptureJob", filename, filename, group.padId, "", allPages = true, List(), msg.parentId, presentationUploadToken)
|
||||
val job = buildStoreExportJobInRedisSysMsg(exportJob, liveMeeting)
|
||||
outGW.send(job)
|
||||
} else {
|
||||
// Notify that no content is available
|
||||
val event = buildPresentationConversionUpdateEvtMsg(msg.parentId, presentationId, filename, jobId)
|
||||
outGW.send(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.info("Breakout room {} ended by parent meeting {}.", msg.breakoutId, msg.parentId)
|
||||
sendEndMeetingDueToExpiry(msg.reason, eventBus, outGW, liveMeeting, "system")
|
||||
}
|
||||
|
||||
def buildStoreExportJobInRedisSysMsg(exportJob: ExportJob, liveMeeting: LiveMeeting): BbbCommonEnvCoreMsg = {
|
||||
val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka")
|
||||
val envelope = BbbCoreEnvelope(StoreExportJobInRedisSysMsg.NAME, routing)
|
||||
val body = StoreExportJobInRedisSysMsgBody(exportJob)
|
||||
val header = BbbCoreHeaderWithMeetingId(StoreExportJobInRedisSysMsg.NAME, liveMeeting.props.meetingProp.intId)
|
||||
val event = StoreExportJobInRedisSysMsg(header, body)
|
||||
|
||||
BbbCommonEnvCoreMsg(envelope, event)
|
||||
}
|
||||
|
||||
def buildPresentationUploadTokenSysPubMsg(parentMeetingId: String, userId: String, presentationUploadToken: String, filename: String, presId: String): BbbCommonEnvCoreMsg = {
|
||||
val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka")
|
||||
val envelope = BbbCoreEnvelope(PresentationUploadTokenSysPubMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(PresentationUploadTokenSysPubMsg.NAME, parentMeetingId, userId)
|
||||
val body = PresentationUploadTokenSysPubMsgBody("DEFAULT_PRESENTATION_POD", presentationUploadToken, filename, parentMeetingId, presId)
|
||||
val event = PresentationUploadTokenSysPubMsg(header, body)
|
||||
BbbCommonEnvCoreMsg(envelope, event)
|
||||
}
|
||||
|
||||
def buildPresentationConversionUpdateEvtMsg(meetingId: String, presentationId: String, presName: String, temporaryPresentationId: String): BbbCommonEnvCoreMsg = {
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, "system")
|
||||
val envelope = BbbCoreEnvelope(PresentationConversionUpdateEvtMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(PresentationConversionUpdateEvtMsg.NAME, meetingId, "system")
|
||||
|
||||
val body = PresentationConversionUpdateEvtMsgBody(
|
||||
"DEFAULT_PRESENTATION_POD",
|
||||
"204",
|
||||
"not-used",
|
||||
presentationId,
|
||||
presName,
|
||||
temporaryPresentationId
|
||||
)
|
||||
val event = PresentationConversionUpdateEvtMsg(header, body)
|
||||
BbbCommonEnvCoreMsg(envelope, event)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,13 +1,14 @@
|
||||
package org.bigbluebutton.core.apps.breakout
|
||||
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.api.{ SendMessageToBreakoutRoomInternalMsg }
|
||||
import org.bigbluebutton.core.api.SendMessageToBreakoutRoomInternalMsg
|
||||
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
|
||||
import org.bigbluebutton.core.bus.BigBlueButtonEvent
|
||||
import org.bigbluebutton.core.db.NotificationDAO
|
||||
import org.bigbluebutton.core.domain.MeetingState2x
|
||||
import org.bigbluebutton.core.models.{ RegisteredUsers }
|
||||
import org.bigbluebutton.core.models.RegisteredUsers
|
||||
import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter }
|
||||
import org.bigbluebutton.core2.message.senders.{ MsgBuilder }
|
||||
import org.bigbluebutton.core2.message.senders.MsgBuilder
|
||||
|
||||
trait SendMessageToAllBreakoutRoomsMsgHdlr extends RightsManagementTrait {
|
||||
this: MeetingActor =>
|
||||
@ -32,7 +33,7 @@ trait SendMessageToAllBreakoutRoomsMsgHdlr extends RightsManagementTrait {
|
||||
val event = buildSendMessageToAllBreakoutRoomsEvtMsg(msg.header.userId, msg.body.msg, breakoutModel.rooms.size)
|
||||
outGW.send(event)
|
||||
|
||||
val notifyModeratorEvent = MsgBuilder.buildNotifyUserInMeetingEvtMsg(
|
||||
val notifyUserEvent = MsgBuilder.buildNotifyUserInMeetingEvtMsg(
|
||||
msg.header.userId,
|
||||
liveMeeting.props.meetingProp.intId,
|
||||
"info",
|
||||
@ -41,7 +42,8 @@ trait SendMessageToAllBreakoutRoomsMsgHdlr extends RightsManagementTrait {
|
||||
"Message for chat sent successfully",
|
||||
Vector(s"${breakoutModel.rooms.size}")
|
||||
)
|
||||
outGW.send(notifyModeratorEvent)
|
||||
outGW.send(notifyUserEvent)
|
||||
NotificationDAO.insert(notifyUserEvent)
|
||||
|
||||
log.debug("Sending message '{}' to all breakout rooms in meeting {}", msg.body.msg, props.meetingProp.intId)
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package org.bigbluebutton.core.apps.breakout
|
||||
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.apps.{ BreakoutModel, PermissionCheck, RightsManagementTrait }
|
||||
import org.bigbluebutton.core.db.UserDAO
|
||||
import org.bigbluebutton.core.domain.MeetingState2x
|
||||
import org.bigbluebutton.core.models.VoiceUsers
|
||||
import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter }
|
||||
@ -17,13 +18,13 @@ trait TransferUserToMeetingRequestHdlr extends RightsManagementTrait {
|
||||
val reason = "No permission to transfer user to voice breakout."
|
||||
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, outGW, liveMeeting)
|
||||
} else {
|
||||
processRequest(msg)
|
||||
processTransferUserToMeetingRequest(msg)
|
||||
}
|
||||
|
||||
state
|
||||
}
|
||||
|
||||
def processRequest(msg: TransferUserToMeetingRequestMsg) {
|
||||
def processTransferUserToMeetingRequest(msg: TransferUserToMeetingRequestMsg) {
|
||||
if (msg.body.fromMeetingId == liveMeeting.props.meetingProp.intId) {
|
||||
// want to transfer from parent meeting to breakout
|
||||
for {
|
||||
@ -32,6 +33,7 @@ trait TransferUserToMeetingRequestHdlr extends RightsManagementTrait {
|
||||
from <- getVoiceConf(msg.body.fromMeetingId, model)
|
||||
voiceUser <- VoiceUsers.findWithIntId(liveMeeting.voiceUsers, msg.body.userId)
|
||||
} yield {
|
||||
UserDAO.transferUserToBreakoutRoomAsAudioOnly(msg.body.userId, msg.body.fromMeetingId, msg.body.toMeetingId)
|
||||
val event = buildTransferUserToVoiceConfSysMsg(from, to, voiceUser.voiceUserId)
|
||||
outGW.send(event)
|
||||
}
|
||||
@ -53,6 +55,7 @@ trait TransferUserToMeetingRequestHdlr extends RightsManagementTrait {
|
||||
room <- model.find(msg.body.fromMeetingId)
|
||||
voiceUser <- room.voiceUsers.find(p => p.id == msg.body.userId)
|
||||
} yield {
|
||||
UserDAO.transferUserToBreakoutRoomAsAudioOnly(msg.body.userId, msg.body.fromMeetingId, msg.body.toMeetingId)
|
||||
val event = buildTransferUserToVoiceConfSysMsg(from, to, voiceUser.voiceUserId)
|
||||
outGW.send(event)
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.api.{ SendTimeRemainingAuditInternalMsg, UpdateBreakoutRoomTimeInternalMsg }
|
||||
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
|
||||
import org.bigbluebutton.core.bus.BigBlueButtonEvent
|
||||
import org.bigbluebutton.core.db.{ BreakoutRoomDAO, MeetingDAO }
|
||||
import org.bigbluebutton.core.db.{ BreakoutRoomDAO, MeetingDAO, NotificationDAO }
|
||||
import org.bigbluebutton.core.domain.MeetingState2x
|
||||
import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter }
|
||||
import org.bigbluebutton.core2.message.senders.{ MsgBuilder, Sender }
|
||||
@ -63,9 +63,10 @@ trait UpdateBreakoutRoomsTimeMsgHdlr extends RightsManagementTrait {
|
||||
Vector(s"${msg.body.timeInMinutes}")
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
}
|
||||
|
||||
val notifyModeratorEvent = MsgBuilder.buildNotifyUserInMeetingEvtMsg(
|
||||
val notifyUserEvent = MsgBuilder.buildNotifyUserInMeetingEvtMsg(
|
||||
msg.header.userId,
|
||||
liveMeeting.props.meetingProp.intId,
|
||||
"info",
|
||||
@ -74,7 +75,8 @@ trait UpdateBreakoutRoomsTimeMsgHdlr extends RightsManagementTrait {
|
||||
"Sent to the moderator that requested breakout duration change",
|
||||
Vector(s"${msg.body.timeInMinutes}")
|
||||
)
|
||||
outGW.send(notifyModeratorEvent)
|
||||
outGW.send(notifyUserEvent)
|
||||
NotificationDAO.insert(notifyUserEvent)
|
||||
|
||||
log.debug("Updating {} minutes for breakout rooms time in meeting {}", msg.body.timeInMinutes, props.meetingProp.intId)
|
||||
BreakoutRoomDAO.updateRoomsDuration(props.meetingProp.intId, newDurationInSeconds)
|
||||
|
@ -4,8 +4,9 @@ import org.apache.pekko.actor.ActorContext
|
||||
import org.apache.pekko.event.Logging
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.bus.MessageBus
|
||||
import org.bigbluebutton.core.running.{ LiveMeeting }
|
||||
import org.bigbluebutton.core.running.LiveMeeting
|
||||
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
|
||||
import org.bigbluebutton.core.db.{ CaptionLocaleDAO, CaptionTypes }
|
||||
|
||||
class CaptionApp2x(implicit val context: ActorContext) extends RightsManagementTrait {
|
||||
val log = Logging(context.system, getClass)
|
||||
@ -84,6 +85,7 @@ class CaptionApp2x(implicit val context: ActorContext) extends RightsManagementT
|
||||
val event = UpdateCaptionOwnerEvtMsg(header, body)
|
||||
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
|
||||
bus.outGW.send(msgEvent)
|
||||
CaptionLocaleDAO.insertOrUpdateCaptionLocale(liveMeeting.props.meetingProp.intId, locale, CaptionTypes.TYPED, newOwnerId)
|
||||
}
|
||||
|
||||
if (permissionFailed(PermissionCheck.MOD_LEVEL, PermissionCheck.VIEWER_LEVEL, liveMeeting.users2x, msg.header.userId)) {
|
||||
|
@ -11,7 +11,7 @@ trait SyncGetGroupChatsInfoMsgHdlr {
|
||||
def handleSyncGetGroupChatsInfo(state: MeetingState2x, liveMeeting: LiveMeeting, bus: MessageBus): MeetingState2x = {
|
||||
|
||||
def buildSyncGetGroupChatsRespMsg(allChats: Vector[GroupChatInfo]): BbbCommonEnvCoreMsg = {
|
||||
val routing = Routing.addMsgToHtml5InstanceIdRouting(liveMeeting.props.meetingProp.intId, liveMeeting.props.systemProps.html5InstanceId.toString)
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, liveMeeting.props.meetingProp.intId, "nodeJSapp")
|
||||
val envelope = BbbCoreEnvelope(SyncGetGroupChatsRespMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(SyncGetGroupChatsRespMsg.NAME, liveMeeting.props.meetingProp.intId, "nodeJSapp")
|
||||
val body = SyncGetGroupChatsRespMsgBody(allChats)
|
||||
@ -21,7 +21,7 @@ trait SyncGetGroupChatsInfoMsgHdlr {
|
||||
}
|
||||
|
||||
def buildSyncGetGroupChatMsgsRespMsg(msgs: Vector[GroupChatMsgToUser], chatId: String): BbbCommonEnvCoreMsg = {
|
||||
val routing = Routing.addMsgToHtml5InstanceIdRouting(liveMeeting.props.meetingProp.intId, liveMeeting.props.systemProps.html5InstanceId.toString)
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, liveMeeting.props.meetingProp.intId, "nodeJSapp")
|
||||
val envelope = BbbCoreEnvelope(SyncGetGroupChatMsgsRespMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(SyncGetGroupChatMsgsRespMsg.NAME, liveMeeting.props.meetingProp.intId, "nodeJSapp")
|
||||
val body = SyncGetGroupChatMsgsRespMsgBody(chatId, msgs)
|
||||
|
@ -5,8 +5,8 @@ import org.bigbluebutton.core.models.{ Layouts, LayoutsType }
|
||||
import org.bigbluebutton.core.running.OutMsgRouter
|
||||
import org.bigbluebutton.core2.MeetingStatus2x
|
||||
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
|
||||
import org.bigbluebutton.core.db.LayoutDAO
|
||||
import org.bigbluebutton.core2.message.senders.{ MsgBuilder }
|
||||
import org.bigbluebutton.core.db.{ LayoutDAO, NotificationDAO }
|
||||
import org.bigbluebutton.core2.message.senders.MsgBuilder
|
||||
|
||||
trait BroadcastLayoutMsgHdlr extends RightsManagementTrait {
|
||||
this: LayoutApp2x =>
|
||||
@ -73,6 +73,7 @@ trait BroadcastLayoutMsgHdlr extends RightsManagementTrait {
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ trait SyncGetMeetingInfoRespMsgHdlr {
|
||||
val outGW: OutMsgRouter
|
||||
|
||||
def handleSyncGetMeetingInfoRespMsg(props: DefaultProps): Unit = {
|
||||
val routing = Routing.addMsgToHtml5InstanceIdRouting(props.meetingProp.intId, props.systemProps.html5InstanceId.toString)
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, props.meetingProp.intId, "nodeJSapp")
|
||||
val envelope = BbbCoreEnvelope(SyncGetMeetingInfoRespMsg.NAME, routing)
|
||||
val header = BbbCoreBaseHeader(SyncGetMeetingInfoRespMsg.NAME)
|
||||
|
||||
|
@ -10,17 +10,6 @@ trait PadCreateGroupReqMsgHdlr {
|
||||
|
||||
def handle(msg: PadCreateGroupReqMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||
|
||||
def broadcastEvent(externalId: String, model: String): Unit = {
|
||||
val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka")
|
||||
val envelope = BbbCoreEnvelope(PadCreateGroupCmdMsg.NAME, routing)
|
||||
val header = BbbCoreHeaderWithMeetingId(PadCreateGroupCmdMsg.NAME, liveMeeting.props.meetingProp.intId)
|
||||
val body = PadCreateGroupCmdMsgBody(externalId, model)
|
||||
val event = PadCreateGroupCmdMsg(header, body)
|
||||
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
|
||||
|
||||
bus.outGW.send(msgEvent)
|
||||
}
|
||||
|
||||
val padEnabled = msg.body.model match {
|
||||
case "notes" => !liveMeeting.props.meetingProp.disabledFeatures.contains("sharedNotes")
|
||||
case "captions" => !liveMeeting.props.meetingProp.disabledFeatures.contains("captions")
|
||||
@ -29,7 +18,7 @@ trait PadCreateGroupReqMsgHdlr {
|
||||
|
||||
if (padEnabled && !Pads.hasGroup(liveMeeting.pads, msg.body.externalId)) {
|
||||
Pads.addGroup(liveMeeting.pads, msg.body.externalId, msg.body.model, msg.body.name, msg.header.userId)
|
||||
broadcastEvent(msg.body.externalId, msg.body.model)
|
||||
PadslHdlrHelpers.broadcastPadCreateGroupCmdMsg(bus.outGW, liveMeeting.props.meetingProp.intId, msg.body.externalId, msg.body.model)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ trait PadCreatedEvtMsgHdlr {
|
||||
|
||||
Pads.getGroupById(liveMeeting.pads, msg.body.groupId) match {
|
||||
case Some(group) => {
|
||||
Pads.setPadId(liveMeeting.pads, group.externalId, msg.body.padId)
|
||||
SharedNotesDAO.insert(liveMeeting.props.meetingProp.intId, group, msg.body.padId, msg.body.name)
|
||||
broadcastEvent(group.externalId, group.userId, msg.body.padId, msg.body.name)
|
||||
}
|
||||
|
@ -9,22 +9,12 @@ trait PadGroupCreatedEvtMsgHdlr {
|
||||
this: PadsApp2x =>
|
||||
|
||||
def handle(msg: PadGroupCreatedEvtMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||
|
||||
def broadcastEvent(externalId: String, model: String, name: String, userId: String): Unit = {
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, userId)
|
||||
val envelope = BbbCoreEnvelope(PadGroupCreatedRespMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(PadGroupCreatedRespMsg.NAME, liveMeeting.props.meetingProp.intId, userId)
|
||||
val body = PadGroupCreatedRespMsgBody(externalId, model, name)
|
||||
val event = PadGroupCreatedRespMsg(header, body)
|
||||
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
|
||||
|
||||
bus.outGW.send(msgEvent)
|
||||
}
|
||||
|
||||
Pads.getGroup(liveMeeting.pads, msg.body.externalId) match {
|
||||
case Some(group) => {
|
||||
Pads.setGroupId(liveMeeting.pads, msg.body.externalId, msg.body.groupId)
|
||||
broadcastEvent(msg.body.externalId, group.model, group.name, group.userId)
|
||||
|
||||
//Group was created, now request to create the pad
|
||||
PadslHdlrHelpers.broadcastPadCreateCmdMsg(bus.outGW, liveMeeting.props.meetingProp.intId, msg.body.groupId, msg.body.externalId)
|
||||
}
|
||||
case _ =>
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ trait PadSessionDeletedSysMsgHdlr {
|
||||
|
||||
Pads.getGroupById(liveMeeting.pads, msg.body.groupId) match {
|
||||
case Some(group) => {
|
||||
SharedNotesSessionDAO.delete(msg.body.userId, msg.body.sessionId)
|
||||
SharedNotesSessionDAO.delete(liveMeeting.props.meetingProp.intId, msg.body.userId, msg.body.sessionId)
|
||||
broadcastEvent(group.externalId, msg.body.userId, msg.body.sessionId)
|
||||
}
|
||||
case _ =>
|
||||
|
@ -21,7 +21,7 @@ trait PadUpdatePubMsgHdlr {
|
||||
bus.outGW.send(msgEvent)
|
||||
}
|
||||
|
||||
if (Pads.hasAccess(liveMeeting, msg.body.externalId, msg.header.userId)) {
|
||||
if (Pads.hasAccess(liveMeeting, msg.body.externalId, msg.header.userId) || msg.body.transcript == true) {
|
||||
Pads.getGroup(liveMeeting.pads, msg.body.externalId) match {
|
||||
case Some(group) => broadcastEvent(group.groupId, msg.body.externalId, msg.body.text)
|
||||
case _ =>
|
||||
|
@ -24,6 +24,7 @@ trait PadUpdatedSysMsgHdlr {
|
||||
|
||||
Pads.getGroupById(liveMeeting.pads, msg.body.groupId) match {
|
||||
case Some(group) => {
|
||||
Pads.setRev(liveMeeting.pads, group.externalId, msg.body.rev)
|
||||
SharedNotesRevDAO.insert(liveMeeting.props.meetingProp.intId, group.externalId, msg.body.rev, msg.body.userId, msg.body.changeset)
|
||||
broadcastEvent(group.externalId, msg.body.padId, msg.body.userId, msg.body.rev, msg.body.changeset)
|
||||
}
|
||||
|
@ -0,0 +1,30 @@
|
||||
package org.bigbluebutton.core.apps.pads
|
||||
|
||||
import org.bigbluebutton.common2.msgs.{ BbbCommonEnvCoreMsg, BbbCoreEnvelope, BbbCoreHeaderWithMeetingId, PadCreateCmdMsg, PadCreateCmdMsgBody, PadCreateGroupCmdMsg, PadCreateGroupCmdMsgBody }
|
||||
import org.bigbluebutton.core.running.OutMsgRouter
|
||||
|
||||
object PadslHdlrHelpers {
|
||||
|
||||
def broadcastPadCreateGroupCmdMsg(outGW: OutMsgRouter, meetingId: String, externalId: String, model: String): Unit = {
|
||||
val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka")
|
||||
val envelope = BbbCoreEnvelope(PadCreateGroupCmdMsg.NAME, routing)
|
||||
val header = BbbCoreHeaderWithMeetingId(PadCreateGroupCmdMsg.NAME, meetingId)
|
||||
val body = PadCreateGroupCmdMsgBody(externalId, model)
|
||||
val event = PadCreateGroupCmdMsg(header, body)
|
||||
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
|
||||
|
||||
outGW.send(msgEvent)
|
||||
}
|
||||
|
||||
def broadcastPadCreateCmdMsg(outGW: OutMsgRouter, meetingId: String, groupId: String, name: String): Unit = {
|
||||
val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka")
|
||||
val envelope = BbbCoreEnvelope(PadCreateCmdMsg.NAME, routing)
|
||||
val header = BbbCoreHeaderWithMeetingId(PadCreateCmdMsg.NAME, meetingId)
|
||||
val body = PadCreateCmdMsgBody(groupId, name)
|
||||
val event = PadCreateCmdMsg(header, body)
|
||||
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
|
||||
|
||||
outGW.send(msgEvent)
|
||||
}
|
||||
|
||||
}
|
@ -1,15 +1,15 @@
|
||||
package org.bigbluebutton.core.apps.plugin
|
||||
|
||||
import org.bigbluebutton.ClientSettings
|
||||
import org.bigbluebutton.common2.msgs.PluginDataChannelDeleteMessageMsg
|
||||
import org.bigbluebutton.core.db.PluginDataChannelMessageDAO
|
||||
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 PluginDataChannelDeleteMessageMsgHdlr extends HandlerHelpers {
|
||||
trait PluginDataChannelDeleteEntryMsgHdlr extends HandlerHelpers {
|
||||
|
||||
def handle(msg: PluginDataChannelDeleteMessageMsg, state: MeetingState2x, liveMeeting: LiveMeeting): Unit = {
|
||||
def handle(msg: PluginDataChannelDeleteEntryMsg, state: MeetingState2x, liveMeeting: LiveMeeting): Unit = {
|
||||
val pluginsDisabled: Boolean = liveMeeting.props.meetingProp.disabledFeatures.contains("plugins")
|
||||
val meetingId = liveMeeting.props.meetingProp.intId
|
||||
|
||||
@ -21,22 +21,23 @@ trait PluginDataChannelDeleteMessageMsgHdlr extends HandlerHelpers {
|
||||
|
||||
if (!pluginsConfig.contains(msg.body.pluginName)) {
|
||||
println(s"Plugin '${msg.body.pluginName}' not found.")
|
||||
} else if (!pluginsConfig(msg.body.pluginName).dataChannels.contains(msg.body.dataChannel)) {
|
||||
println(s"Data channel '${msg.body.dataChannel}' not found in plugin '${msg.body.pluginName}'.")
|
||||
} else if (!pluginsConfig(msg.body.pluginName).dataChannels.contains(msg.body.channelName)) {
|
||||
println(s"Data channel '${msg.body.channelName}' not found in plugin '${msg.body.pluginName}'.")
|
||||
} else {
|
||||
val hasPermission = for {
|
||||
deletePermission <- pluginsConfig(msg.body.pluginName).dataChannels(msg.body.dataChannel).deletePermission
|
||||
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 = PluginDataChannelMessageDAO.getMessageSender(
|
||||
val senderUserId = PluginDataChannelEntryDAO.getMessageSender(
|
||||
meetingId,
|
||||
msg.body.pluginName,
|
||||
msg.body.dataChannel,
|
||||
msg.body.messageId
|
||||
msg.body.channelName,
|
||||
msg.body.subChannelName,
|
||||
msg.body.entryId
|
||||
)
|
||||
senderUserId == msg.header.userId
|
||||
}
|
||||
@ -45,13 +46,14 @@ trait PluginDataChannelDeleteMessageMsgHdlr extends HandlerHelpers {
|
||||
}
|
||||
|
||||
if (!hasPermission.contains(true)) {
|
||||
println(s"No permission to delete in plugin: '${msg.body.pluginName}', data channel: '${msg.body.dataChannel}'.")
|
||||
println(s"No permission to delete in plugin: '${msg.body.pluginName}', data channel: '${msg.body.channelName}'.")
|
||||
} else {
|
||||
PluginDataChannelMessageDAO.delete(
|
||||
PluginDataChannelEntryDAO.delete(
|
||||
meetingId,
|
||||
msg.body.pluginName,
|
||||
msg.body.dataChannel,
|
||||
msg.body.messageId
|
||||
msg.body.channelName,
|
||||
msg.body.subChannelName,
|
||||
msg.body.entryId
|
||||
)
|
||||
}
|
||||
}
|
@ -1,15 +1,15 @@
|
||||
package org.bigbluebutton.core.apps.plugin
|
||||
|
||||
import org.bigbluebutton.common2.msgs.PluginDataChannelPushEntryMsg
|
||||
import org.bigbluebutton.ClientSettings
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.db.{ PluginDataChannelMessageDAO }
|
||||
import org.bigbluebutton.core.db.PluginDataChannelEntryDAO
|
||||
import org.bigbluebutton.core.domain.MeetingState2x
|
||||
import org.bigbluebutton.core.models.{ Roles, Users2x }
|
||||
import org.bigbluebutton.core.running.{ HandlerHelpers, LiveMeeting }
|
||||
|
||||
trait PluginDataChannelDispatchMessageMsgHdlr extends HandlerHelpers {
|
||||
trait PluginDataChannelPushEntryMsgHdlr extends HandlerHelpers {
|
||||
|
||||
def handle(msg: PluginDataChannelDispatchMessageMsg, state: MeetingState2x, liveMeeting: LiveMeeting): Unit = {
|
||||
def handle(msg: PluginDataChannelPushEntryMsg, state: MeetingState2x, liveMeeting: LiveMeeting): Unit = {
|
||||
val pluginsDisabled: Boolean = liveMeeting.props.meetingProp.disabledFeatures.contains("plugins")
|
||||
val meetingId = liveMeeting.props.meetingProp.intId
|
||||
|
||||
@ -21,11 +21,11 @@ trait PluginDataChannelDispatchMessageMsgHdlr extends HandlerHelpers {
|
||||
|
||||
if (!pluginsConfig.contains(msg.body.pluginName)) {
|
||||
println(s"Plugin '${msg.body.pluginName}' not found.")
|
||||
} else if (!pluginsConfig(msg.body.pluginName).dataChannels.contains(msg.body.dataChannel)) {
|
||||
println(s"Data channel '${msg.body.dataChannel}' not found in plugin '${msg.body.pluginName}'.")
|
||||
} else if (!pluginsConfig(msg.body.pluginName).dataChannels.contains(msg.body.channelName)) {
|
||||
println(s"Data channel '${msg.body.channelName}' not found in plugin '${msg.body.pluginName}'.")
|
||||
} else {
|
||||
val hasPermission = for {
|
||||
writePermission <- pluginsConfig(msg.body.pluginName).dataChannels(msg.body.dataChannel).writePermission
|
||||
writePermission <- pluginsConfig(msg.body.pluginName).dataChannels(msg.body.channelName).writePermission
|
||||
} yield {
|
||||
writePermission.toLowerCase match {
|
||||
case "all" => true
|
||||
@ -36,12 +36,13 @@ trait PluginDataChannelDispatchMessageMsgHdlr extends HandlerHelpers {
|
||||
}
|
||||
|
||||
if (!hasPermission.contains(true)) {
|
||||
println(s"No permission to write in plugin: '${msg.body.pluginName}', data channel: '${msg.body.dataChannel}'.")
|
||||
println(s"No permission to write in plugin: '${msg.body.pluginName}', data channel: '${msg.body.channelName}'.")
|
||||
} else {
|
||||
PluginDataChannelMessageDAO.insert(
|
||||
PluginDataChannelEntryDAO.insert(
|
||||
meetingId,
|
||||
msg.body.pluginName,
|
||||
msg.body.dataChannel,
|
||||
msg.body.channelName,
|
||||
msg.body.subChannelName,
|
||||
msg.header.userId,
|
||||
msg.body.payloadJson,
|
||||
msg.body.toRoles,
|
@ -2,7 +2,7 @@ package org.bigbluebutton.core.apps.plugin
|
||||
|
||||
import org.bigbluebutton.ClientSettings
|
||||
import org.bigbluebutton.common2.msgs.PluginDataChannelResetMsg
|
||||
import org.bigbluebutton.core.db.PluginDataChannelMessageDAO
|
||||
import org.bigbluebutton.core.db.PluginDataChannelEntryDAO
|
||||
import org.bigbluebutton.core.domain.MeetingState2x
|
||||
import org.bigbluebutton.core.models.{ Roles, Users2x }
|
||||
import org.bigbluebutton.core.running.{ HandlerHelpers, LiveMeeting }
|
||||
@ -21,11 +21,11 @@ trait PluginDataChannelResetMsgHdlr extends HandlerHelpers {
|
||||
|
||||
if (!pluginsConfig.contains(msg.body.pluginName)) {
|
||||
println(s"Plugin '${msg.body.pluginName}' not found.")
|
||||
} else if (!pluginsConfig(msg.body.pluginName).dataChannels.contains(msg.body.dataChannel)) {
|
||||
println(s"Data channel '${msg.body.dataChannel}' not found in plugin '${msg.body.pluginName}'.")
|
||||
} else if (!pluginsConfig(msg.body.pluginName).dataChannels.contains(msg.body.channelName)) {
|
||||
println(s"Data channel '${msg.body.channelName}' not found in plugin '${msg.body.pluginName}'.")
|
||||
} else {
|
||||
val hasPermission = for {
|
||||
deletePermission <- pluginsConfig(msg.body.pluginName).dataChannels(msg.body.dataChannel).deletePermission
|
||||
deletePermission <- pluginsConfig(msg.body.pluginName).dataChannels(msg.body.channelName).deletePermission
|
||||
} yield {
|
||||
deletePermission.toLowerCase match {
|
||||
case "all" => true
|
||||
@ -36,12 +36,13 @@ trait PluginDataChannelResetMsgHdlr extends HandlerHelpers {
|
||||
}
|
||||
|
||||
if (!hasPermission.contains(true)) {
|
||||
println(s"No permission to delete (reset) in plugin: '${msg.body.pluginName}', data channel: '${msg.body.dataChannel}'.")
|
||||
println(s"No permission to delete (reset) in plugin: '${msg.body.pluginName}', data channel: '${msg.body.channelName}'.")
|
||||
} else {
|
||||
PluginDataChannelMessageDAO.reset(
|
||||
PluginDataChannelEntryDAO.reset(
|
||||
meetingId,
|
||||
msg.body.pluginName,
|
||||
msg.body.dataChannel
|
||||
msg.body.channelName,
|
||||
msg.body.subChannelName
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -2,10 +2,11 @@ package org.bigbluebutton.core.apps.plugin
|
||||
|
||||
import org.apache.pekko.actor.ActorContext
|
||||
import org.apache.pekko.event.Logging
|
||||
import org.bigbluebutton.common2.msgs.PluginDataChannelDeleteEntryMsgBody
|
||||
|
||||
class PluginHdlrs(implicit val context: ActorContext)
|
||||
extends PluginDataChannelDispatchMessageMsgHdlr
|
||||
with PluginDataChannelDeleteMessageMsgHdlr
|
||||
extends PluginDataChannelPushEntryMsgHdlr
|
||||
with PluginDataChannelDeleteEntryMsgHdlr
|
||||
with PluginDataChannelResetMsgHdlr {
|
||||
|
||||
val log = Logging(context.system, getClass)
|
||||
|
@ -7,8 +7,8 @@ import org.bigbluebutton.core.bus.MessageBus
|
||||
import org.bigbluebutton.core.domain.MeetingState2x
|
||||
import org.bigbluebutton.core.models.Polls
|
||||
import org.bigbluebutton.core.running.LiveMeeting
|
||||
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
|
||||
import org.bigbluebutton.core.db.{ ChatMessageDAO, JsonUtils }
|
||||
import org.bigbluebutton.core.apps.{PermissionCheck, RightsManagementTrait}
|
||||
import org.bigbluebutton.core.db.{ChatMessageDAO, JsonUtils, NotificationDAO}
|
||||
import org.bigbluebutton.core2.message.senders.MsgBuilder
|
||||
import spray.json.DefaultJsonProtocol.jsonFormat2
|
||||
|
||||
@ -37,6 +37,7 @@ trait ShowPollResultReqMsgHdlr extends RightsManagementTrait {
|
||||
Vector()
|
||||
)
|
||||
bus.outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
|
||||
// SendWhiteboardAnnotationPubMsg
|
||||
val annotationRouting = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
|
@ -1,10 +1,9 @@
|
||||
package org.bigbluebutton.core.apps.presentationpod
|
||||
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.api.{ CapturePresentationReqInternalMsg, CaptureSharedNotesReqInternalMsg }
|
||||
import org.bigbluebutton.core.api.{ CapturePresentationReqInternalMsg }
|
||||
import org.bigbluebutton.core.apps.groupchats.GroupChatApp
|
||||
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
|
||||
import org.bigbluebutton.core.apps.presentationpod.PresentationSender
|
||||
import org.bigbluebutton.core.bus.MessageBus
|
||||
import org.bigbluebutton.core.db.{ ChatMessageDAO, PresPresentationDAO }
|
||||
import org.bigbluebutton.core.domain.MeetingState2x
|
||||
@ -268,35 +267,8 @@ trait MakePresentationDownloadReqMsgHdlr extends RightsManagementTrait {
|
||||
bus.outGW.send(buildBroadcastNewPresFileAvailable(m, liveMeeting))
|
||||
}
|
||||
|
||||
def handle(m: CaptureSharedNotesReqInternalMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||
val parentMeetingId = liveMeeting.props.meetingProp.intId
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, parentMeetingId, "not-used")
|
||||
val envelope = BbbCoreEnvelope(PresentationPageConversionStartedEventMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(CaptureSharedNotesReqEvtMsg.NAME, parentMeetingId, "not-used")
|
||||
val body = CaptureSharedNotesReqEvtMsgBody(m.breakoutId, m.filename)
|
||||
val event = CaptureSharedNotesReqEvtMsg(header, body)
|
||||
|
||||
bus.outGW.send(BbbCommonEnvCoreMsg(envelope, event))
|
||||
}
|
||||
|
||||
def handle(m: PresAnnStatusMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||
PresPresentationDAO.updateExportToChat(m.body.presId, m.body.status, m.body.pageNumber, m.body.error)
|
||||
bus.outGW.send(buildBroadcastPresAnnStatusMsg(m, liveMeeting))
|
||||
}
|
||||
|
||||
def handle(m: PadCapturePubMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||
|
||||
val userId: String = "system"
|
||||
val jobId: String = s"${m.body.breakoutId}-notes" // Used as the temporaryPresentationId upon upload
|
||||
val filename = m.body.filename
|
||||
val presentationUploadToken: String = PresentationPodsApp.generateToken("DEFAULT_PRESENTATION_POD", userId)
|
||||
val presentationId = PresentationPodsApp.generatePresentationId(m.body.filename)
|
||||
|
||||
bus.outGW.send(buildPresentationUploadTokenSysPubMsg(m.body.parentMeetingId, userId, presentationUploadToken, filename, presentationId))
|
||||
|
||||
val exportJob = new ExportJob(jobId, JobTypes.CAPTURE_NOTES, filename, filename, m.body.padId, "", true, List(), m.body.parentMeetingId, presentationUploadToken)
|
||||
val job = buildStoreExportJobInRedisSysMsg(exportJob, liveMeeting)
|
||||
|
||||
bus.outGW.send(job)
|
||||
}
|
||||
}
|
||||
|
@ -13,31 +13,7 @@ trait PresentationConversionUpdatePubMsgHdlr {
|
||||
def handle(msg: PresentationConversionUpdateSysPubMsg, state: MeetingState2x,
|
||||
liveMeeting: LiveMeeting, bus: MessageBus): MeetingState2x = {
|
||||
|
||||
def broadcastEvent(msg: PresentationConversionUpdateSysPubMsg): Unit = {
|
||||
val routing = Routing.addMsgToClientRouting(
|
||||
MessageTypes.BROADCAST_TO_MEETING,
|
||||
liveMeeting.props.meetingProp.intId, msg.header.userId
|
||||
)
|
||||
val envelope = BbbCoreEnvelope(PresentationConversionUpdateEvtMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(
|
||||
PresentationConversionUpdateEvtMsg.NAME,
|
||||
liveMeeting.props.meetingProp.intId, msg.header.userId
|
||||
)
|
||||
|
||||
val body = PresentationConversionUpdateEvtMsgBody(
|
||||
msg.body.podId,
|
||||
msg.body.messageKey,
|
||||
msg.body.code,
|
||||
msg.body.presentationId,
|
||||
msg.body.presName,
|
||||
msg.body.temporaryPresentationId
|
||||
)
|
||||
val event = PresentationConversionUpdateEvtMsg(header, body)
|
||||
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
|
||||
bus.outGW.send(msgEvent)
|
||||
}
|
||||
|
||||
broadcastEvent(msg)
|
||||
// broadcastEvent(msg)
|
||||
state
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ trait SyncGetPresentationPodsMsgHdlr {
|
||||
def handleSyncGetPresentationPods(state: MeetingState2x, liveMeeting: LiveMeeting, bus: MessageBus): MeetingState2x = {
|
||||
|
||||
def buildSyncGetPresentationPodsRespMsg(pods: Vector[PresentationPodVO]): BbbCommonEnvCoreMsg = {
|
||||
val routing = Routing.addMsgToHtml5InstanceIdRouting(liveMeeting.props.meetingProp.intId, liveMeeting.props.systemProps.html5InstanceId.toString)
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, liveMeeting.props.meetingProp.intId, "nodeJSapp")
|
||||
val envelope = BbbCoreEnvelope(SyncGetPresentationPodsRespMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(SyncGetPresentationPodsRespMsg.NAME, liveMeeting.props.meetingProp.intId, "nodeJSapp")
|
||||
|
||||
|
@ -9,9 +9,10 @@ trait SyncGetScreenshareInfoRespMsgHdlr {
|
||||
this: ScreenshareApp2x =>
|
||||
|
||||
def handleSyncGetScreenshareInfoRespMsg(liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||
val routing = Routing.addMsgToHtml5InstanceIdRouting(
|
||||
val routing = Routing.addMsgToClientRouting(
|
||||
MessageTypes.BROADCAST_TO_MEETING,
|
||||
liveMeeting.props.meetingProp.intId,
|
||||
liveMeeting.props.systemProps.html5InstanceId.toString
|
||||
"nodeJSapp"
|
||||
)
|
||||
val envelope = BbbCoreEnvelope(SyncGetScreenshareInfoRespMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(
|
||||
|
@ -3,7 +3,7 @@ package org.bigbluebutton.core.apps.users
|
||||
import org.bigbluebutton.LockSettingsUtil
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
|
||||
import org.bigbluebutton.core.db.MeetingLockSettingsDAO
|
||||
import org.bigbluebutton.core.db.{ MeetingLockSettingsDAO, NotificationDAO }
|
||||
import org.bigbluebutton.core.models._
|
||||
import org.bigbluebutton.core.running.OutMsgRouter
|
||||
import org.bigbluebutton.core.running.MeetingActor
|
||||
@ -66,6 +66,7 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
|
||||
LockSettingsUtil.enforceCamLockSettingsForAllUsers(liveMeeting, outGW)
|
||||
} else {
|
||||
@ -78,6 +79,7 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
}
|
||||
}
|
||||
|
||||
@ -92,6 +94,7 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
VoiceUsers.findAll(liveMeeting.voiceUsers) foreach { vu =>
|
||||
if (vu.intId.startsWith(IntIdPrefixType.DIAL_IN)) { // only Dial-in users need this
|
||||
val eventExplicitLock = buildLockMessage(liveMeeting.props.meetingProp.intId, vu.intId, msg.body.setBy, settings.disableMic)
|
||||
@ -109,6 +112,7 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,6 +127,7 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
} else {
|
||||
val notifyEvent = MsgBuilder.buildNotifyAllInMeetingEvtMsg(
|
||||
liveMeeting.props.meetingProp.intId,
|
||||
@ -133,6 +138,7 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
}
|
||||
}
|
||||
|
||||
@ -147,6 +153,7 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
} else {
|
||||
val notifyEvent = MsgBuilder.buildNotifyAllInMeetingEvtMsg(
|
||||
liveMeeting.props.meetingProp.intId,
|
||||
@ -157,6 +164,7 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
}
|
||||
}
|
||||
|
||||
@ -171,6 +179,7 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
} else {
|
||||
val notifyEvent = MsgBuilder.buildNotifyAllInMeetingEvtMsg(
|
||||
liveMeeting.props.meetingProp.intId,
|
||||
@ -181,6 +190,7 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
}
|
||||
}
|
||||
|
||||
@ -195,6 +205,7 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
} else {
|
||||
val notifyEvent = MsgBuilder.buildNotifyAllInMeetingEvtMsg(
|
||||
liveMeeting.props.meetingProp.intId,
|
||||
@ -205,6 +216,7 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@ import org.bigbluebutton.core.models.{ RegisteredUsers, Roles, UserState, Users2
|
||||
import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter }
|
||||
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
|
||||
import org.bigbluebutton.LockSettingsUtil
|
||||
import org.bigbluebutton.core.db.NotificationDAO
|
||||
import org.bigbluebutton.core2.message.senders.{ MsgBuilder, Sender }
|
||||
|
||||
trait ChangeUserRoleCmdMsgHdlr extends RightsManagementTrait {
|
||||
@ -43,6 +44,7 @@ trait ChangeUserRoleCmdMsgHdlr extends RightsManagementTrait {
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
|
||||
Users2x.changeRole(liveMeeting.users2x, uvo, msg.body.role)
|
||||
val event = buildUserRoleChangedEvtMsg(liveMeeting.props.meetingProp.intId, msg.body.userId,
|
||||
@ -59,6 +61,7 @@ trait ChangeUserRoleCmdMsgHdlr extends RightsManagementTrait {
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
|
||||
val newUvo: UserState = Users2x.changeRole(liveMeeting.users2x, uvo, msg.body.role)
|
||||
val event = buildUserRoleChangedEvtMsg(liveMeeting.props.meetingProp.intId, msg.body.userId,
|
||||
|
@ -1,6 +1,7 @@
|
||||
package org.bigbluebutton.core.apps.users
|
||||
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.db.NotificationDAO
|
||||
import org.bigbluebutton.core.models._
|
||||
import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter }
|
||||
import org.bigbluebutton.core.util.ColorPicker
|
||||
@ -58,7 +59,7 @@ trait RegisterUserReqMsgHdlr {
|
||||
|
||||
val guestStatus = msg.body.guestStatus
|
||||
|
||||
val regUser = RegisteredUsers.create(msg.body.intUserId, msg.body.extUserId,
|
||||
val regUser = RegisteredUsers.create(liveMeeting.props.meetingProp.intId, msg.body.intUserId, msg.body.extUserId,
|
||||
msg.body.name, msg.body.role, msg.body.authToken, msg.body.sessionToken,
|
||||
msg.body.avatarURL, ColorPicker.nextColor(liveMeeting.props.meetingProp.intId), msg.body.guest, msg.body.authed,
|
||||
guestStatus, msg.body.excludeFromDashboard, msg.body.enforceLayout, msg.body.customParameters, false)
|
||||
@ -107,6 +108,7 @@ trait RegisterUserReqMsgHdlr {
|
||||
Vector(s"${regUser.name}")
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
case GuestStatus.DENY =>
|
||||
val g = GuestApprovedVO(regUser.id, GuestStatus.DENY)
|
||||
UsersApp.approveOrRejectGuest(liveMeeting, outGW, g, SystemUser.ID)
|
||||
|
@ -1,63 +0,0 @@
|
||||
package org.bigbluebutton.core.apps.users
|
||||
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter }
|
||||
import org.bigbluebutton.core.models.{ UserState, Users2x }
|
||||
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
|
||||
import org.bigbluebutton.core2.MeetingStatus2x
|
||||
import org.bigbluebutton.SystemConfiguration
|
||||
import scala.util.Random
|
||||
|
||||
trait SelectRandomViewerReqMsgHdlr extends RightsManagementTrait {
|
||||
this: UsersApp =>
|
||||
|
||||
val outGW: OutMsgRouter
|
||||
|
||||
def handleSelectRandomViewerReqMsg(msg: SelectRandomViewerReqMsg): Unit = {
|
||||
log.debug("Received SelectRandomViewerReqMsg {}", SelectRandomViewerReqMsg)
|
||||
|
||||
def broadcastEvent(msg: SelectRandomViewerReqMsg, users: Vector[String], choice: String): Unit = {
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
val envelope = BbbCoreEnvelope(SelectRandomViewerRespMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(SelectRandomViewerRespMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
|
||||
val body = SelectRandomViewerRespMsgBody(msg.header.userId, users, choice)
|
||||
val event = SelectRandomViewerRespMsg(header, body)
|
||||
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
|
||||
outGW.send(msgEvent)
|
||||
}
|
||||
|
||||
if (permissionFailed(PermissionCheck.GUEST_LEVEL, PermissionCheck.PRESENTER_LEVEL, liveMeeting.users2x, msg.header.userId)) {
|
||||
val meetingId = liveMeeting.props.meetingProp.intId
|
||||
val reason = "No permission to select random user."
|
||||
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, outGW, liveMeeting)
|
||||
} else {
|
||||
val users = Users2x.getRandomlyPickableUsers(liveMeeting.users2x, false)
|
||||
|
||||
val usersPicked = Users2x.getRandomlyPickableUsers(liveMeeting.users2x, reduceDuplicatedPick)
|
||||
|
||||
val randNum = new scala.util.Random
|
||||
var pickedUser = if (usersPicked.size == 0) "" else usersPicked(randNum.nextInt(usersPicked.size)).intId
|
||||
|
||||
if (reduceDuplicatedPick) {
|
||||
if (usersPicked.size <= 1) {
|
||||
// Initialise the exemption
|
||||
val usersToUnexempt = Users2x.findAll(liveMeeting.users2x)
|
||||
usersToUnexempt foreach { u =>
|
||||
Users2x.setUserExempted(liveMeeting.users2x, u.intId, false)
|
||||
}
|
||||
if (usersPicked.size == 0) {
|
||||
// Pick again
|
||||
val usersRepicked = Users2x.getRandomlyPickableUsers(liveMeeting.users2x, reduceDuplicatedPick)
|
||||
pickedUser = if (usersRepicked.size == 0) "" else usersRepicked(randNum.nextInt(usersRepicked.size)).intId
|
||||
Users2x.setUserExempted(liveMeeting.users2x, pickedUser, true)
|
||||
}
|
||||
} else if (usersPicked.size > 1) {
|
||||
Users2x.setUserExempted(liveMeeting.users2x, pickedUser, true)
|
||||
}
|
||||
}
|
||||
val userIds = users.map { case (v) => v.intId }
|
||||
broadcastEvent(msg, userIds, pickedUser)
|
||||
}
|
||||
}
|
||||
}
|
@ -10,7 +10,7 @@ import org.bigbluebutton.core.api.SendRecordingTimerInternalMsg
|
||||
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
|
||||
import org.bigbluebutton.core2.message.senders.MsgBuilder
|
||||
import org.bigbluebutton.core.apps.voice.VoiceApp
|
||||
import org.bigbluebutton.core.db.MeetingRecordingDAO
|
||||
import org.bigbluebutton.core.db.{ MeetingRecordingDAO, NotificationDAO }
|
||||
|
||||
trait SetRecordingStatusCmdMsgHdlr extends RightsManagementTrait {
|
||||
this: UsersApp =>
|
||||
@ -49,6 +49,7 @@ trait SetRecordingStatusCmdMsgHdlr extends RightsManagementTrait {
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
|
||||
MeetingStatus2x.recordingStarted(liveMeeting.status)
|
||||
MeetingRecordingDAO.insertRecording(liveMeeting.props.meetingProp.intId, msg.body.setBy)
|
||||
@ -75,6 +76,7 @@ trait SetRecordingStatusCmdMsgHdlr extends RightsManagementTrait {
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
|
||||
MeetingStatus2x.recordingStopped(liveMeeting.status)
|
||||
MeetingRecordingDAO.updateStopped(liveMeeting.props.meetingProp.intId, msg.body.setBy)
|
||||
|
@ -0,0 +1,41 @@
|
||||
package org.bigbluebutton.core.apps.users
|
||||
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.models.{ UserState, Users2x }
|
||||
import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter }
|
||||
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
|
||||
import org.bigbluebutton.core.domain.MeetingState2x
|
||||
|
||||
trait SetUserSpeechOptionsMsgHdlr extends RightsManagementTrait {
|
||||
this: UsersApp =>
|
||||
|
||||
val liveMeeting: LiveMeeting
|
||||
val outGW: OutMsgRouter
|
||||
|
||||
def handleSetUserSpeechOptionsReqMsg(msg: SetUserSpeechOptionsReqMsg): Unit = {
|
||||
log.info("handleSetUserSpeechOptionsReqMsg: partialUtterances={} minUtteranceLength={} userId={}", msg.body.partialUtterances, msg.body.minUtteranceLength, msg.header.userId)
|
||||
|
||||
def broadcastUserSpeechOptionsChanged(user: UserState, partialUtterances: Boolean, minUtteranceLength: Int): Unit = {
|
||||
val routingChange = Routing.addMsgToClientRouting(
|
||||
MessageTypes.BROADCAST_TO_MEETING,
|
||||
liveMeeting.props.meetingProp.intId, user.intId
|
||||
)
|
||||
val envelopeChange = BbbCoreEnvelope(UserSpeechOptionsChangedEvtMsg.NAME, routingChange)
|
||||
val headerChange = BbbClientMsgHeader(UserSpeechOptionsChangedEvtMsg.NAME, liveMeeting.props.meetingProp.intId, user.intId)
|
||||
|
||||
val bodyChange = UserSpeechOptionsChangedEvtMsgBody(partialUtterances, minUtteranceLength)
|
||||
val eventChange = UserSpeechOptionsChangedEvtMsg(headerChange, bodyChange)
|
||||
val msgEventChange = BbbCommonEnvCoreMsg(envelopeChange, eventChange)
|
||||
outGW.send(msgEventChange)
|
||||
}
|
||||
|
||||
for {
|
||||
user <- Users2x.findWithIntId(liveMeeting.users2x, msg.header.userId)
|
||||
} yield {
|
||||
var changeLocale: Option[UserState] = None;
|
||||
//changeLocale = Users2x.setUserSpeechLocale(liveMeeting.users2x, msg.header.userId, msg.body.locale)
|
||||
broadcastUserSpeechOptionsChanged(user, msg.body.partialUtterances, msg.body.minUtteranceLength)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -11,7 +11,7 @@ trait SyncGetUsersMeetingRespMsgHdlr {
|
||||
val outGW: OutMsgRouter
|
||||
|
||||
def handleSyncGetUsersMeetingRespMsg(): Unit = {
|
||||
val routing = Routing.addMsgToHtml5InstanceIdRouting(liveMeeting.props.meetingProp.intId, liveMeeting.props.systemProps.html5InstanceId.toString)
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, liveMeeting.props.meetingProp.intId, "nodeJSapp")
|
||||
val envelope = BbbCoreEnvelope(SyncGetUsersMeetingRespMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(SyncGetUsersMeetingRespMsg.NAME, liveMeeting.props.meetingProp.intId, "nodeJSapp")
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package org.bigbluebutton.core.apps.users
|
||||
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.db.UserDAO
|
||||
import org.bigbluebutton.core.models.{ Users2x, VoiceUserState, VoiceUsers }
|
||||
import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter }
|
||||
|
||||
@ -29,10 +30,10 @@ trait UserConnectedToGlobalAudioMsgHdlr {
|
||||
for {
|
||||
user <- Users2x.findWithIntId(liveMeeting.users2x, msg.body.userId)
|
||||
} yield {
|
||||
|
||||
val vu = VoiceUserState(
|
||||
intId = user.intId,
|
||||
voiceUserId = user.intId,
|
||||
meetingId = props.meetingProp.intId,
|
||||
callingWith = "flash",
|
||||
callerName = user.name,
|
||||
callerNum = user.name,
|
||||
|
@ -1,9 +1,10 @@
|
||||
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.{ UserState, Users2x }
|
||||
import org.bigbluebutton.core.models.Users2x
|
||||
import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter }
|
||||
|
||||
trait UserConnectionAliveReqMsgHdlr extends RightsManagementTrait {
|
||||
@ -13,13 +14,42 @@ trait UserConnectionAliveReqMsgHdlr extends RightsManagementTrait {
|
||||
val outGW: OutMsgRouter
|
||||
|
||||
def handleUserConnectionAliveReqMsg(msg: UserConnectionAliveReqMsg): Unit = {
|
||||
log.info("handleUserConnectionAliveReqMsg: userId={}", msg.body.userId)
|
||||
log.info("handleUserConnectionAliveReqMsg: networkRttInMs={} userId={}", msg.body.networkRttInMs, msg.body.userId)
|
||||
|
||||
for {
|
||||
user <- Users2x.findWithIntId(liveMeeting.users2x, msg.body.userId)
|
||||
} yield {
|
||||
UserConnectionStatusDAO.updateUserAlive(user.intId)
|
||||
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")
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,25 +0,0 @@
|
||||
package org.bigbluebutton.core.apps.users
|
||||
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.apps.RightsManagementTrait
|
||||
import org.bigbluebutton.core.db.UserConnectionStatusDAO
|
||||
import org.bigbluebutton.core.models.{ UserState, Users2x }
|
||||
import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter }
|
||||
|
||||
trait UserConnectionUpdateRttReqMsgHdlr extends RightsManagementTrait {
|
||||
this: UsersApp =>
|
||||
|
||||
val liveMeeting: LiveMeeting
|
||||
val outGW: OutMsgRouter
|
||||
|
||||
def handleUserConnectionUpdateRttReqMsg(msg: UserConnectionUpdateRttReqMsg): Unit = {
|
||||
log.info("handleUserConnectionUpdateRttReqMsg: networkRttInMs={} userId={}", msg.body.networkRttInMs, msg.body.userId)
|
||||
|
||||
for {
|
||||
user <- Users2x.findWithIntId(liveMeeting.users2x, msg.body.userId)
|
||||
} yield {
|
||||
UserConnectionStatusDAO.updateUserRtt(user.intId, msg.body.networkRttInMs)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -28,7 +28,7 @@ trait UserDisconnectedFromGlobalAudioMsgHdlr {
|
||||
for {
|
||||
user <- VoiceUsers.findWithIntId(liveMeeting.voiceUsers, msg.body.userId)
|
||||
} yield {
|
||||
VoiceUsers.removeWithIntId(liveMeeting.voiceUsers, user.intId)
|
||||
VoiceUsers.removeWithIntId(liveMeeting.voiceUsers, liveMeeting.props.meetingProp.intId, user.intId)
|
||||
broadcastEvent(user)
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ package org.bigbluebutton.core.apps.users
|
||||
|
||||
import org.bigbluebutton.common2.msgs.UserJoinMeetingReqMsg
|
||||
import org.bigbluebutton.core.apps.breakout.BreakoutHdlrHelpers
|
||||
import org.bigbluebutton.core.db.{ UserDAO, UserStateDAO }
|
||||
import org.bigbluebutton.core.db.{ NotificationDAO, UserDAO, UserStateDAO }
|
||||
import org.bigbluebutton.core.domain.MeetingState2x
|
||||
import org.bigbluebutton.core.models._
|
||||
import org.bigbluebutton.core.running._
|
||||
@ -58,7 +58,7 @@ trait UserJoinMeetingReqMsgHdlr extends HandlerHelpers {
|
||||
|
||||
private def handleFailedUserJoin(msg: UserJoinMeetingReqMsg, failReason: String, failReasonCode: String) = {
|
||||
log.info("Ignoring user {} attempt to join in meeting {}. Reason Code: {}, Reason Message: {}", msg.body.userId, msg.header.meetingId, failReasonCode, failReason)
|
||||
UserDAO.updateJoinError(msg.body.userId, failReasonCode, failReason)
|
||||
UserDAO.updateJoinError(msg.header.meetingId, msg.body.userId, failReasonCode, failReason)
|
||||
state
|
||||
}
|
||||
|
||||
@ -137,6 +137,7 @@ trait UserJoinMeetingReqMsgHdlr extends HandlerHelpers {
|
||||
Vector(newUser.name)
|
||||
)
|
||||
outGW.send(notifyUserEvent)
|
||||
NotificationDAO.insert(notifyUserEvent)
|
||||
}
|
||||
|
||||
private def clearCachedVoiceUser(regUser: RegisteredUser) =
|
||||
@ -144,7 +145,7 @@ trait UserJoinMeetingReqMsgHdlr extends HandlerHelpers {
|
||||
VoiceUsers.recoverVoiceUser(liveMeeting.voiceUsers, regUser.id)
|
||||
|
||||
private def clearExpiredUserState(regUser: RegisteredUser) =
|
||||
UserStateDAO.updateExpired(regUser.id, false)
|
||||
UserStateDAO.updateExpired(regUser.meetingId, regUser.id, false)
|
||||
|
||||
private def ForceUserGraphqlReconnection(regUser: RegisteredUser) =
|
||||
Sender.sendForceUserGraphqlReconnectionSysMsg(liveMeeting.props.meetingProp.intId, regUser.id, regUser.sessionToken, "user_joined", outGW)
|
||||
|
@ -44,7 +44,7 @@ object UsersApp {
|
||||
u <- RegisteredUsers.findWithUserId(guest.guest, liveMeeting.registeredUsers)
|
||||
} yield {
|
||||
RegisteredUsers.setWaitingForApproval(liveMeeting.registeredUsers, u, guest.status)
|
||||
UserStateDAO.updateGuestStatus(guest.guest, guest.status, approvedBy)
|
||||
UserStateDAO.updateGuestStatus(liveMeeting.props.meetingProp.intId, guest.guest, guest.status, approvedBy)
|
||||
// send message to user that he has been approved
|
||||
|
||||
val event = MsgBuilder.buildGuestApprovedEvtMsg(
|
||||
@ -131,7 +131,7 @@ object UsersApp {
|
||||
// println(s"ejectUserFromMeeting will cause a automaticallyAssignPresenter for user=${user}")
|
||||
automaticallyAssignPresenter(outGW, liveMeeting)
|
||||
}
|
||||
UserStateDAO.updateEjected(userId, reason, reasonCode, ejectedBy)
|
||||
UserStateDAO.updateEjected(meetingId, userId, reason, reasonCode, ejectedBy)
|
||||
}
|
||||
|
||||
for {
|
||||
@ -158,18 +158,17 @@ class UsersApp(
|
||||
with RegisterUserReqMsgHdlr
|
||||
with ChangeUserRoleCmdMsgHdlr
|
||||
with SetUserSpeechLocaleMsgHdlr
|
||||
with SetUserSpeechOptionsMsgHdlr
|
||||
with SyncGetUsersMeetingRespMsgHdlr
|
||||
with LogoutAndEndMeetingCmdMsgHdlr
|
||||
with SetRecordingStatusCmdMsgHdlr
|
||||
with RecordAndClearPreviousMarkersCmdMsgHdlr
|
||||
with SendRecordingTimerInternalMsgHdlr
|
||||
with GetRecordingStatusReqMsgHdlr
|
||||
with SelectRandomViewerReqMsgHdlr
|
||||
with AssignPresenterReqMsgHdlr
|
||||
with ChangeUserPinStateReqMsgHdlr
|
||||
with ChangeUserMobileFlagReqMsgHdlr
|
||||
with UserConnectionAliveReqMsgHdlr
|
||||
with UserConnectionUpdateRttReqMsgHdlr
|
||||
with ChangeUserReactionEmojiReqMsgHdlr
|
||||
with ChangeUserRaiseHandReqMsgHdlr
|
||||
with ChangeUserAwayReqMsgHdlr
|
||||
|
@ -75,7 +75,7 @@ trait ValidateAuthTokenReqMsgHdlr extends HandlerHelpers {
|
||||
}
|
||||
|
||||
private def sendFailedValidateAuthTokenRespMsg(msg: ValidateAuthTokenReqMsg, failReason: String, failReasonCode: String) = {
|
||||
UserDAO.updateJoinError(msg.body.userId, failReasonCode, failReason)
|
||||
UserDAO.updateJoinError(msg.header.meetingId, msg.body.userId, failReasonCode, failReason)
|
||||
|
||||
val event = MsgBuilder.buildValidateAuthTokenRespMsg(liveMeeting.props.meetingProp.intId, msg.header.userId, msg.body.authToken, false, false, 0,
|
||||
0, failReasonCode, failReason)
|
||||
|
@ -17,7 +17,7 @@ trait SyncGetVoiceUsersMsgHdlr {
|
||||
callerNum = u.callerNum, color = u.color, muted = u.muted, talking = u.talking, listenOnly = u.listenOnly)
|
||||
}
|
||||
|
||||
val routing = Routing.addMsgToHtml5InstanceIdRouting(liveMeeting.props.meetingProp.intId, liveMeeting.props.systemProps.html5InstanceId.toString)
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, liveMeeting.props.meetingProp.intId, "nodeJSapp")
|
||||
val envelope = BbbCoreEnvelope(SyncGetVoiceUsersRespMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(SyncGetVoiceUsersRespMsg.NAME, liveMeeting.props.meetingProp.intId, "nodeJSapp")
|
||||
val body = SyncGetVoiceUsersRespMsgBody(voiceUsers)
|
||||
|
@ -32,7 +32,7 @@ trait UserJoinedVoiceConfEvtMsgHdlr extends SystemConfiguration {
|
||||
}
|
||||
|
||||
def registerUserInRegisteredUsers() = {
|
||||
val regUser = RegisteredUsers.create(msg.body.intId, msg.body.voiceUserId,
|
||||
val regUser = RegisteredUsers.create(liveMeeting.props.meetingProp.intId, msg.body.intId, msg.body.voiceUserId,
|
||||
msg.body.callerIdName, Roles.VIEWER_ROLE, msg.body.intId, "", "", userColor,
|
||||
true, true, GuestStatus.WAIT, true, "", Map(), false)
|
||||
RegisteredUsers.add(liveMeeting.registeredUsers, regUser, liveMeeting.props.meetingProp.intId)
|
||||
@ -42,6 +42,7 @@ trait UserJoinedVoiceConfEvtMsgHdlr extends SystemConfiguration {
|
||||
val newUser = UserState(
|
||||
intId = msg.body.intId,
|
||||
extId = msg.body.voiceUserId,
|
||||
meetingId = liveMeeting.props.meetingProp.intId,
|
||||
name = msg.body.callerIdName,
|
||||
role = Roles.VIEWER_ROLE,
|
||||
guest = true,
|
||||
@ -58,7 +59,6 @@ trait UserJoinedVoiceConfEvtMsgHdlr extends SystemConfiguration {
|
||||
avatar = "",
|
||||
color = userColor,
|
||||
clientType = if (isDialInUser) "dial-in-user" else "",
|
||||
pickExempted = false,
|
||||
userLeftFlag = UserLeftFlag(false, 0)
|
||||
)
|
||||
Users2x.add(liveMeeting.users2x, newUser)
|
||||
|
@ -40,14 +40,14 @@ trait UserLeftVoiceConfEvtMsgHdlr {
|
||||
UsersApp.guestWaitingLeft(liveMeeting, user.intId, outGW)
|
||||
}
|
||||
Users2x.remove(liveMeeting.users2x, user.intId)
|
||||
UserDAO.softDelete(user.intId)
|
||||
UserDAO.softDelete(user.meetingId, user.intId)
|
||||
VoiceApp.removeUserFromVoiceConf(liveMeeting, outGW, msg.body.voiceUserId)
|
||||
}
|
||||
|
||||
for {
|
||||
user <- VoiceUsers.findWithVoiceUserId(liveMeeting.voiceUsers, msg.body.voiceUserId)
|
||||
} yield {
|
||||
VoiceUsers.removeWithIntId(liveMeeting.voiceUsers, user.intId)
|
||||
VoiceUsers.removeWithIntId(liveMeeting.voiceUsers, liveMeeting.props.meetingProp.intId, user.intId)
|
||||
broadcastEvent(user)
|
||||
}
|
||||
|
||||
|
@ -238,7 +238,7 @@ object VoiceApp extends SystemConfiguration {
|
||||
): Unit = {
|
||||
for {
|
||||
u <- VoiceUsers.findWithIntId(liveMeeting.voiceUsers, userid)
|
||||
oldU <- VoiceUsers.removeWithIntId(liveMeeting.voiceUsers, userid)
|
||||
oldU <- VoiceUsers.removeWithIntId(liveMeeting.voiceUsers, u.meetingId, u.intId)
|
||||
} yield {
|
||||
val event = MsgBuilder.buildEjectUserFromVoiceConfSysMsg(liveMeeting.props.meetingProp.intId, liveMeeting.props.voiceProp.voiceConf, oldU.voiceUserId)
|
||||
outGW.send(event)
|
||||
@ -302,7 +302,6 @@ object VoiceApp extends SystemConfiguration {
|
||||
)
|
||||
outGW.send(msgEvent)
|
||||
}
|
||||
|
||||
checkAndEjectOldDuplicateVoiceConfUser(intId, liveMeeting, outGW)
|
||||
|
||||
val isListenOnly = if (callerIdName.startsWith("LISTENONLY")) true else false
|
||||
@ -310,6 +309,7 @@ object VoiceApp extends SystemConfiguration {
|
||||
val voiceUserState = VoiceUserState(
|
||||
intId,
|
||||
voiceUserId,
|
||||
meetingId = liveMeeting.props.meetingProp.intId,
|
||||
callingWith,
|
||||
callerIdName,
|
||||
callerIdNum,
|
||||
@ -393,7 +393,7 @@ object VoiceApp extends SystemConfiguration {
|
||||
for {
|
||||
user <- VoiceUsers.findWithVoiceUserId(liveMeeting.voiceUsers, voiceUserId)
|
||||
} yield {
|
||||
VoiceUsers.removeWithIntId(liveMeeting.voiceUsers, user.intId)
|
||||
VoiceUsers.removeWithIntId(liveMeeting.voiceUsers, user.meetingId, user.intId)
|
||||
broadcastEvent(user)
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,7 @@ trait VoiceConfCallStateEvtMsgHdlr {
|
||||
outGW.send(msgEvent)
|
||||
|
||||
if (msg.body.userId.nonEmpty) {
|
||||
UserVoiceConfStateDAO.insertOrUpdate(msg.body.userId, msg.body.voiceConf, msg.body.callSession, msg.body.clientSession, msg.body.callState)
|
||||
UserVoiceConfStateDAO.insertOrUpdate(liveMeeting.props.meetingProp.intId, msg.body.userId, msg.body.voiceConf, msg.body.callSession, msg.body.clientSession, msg.body.callState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,9 +13,10 @@ trait SyncGetWebcamInfoRespMsgHdlr {
|
||||
this: WebcamApp2x =>
|
||||
|
||||
def handleSyncGetWebcamInfoRespMsg(liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||
val routing = Routing.addMsgToHtml5InstanceIdRouting(
|
||||
val routing = Routing.addMsgToClientRouting(
|
||||
MessageTypes.BROADCAST_TO_MEETING,
|
||||
liveMeeting.props.meetingProp.intId,
|
||||
liveMeeting.props.systemProps.html5InstanceId.toString
|
||||
"nodeJSapp"
|
||||
)
|
||||
val envelope = BbbCoreEnvelope(SyncGetWebcamInfoRespMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(
|
||||
|
@ -3,7 +3,7 @@ package org.bigbluebutton.core.apps.webcam
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.apps.PermissionCheck
|
||||
import org.bigbluebutton.core.bus.MessageBus
|
||||
import org.bigbluebutton.core.db.MeetingUsersPoliciesDAO
|
||||
import org.bigbluebutton.core.db.{ MeetingUsersPoliciesDAO, NotificationDAO }
|
||||
import org.bigbluebutton.core.models.{ RegisteredUsers, Roles, Users2x }
|
||||
import org.bigbluebutton.core.running.LiveMeeting
|
||||
import org.bigbluebutton.core2.message.senders.{ MsgBuilder, Sender }
|
||||
@ -64,6 +64,7 @@ trait UpdateWebcamsOnlyForModeratorCmdMsgHdlr {
|
||||
Vector()
|
||||
)
|
||||
bus.outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
} else {
|
||||
val notifyEvent = MsgBuilder.buildNotifyAllInMeetingEvtMsg(
|
||||
meetingId,
|
||||
@ -74,6 +75,7 @@ trait UpdateWebcamsOnlyForModeratorCmdMsgHdlr {
|
||||
Vector()
|
||||
)
|
||||
bus.outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
}
|
||||
|
||||
broadcastEvent(meetingId, msg.body.setBy, value)
|
||||
|
@ -47,7 +47,7 @@ trait UserBroadcastCamStartMsgHdlr {
|
||||
val webcam = new WebcamStream(msg.body.stream, msg.header.userId, Set.empty)
|
||||
|
||||
for {
|
||||
_ <- Webcams.addWebcamStream(liveMeeting.webcams, webcam)
|
||||
_ <- Webcams.addWebcamStream(liveMeeting.props.meetingProp.intId, liveMeeting.webcams, webcam)
|
||||
} yield broadcastEvent(meetingId, msg.header.userId, msg.body.stream)
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ trait ClearWhiteboardPubMsgHdlr extends RightsManagementTrait {
|
||||
def handle(msg: ClearWhiteboardPubMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||
|
||||
def broadcastEvent(msg: ClearWhiteboardPubMsg, fullClear: Boolean): Unit = {
|
||||
val routing = Routing.addMsgToHtml5InstanceIdRouting(liveMeeting.props.meetingProp.intId, liveMeeting.props.systemProps.html5InstanceId.toString)
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
val envelope = BbbCoreEnvelope(ClearWhiteboardEvtMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(ClearWhiteboardEvtMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
|
||||
|
@ -11,7 +11,7 @@ trait DeleteWhiteboardAnnotationsPubMsgHdlr extends RightsManagementTrait {
|
||||
def handle(msg: DeleteWhiteboardAnnotationsPubMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||
|
||||
def broadcastEvent(msg: DeleteWhiteboardAnnotationsPubMsg, removedAnnotationsIds: Array[String]): Unit = {
|
||||
val routing = Routing.addMsgToHtml5InstanceIdRouting(liveMeeting.props.meetingProp.intId, liveMeeting.props.systemProps.html5InstanceId.toString)
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
val envelope = BbbCoreEnvelope(DeleteWhiteboardAnnotationsEvtMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(DeleteWhiteboardAnnotationsEvtMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
|
||||
|
@ -10,7 +10,7 @@ trait GetWhiteboardAnnotationsReqMsgHdlr {
|
||||
def handle(msg: GetWhiteboardAnnotationsReqMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||
|
||||
def broadcastEvent(msg: GetWhiteboardAnnotationsReqMsg, history: Array[AnnotationVO], multiUser: Array[String]): Unit = {
|
||||
val routing = Routing.addMsgToHtml5InstanceIdRouting(liveMeeting.props.meetingProp.intId, liveMeeting.props.systemProps.html5InstanceId.toString)
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
|
||||
val envelope = BbbCoreEnvelope(GetWhiteboardAnnotationsRespMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(GetWhiteboardAnnotationsRespMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
|
@ -11,7 +11,7 @@ trait ModifyWhiteboardAccessPubMsgHdlr extends RightsManagementTrait {
|
||||
def handle(msg: ModifyWhiteboardAccessPubMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||
|
||||
def broadcastEvent(msg: ModifyWhiteboardAccessPubMsg): Unit = {
|
||||
val routing = Routing.addMsgToHtml5InstanceIdRouting(liveMeeting.props.meetingProp.intId, liveMeeting.props.systemProps.html5InstanceId.toString)
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
val envelope = BbbCoreEnvelope(ModifyWhiteboardAccessEvtMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(ModifyWhiteboardAccessEvtMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
|
||||
|
@ -12,7 +12,7 @@ trait SendCursorPositionPubMsgHdlr extends RightsManagementTrait {
|
||||
def handle(msg: SendCursorPositionPubMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||
|
||||
def broadcastEvent(msg: SendCursorPositionPubMsg): Unit = {
|
||||
val routing = Routing.addMsgToHtml5InstanceIdRouting(liveMeeting.props.meetingProp.intId, liveMeeting.props.systemProps.html5InstanceId.toString)
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
val envelope = BbbCoreEnvelope(SendCursorPositionEvtMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(SendCursorPositionEvtMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
|
||||
@ -30,7 +30,7 @@ trait SendCursorPositionPubMsgHdlr extends RightsManagementTrait {
|
||||
//PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
|
||||
} else {
|
||||
broadcastEvent(msg)
|
||||
PresPageCursorDAO.insertOrUpdate(msg.body.whiteboardId, msg.header.userId, msg.body.xPercent, msg.body.yPercent)
|
||||
PresPageCursorDAO.insertOrUpdate(msg.body.whiteboardId, liveMeeting.props.meetingProp.intId, msg.header.userId, msg.body.xPercent, msg.body.yPercent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,8 +10,8 @@ trait SendWhiteboardAnnotationsPubMsgHdlr extends RightsManagementTrait {
|
||||
|
||||
def handle(msg: SendWhiteboardAnnotationsPubMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||
|
||||
def broadcastEvent(msg: SendWhiteboardAnnotationsPubMsg, whiteboardId: String, annotations: Array[AnnotationVO], html5InstanceId: String): Unit = {
|
||||
val routing = Routing.addMsgToHtml5InstanceIdRouting(liveMeeting.props.meetingProp.intId, html5InstanceId)
|
||||
def broadcastEvent(msg: SendWhiteboardAnnotationsPubMsg, whiteboardId: String, annotations: Array[AnnotationVO]): Unit = {
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
val envelope = BbbCoreEnvelope(SendWhiteboardAnnotationsEvtMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(SendWhiteboardAnnotationsEvtMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
|
||||
@ -58,7 +58,7 @@ trait SendWhiteboardAnnotationsPubMsgHdlr extends RightsManagementTrait {
|
||||
// }
|
||||
// println("============= Printed Sanitized annotations ============")
|
||||
val annotations = sendWhiteboardAnnotations(msg.body.whiteboardId, msg.header.userId, msg.body.annotations, liveMeeting, isUserAmongPresenters, isUserModerator)
|
||||
broadcastEvent(msg, msg.body.whiteboardId, annotations, msg.body.html5InstanceId)
|
||||
broadcastEvent(msg, msg.body.whiteboardId, annotations)
|
||||
} else {
|
||||
//val meetingId = liveMeeting.props.meetingProp.intId
|
||||
//val reason = "No permission to send a whiteboard annotation."
|
||||
|
@ -33,7 +33,7 @@ class WhiteboardApp2x(implicit val context: ActorContext)
|
||||
isModerator: Boolean
|
||||
): Array[AnnotationVO] = {
|
||||
// println("Received whiteboard annotation. status=[" + status + "], annotationType=[" + annotationType + "]")
|
||||
liveMeeting.wbModel.addAnnotations(whiteboardId, requesterId, annotations, isPresenter, isModerator)
|
||||
liveMeeting.wbModel.addAnnotations(whiteboardId, liveMeeting.props.meetingProp.intId, requesterId, annotations, isPresenter, isModerator)
|
||||
}
|
||||
|
||||
def getWhiteboardAnnotations(whiteboardId: String, liveMeeting: LiveMeeting): Array[AnnotationVO] = {
|
||||
@ -49,7 +49,7 @@ class WhiteboardApp2x(implicit val context: ActorContext)
|
||||
isPresenter: Boolean,
|
||||
isModerator: Boolean
|
||||
): Array[String] = {
|
||||
liveMeeting.wbModel.deleteAnnotations(whiteboardId, requesterId, annotationsIds, isPresenter, isModerator)
|
||||
liveMeeting.wbModel.deleteAnnotations(whiteboardId, liveMeeting.props.meetingProp.intId, requesterId, annotationsIds, isPresenter, isModerator)
|
||||
}
|
||||
|
||||
def getWhiteboardAccess(whiteboardId: String, liveMeeting: LiveMeeting): Array[String] = {
|
||||
@ -57,7 +57,7 @@ class WhiteboardApp2x(implicit val context: ActorContext)
|
||||
}
|
||||
|
||||
def modifyWhiteboardAccess(whiteboardId: String, multiUser: Array[String], liveMeeting: LiveMeeting) {
|
||||
liveMeeting.wbModel.modifyWhiteboardAccess(whiteboardId, multiUser)
|
||||
liveMeeting.wbModel.modifyWhiteboardAccess(liveMeeting.props.meetingProp.intId, whiteboardId, multiUser)
|
||||
}
|
||||
|
||||
def filterWhiteboardMessage(whiteboardId: String, userId: String, liveMeeting: LiveMeeting): Boolean = {
|
||||
|
@ -67,7 +67,7 @@ object BreakoutRoomDAO {
|
||||
userId <- room.assignedUsers
|
||||
(redirectToHtml5JoinURL, redirectJoinURL) <- BreakoutHdlrHelpers.getRedirectUrls(liveMeeting, userId, room.externalId, room.sequence.toString())
|
||||
} yield {
|
||||
BreakoutRoomUserDAO.prepareInsert(room.id, userId, redirectToHtml5JoinURL)
|
||||
BreakoutRoomUserDAO.prepareInsert(room.id, liveMeeting.props.meetingProp.intId, userId, redirectToHtml5JoinURL)
|
||||
}
|
||||
).transactionally)
|
||||
.onComplete {
|
||||
|
@ -11,6 +11,7 @@ import scala.util.{Failure, Success}
|
||||
|
||||
case class BreakoutRoomUserDbModel(
|
||||
breakoutRoomId: String,
|
||||
meetingId: String,
|
||||
userId: String,
|
||||
joinURL: String,
|
||||
joinedAt: Option[java.sql.Timestamp],
|
||||
@ -19,19 +20,21 @@ case class BreakoutRoomUserDbModel(
|
||||
|
||||
class BreakoutRoomUserDbTableDef(tag: Tag) extends Table[BreakoutRoomUserDbModel](tag, None, "breakoutRoom_user") {
|
||||
val breakoutRoomId = column[String]("breakoutRoomId", O.PrimaryKey)
|
||||
val meetingId = column[String]("meetingId", O.PrimaryKey)
|
||||
val userId = column[String]("userId", O.PrimaryKey)
|
||||
val joinURL = column[String]("joinURL")
|
||||
val joinedAt = column[Option[java.sql.Timestamp]]("joinedAt")
|
||||
val assignedAt = column[Option[java.sql.Timestamp]]("assignedAt")
|
||||
override def * = (breakoutRoomId, userId, joinURL, joinedAt, assignedAt) <> (BreakoutRoomUserDbModel.tupled, BreakoutRoomUserDbModel.unapply)
|
||||
override def * = (breakoutRoomId, meetingId, userId, joinURL, joinedAt, assignedAt) <> (BreakoutRoomUserDbModel.tupled, BreakoutRoomUserDbModel.unapply)
|
||||
}
|
||||
|
||||
object BreakoutRoomUserDAO {
|
||||
|
||||
def prepareInsert(breakoutRoomId: String, userId: String, joinURL: String) = {
|
||||
def prepareInsert(breakoutRoomId: String, meetingId: String, userId: String, joinURL: String) = {
|
||||
TableQuery[BreakoutRoomUserDbTableDef].insertOrUpdate(
|
||||
BreakoutRoomUserDbModel(
|
||||
breakoutRoomId = breakoutRoomId,
|
||||
meetingId = meetingId,
|
||||
userId = userId,
|
||||
joinURL = joinURL,
|
||||
joinedAt = None,
|
||||
@ -40,8 +43,9 @@ object BreakoutRoomUserDAO {
|
||||
)
|
||||
}
|
||||
|
||||
def prepareDelete(breakoutRoomId: String, userId: String) = {
|
||||
def prepareDelete(breakoutRoomId: String, meetingId: String, userId: String) = {
|
||||
var query = TableQuery[BreakoutRoomUserDbTableDef]
|
||||
.filter(_.meetingId === meetingId)
|
||||
.filter(_.userId === userId)
|
||||
|
||||
//Sometimes the user is moved before he joined in any room, in this case remove all assignments
|
||||
@ -51,10 +55,10 @@ object BreakoutRoomUserDAO {
|
||||
query.delete
|
||||
}
|
||||
|
||||
def updateRoomChanged(userId: String, fromBreakoutRoomId: String, toBreakoutRoomId: String, joinUrl: String) = {
|
||||
def updateRoomChanged(meetingId: String, userId: String, fromBreakoutRoomId: String, toBreakoutRoomId: String, joinUrl: String) = {
|
||||
DatabaseConnection.db.run(DBIO.seq(
|
||||
BreakoutRoomUserDAO.prepareDelete(fromBreakoutRoomId, userId),
|
||||
BreakoutRoomUserDAO.prepareInsert(toBreakoutRoomId, userId, joinUrl)
|
||||
BreakoutRoomUserDAO.prepareDelete(fromBreakoutRoomId, meetingId, userId),
|
||||
BreakoutRoomUserDAO.prepareInsert(toBreakoutRoomId, meetingId, userId, joinUrl)
|
||||
).transactionally)
|
||||
.onComplete {
|
||||
case Success(rowsAffected) => DatabaseConnection.logger.debug(s"$rowsAffected row(s) changed on breakoutRoom_user table!")
|
||||
@ -62,9 +66,10 @@ object BreakoutRoomUserDAO {
|
||||
}
|
||||
}
|
||||
|
||||
def updateUserJoined(usersInRoom: Vector[String], breakoutRoom: BreakoutRoom2x) = {
|
||||
def updateUserJoined(meetingId: String, usersInRoom: Vector[String], breakoutRoom: BreakoutRoom2x) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[BreakoutRoomUserDbTableDef]
|
||||
.filter(_.meetingId === meetingId)
|
||||
.filter(_.userId inSet usersInRoom)
|
||||
.filter(_.breakoutRoomId === breakoutRoom.id)
|
||||
.filter(_.joinedAt.isEmpty)
|
||||
@ -76,9 +81,9 @@ object BreakoutRoomUserDAO {
|
||||
}
|
||||
}
|
||||
|
||||
def updateUserEjected(userId: String, breakoutRoomId: String) = {
|
||||
def updateUserEjected(meetingId: String, userId: String, breakoutRoomId: String) = {
|
||||
DatabaseConnection.db.run(DBIO.seq(
|
||||
BreakoutRoomUserDAO.prepareDelete(userId, breakoutRoomId),
|
||||
BreakoutRoomUserDAO.prepareDelete(meetingId, userId, breakoutRoomId),
|
||||
).transactionally)
|
||||
.onComplete {
|
||||
case Success(rowsAffected) => DatabaseConnection.logger.debug(s"$rowsAffected row(s) deleted on breakoutRoom_user table!")
|
||||
@ -90,7 +95,7 @@ object BreakoutRoomUserDAO {
|
||||
for {
|
||||
(redirectToHtml5JoinURL, redirectJoinURL) <- BreakoutHdlrHelpers.getRedirectUrls(liveMeeting, userId, room.externalId, room.sequence.toString)
|
||||
} yield {
|
||||
DatabaseConnection.db.run(BreakoutRoomUserDAO.prepareInsert(room.id, userId, redirectToHtml5JoinURL))
|
||||
DatabaseConnection.db.run(BreakoutRoomUserDAO.prepareInsert(room.id, liveMeeting.props.meetingProp.intId, userId, redirectToHtml5JoinURL))
|
||||
.onComplete {
|
||||
case Success(rowsAffected) => DatabaseConnection.logger.debug(s"$rowsAffected row(s) inserted on breakoutRoom_user table!")
|
||||
case Failure(e) => DatabaseConnection.logger.debug(s"Error inserting breakoutRoom_user: $e")
|
||||
@ -98,10 +103,11 @@ object BreakoutRoomUserDAO {
|
||||
}
|
||||
}
|
||||
|
||||
// def updateUserJoined(userId: String, breakoutRoomId: String) = {
|
||||
// def updateUserJoined(meetingId: String, userId: String, breakoutRoomId: String) = {
|
||||
// DatabaseConnection.db.run(
|
||||
// TableQuery[BreakoutRoomUserDbTableDef]
|
||||
// .filter(_.breakoutRoomId === breakoutRoomId)
|
||||
// .filter(_.meetingId === meetingId)
|
||||
// .filter(_.userId === userId)
|
||||
// .map(u => u.joinedAt)
|
||||
// .update(Some(new java.sql.Timestamp(System.currentTimeMillis())))
|
||||
|
@ -9,7 +9,7 @@ case class CaptionDbModel(
|
||||
meetingId: String,
|
||||
captionType: String,
|
||||
userId: String,
|
||||
lang: String,
|
||||
locale: String,
|
||||
captionText: String,
|
||||
createdAt: java.sql.Timestamp
|
||||
)
|
||||
@ -19,10 +19,10 @@ class CaptionTableDef(tag: Tag) extends Table[CaptionDbModel](tag, None, "captio
|
||||
val meetingId = column[String]("meetingId")
|
||||
val captionType = column[String]("captionType")
|
||||
val userId = column[String]("userId")
|
||||
val lang = column[String]("lang")
|
||||
val locale = column[String]("locale")
|
||||
val captionText = column[String]("captionText")
|
||||
val createdAt = column[java.sql.Timestamp]("createdAt")
|
||||
def * = (captionId, meetingId, captionType, userId, lang, captionText, createdAt) <> (CaptionDbModel.tupled, CaptionDbModel.unapply)
|
||||
def * = (captionId, meetingId, captionType, userId, locale, captionText, createdAt) <> (CaptionDbModel.tupled, CaptionDbModel.unapply)
|
||||
}
|
||||
|
||||
object CaptionTypes {
|
||||
@ -32,7 +32,7 @@ object CaptionTypes {
|
||||
|
||||
object CaptionDAO {
|
||||
|
||||
def insertOrUpdateAudioCaption(captionId: String, meetingId: String, userId: String, transcript: String, lang: String) = {
|
||||
def insertOrUpdateAudioCaption(captionId: String, meetingId: String, userId: String, transcript: String, locale: String) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[CaptionTableDef].insertOrUpdate(
|
||||
CaptionDbModel(
|
||||
@ -40,7 +40,7 @@ object CaptionDAO {
|
||||
meetingId = meetingId,
|
||||
captionType = CaptionTypes.AUDIO_TRANSCRIPTION,
|
||||
userId = userId,
|
||||
lang = lang,
|
||||
locale = locale,
|
||||
captionText = transcript,
|
||||
createdAt = new java.sql.Timestamp(System.currentTimeMillis())
|
||||
)
|
||||
@ -68,7 +68,7 @@ object CaptionDAO {
|
||||
SELECT "captionId", "captionText", "createdAt"
|
||||
FROM caption
|
||||
WHERE "meetingId" = ${meetingId}
|
||||
AND lang = ${locale}
|
||||
AND locale = ${locale}
|
||||
AND "captionType" = ${CaptionTypes.TYPED}
|
||||
order by "createdAt" desc
|
||||
limit 2
|
||||
@ -80,13 +80,13 @@ object CaptionDAO {
|
||||
LIMIT 1
|
||||
)
|
||||
RETURNING *)
|
||||
INSERT INTO caption ("captionId", "meetingId", "captionType", "userId", "lang", "captionText", "createdAt")
|
||||
INSERT INTO caption ("captionId", "meetingId", "captionType", "userId", "locale", "captionText", "createdAt")
|
||||
SELECT md5(random()::text || clock_timestamp()::text), ${meetingId}, 'TYPED', ${userId}, ${locale}, ${line}, current_timestamp
|
||||
WHERE NOT EXISTS (SELECT * FROM upsert)
|
||||
AND ${line} NOT IN (SELECT "captionText"
|
||||
FROM caption
|
||||
WHERE "meetingId" = ${meetingId}
|
||||
AND lang = ${locale}
|
||||
AND locale = ${locale}
|
||||
AND "captionType" = ${CaptionTypes.TYPED}
|
||||
order by "createdAt" desc
|
||||
limit 2
|
||||
|
41
akka-bbb-apps/src/main/scala/org/bigbluebutton/core/db/CaptionLangDAO.scala
Executable file
41
akka-bbb-apps/src/main/scala/org/bigbluebutton/core/db/CaptionLangDAO.scala
Executable file
@ -0,0 +1,41 @@
|
||||
package org.bigbluebutton.core.db
|
||||
|
||||
import slick.jdbc.PostgresProfile.api._
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.util.{ Failure, Success }
|
||||
|
||||
case class CaptionLocaleDbModel(
|
||||
meetingId: String,
|
||||
locale: String,
|
||||
captionType: String,
|
||||
ownerUserId: String,
|
||||
updatedAt: java.sql.Timestamp
|
||||
)
|
||||
|
||||
class CaptionLocaleTableDef(tag: Tag) extends Table[CaptionLocaleDbModel](tag, None, "caption_locale") {
|
||||
val meetingId = column[String]("meetingId", O.PrimaryKey)
|
||||
val locale = column[String]("locale", O.PrimaryKey)
|
||||
val captionType = column[String]("captionType", O.PrimaryKey)
|
||||
val ownerUserId = column[String]("ownerUserId")
|
||||
val updatedAt = column[java.sql.Timestamp]("updatedAt")
|
||||
def * = (meetingId, locale, captionType, ownerUserId, updatedAt) <> (CaptionLocaleDbModel.tupled, CaptionLocaleDbModel.unapply)
|
||||
}
|
||||
|
||||
object CaptionLocaleDAO {
|
||||
def insertOrUpdateCaptionLocale(meetingId: String, locale: String, captionType: String, ownerUserId: String) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[CaptionLocaleTableDef].insertOrUpdate(
|
||||
CaptionLocaleDbModel(
|
||||
meetingId = meetingId,
|
||||
locale = locale,
|
||||
captionType = captionType,
|
||||
ownerUserId = ownerUserId,
|
||||
updatedAt = new java.sql.Timestamp(System.currentTimeMillis())
|
||||
)
|
||||
)
|
||||
).onComplete {
|
||||
case Success(_) => DatabaseConnection.logger.debug(s"Upserted caption with ID $meetingId-$locale on CaptionLocale table")
|
||||
case Failure(e) => DatabaseConnection.logger.debug(s"Error upserting caption on CaptionLocale: $e")
|
||||
}
|
||||
}
|
||||
}
|
@ -7,6 +7,14 @@ import org.bigbluebutton.core.apps.groupchats.GroupChatApp
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.util.{ Failure, Success }
|
||||
|
||||
case class MeetingSystemColumnsDbModel(
|
||||
loginUrl: Option[String],
|
||||
logoutUrl: Option[String],
|
||||
customLogoUrl: Option[String],
|
||||
bannerText: Option[String],
|
||||
bannerColor: Option[String],
|
||||
)
|
||||
|
||||
case class MeetingDbModel(
|
||||
meetingId: String,
|
||||
extId: String,
|
||||
@ -19,12 +27,11 @@ case class MeetingDbModel(
|
||||
presentationUploadExternalDescription: String,
|
||||
presentationUploadExternalUrl: String,
|
||||
learningDashboardAccessToken: String,
|
||||
logoutUrl: String,
|
||||
customLogoUrl: Option[String],
|
||||
bannerText: Option[String],
|
||||
bannerColor: Option[String],
|
||||
systemColumns: MeetingSystemColumnsDbModel,
|
||||
createdTime: Long,
|
||||
durationInSeconds: Int,
|
||||
endWhenNoModerator: Boolean,
|
||||
endWhenNoModeratorDelayInMinutes: Int,
|
||||
endedAt: Option[java.sql.Timestamp],
|
||||
endedReasonCode: Option[String],
|
||||
endedBy: Option[String],
|
||||
@ -43,12 +50,11 @@ class MeetingDbTableDef(tag: Tag) extends Table[MeetingDbModel](tag, None, "meet
|
||||
presentationUploadExternalDescription,
|
||||
presentationUploadExternalUrl,
|
||||
learningDashboardAccessToken,
|
||||
logoutUrl,
|
||||
customLogoUrl,
|
||||
bannerText,
|
||||
bannerColor,
|
||||
systemColumns,
|
||||
createdTime,
|
||||
durationInSeconds,
|
||||
endWhenNoModerator,
|
||||
endWhenNoModeratorDelayInMinutes,
|
||||
endedAt,
|
||||
endedReasonCode,
|
||||
endedBy
|
||||
@ -64,12 +70,16 @@ class MeetingDbTableDef(tag: Tag) extends Table[MeetingDbModel](tag, None, "meet
|
||||
val presentationUploadExternalDescription = column[String]("presentationUploadExternalDescription")
|
||||
val presentationUploadExternalUrl = column[String]("presentationUploadExternalUrl")
|
||||
val learningDashboardAccessToken = column[String]("learningDashboardAccessToken")
|
||||
val logoutUrl = column[String]("logoutUrl")
|
||||
val loginUrl = column[Option[String]]("loginUrl")
|
||||
val logoutUrl = column[Option[String]]("logoutUrl")
|
||||
val customLogoUrl = column[Option[String]]("customLogoUrl")
|
||||
val bannerText = column[Option[String]]("bannerText")
|
||||
val bannerColor = column[Option[String]]("bannerColor")
|
||||
val systemColumns = (loginUrl, logoutUrl, customLogoUrl, bannerText, bannerColor) <> (MeetingSystemColumnsDbModel.tupled, MeetingSystemColumnsDbModel.unapply)
|
||||
val createdTime = column[Long]("createdTime")
|
||||
val durationInSeconds = column[Int]("durationInSeconds")
|
||||
val endWhenNoModerator = column[Boolean]("endWhenNoModerator")
|
||||
val endWhenNoModeratorDelayInMinutes = column[Int]("endWhenNoModeratorDelayInMinutes")
|
||||
val endedAt = column[Option[java.sql.Timestamp]]("endedAt")
|
||||
val endedReasonCode = column[Option[String]]("endedReasonCode")
|
||||
val endedBy = column[Option[String]]("endedBy")
|
||||
@ -91,21 +101,32 @@ object MeetingDAO {
|
||||
presentationUploadExternalDescription = meetingProps.meetingProp.presentationUploadExternalDescription,
|
||||
presentationUploadExternalUrl = meetingProps.meetingProp.presentationUploadExternalUrl,
|
||||
learningDashboardAccessToken = meetingProps.password.learningDashboardAccessToken,
|
||||
logoutUrl = meetingProps.systemProps.logoutUrl,
|
||||
customLogoUrl = meetingProps.systemProps.customLogoURL match {
|
||||
case "" => None
|
||||
case logoUrl => Some(logoUrl)
|
||||
},
|
||||
bannerText = meetingProps.systemProps.bannerText match {
|
||||
case "" => None
|
||||
case bannerText => Some(bannerText)
|
||||
},
|
||||
bannerColor = meetingProps.systemProps.bannerColor match {
|
||||
case "" => None
|
||||
case bannerColor => Some(bannerColor)
|
||||
},
|
||||
systemColumns = MeetingSystemColumnsDbModel(
|
||||
loginUrl = meetingProps.systemProps.loginUrl match {
|
||||
case "" => None
|
||||
case loginUrl => Some(loginUrl)
|
||||
},
|
||||
logoutUrl = meetingProps.systemProps.logoutUrl match {
|
||||
case "" => None
|
||||
case logoutUrl => Some(logoutUrl)
|
||||
},
|
||||
customLogoUrl = meetingProps.systemProps.customLogoURL match {
|
||||
case "" => None
|
||||
case logoUrl => Some(logoUrl)
|
||||
},
|
||||
bannerText = meetingProps.systemProps.bannerText match {
|
||||
case "" => None
|
||||
case bannerText => Some(bannerText)
|
||||
},
|
||||
bannerColor = meetingProps.systemProps.bannerColor match {
|
||||
case "" => None
|
||||
case bannerColor => Some(bannerColor)
|
||||
},
|
||||
),
|
||||
createdTime = meetingProps.durationProps.createdTime,
|
||||
durationInSeconds = meetingProps.durationProps.duration * 60,
|
||||
endWhenNoModerator = meetingProps.durationProps.endWhenNoModerator,
|
||||
endWhenNoModeratorDelayInMinutes = meetingProps.durationProps.endWhenNoModeratorDelayInMinutes,
|
||||
endedAt = None,
|
||||
endedReasonCode = None,
|
||||
endedBy = None
|
||||
@ -123,7 +144,7 @@ object MeetingDAO {
|
||||
MeetingWelcomeDAO.insert(meetingProps.meetingProp.intId, meetingProps.welcomeProp)
|
||||
MeetingGroupDAO.insert(meetingProps.meetingProp.intId, meetingProps.groups)
|
||||
MeetingBreakoutDAO.insert(meetingProps.meetingProp.intId, meetingProps.breakoutProps)
|
||||
TimerDAO.insert(meetingProps.meetingProp.intId)
|
||||
TimerDAO.insert(meetingProps.meetingProp.intId, clientSettings)
|
||||
LayoutDAO.insert(meetingProps.meetingProp.intId, meetingProps.usersProp.meetingLayout)
|
||||
MeetingClientSettingsDAO.insert(meetingProps.meetingProp.intId, JsonUtils.mapToJson(clientSettings))
|
||||
}
|
||||
@ -182,4 +203,27 @@ object MeetingDAO {
|
||||
case Failure(e) => DatabaseConnection.logger.debug(s"Error updating endedAt=now() Meeting: $e")
|
||||
}
|
||||
}
|
||||
|
||||
def setAllMeetingsEnded(endedReasonCode: String, endedBy: String) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[MeetingDbTableDef]
|
||||
.filter(_.endedAt.isEmpty)
|
||||
.map(a => (a.endedAt, a.endedReasonCode, a.endedBy))
|
||||
.update(
|
||||
(
|
||||
Some(new java.sql.Timestamp(System.currentTimeMillis())),
|
||||
Some(endedReasonCode),
|
||||
endedBy match {
|
||||
case "" => None
|
||||
case c => Some(c)
|
||||
}
|
||||
)
|
||||
)
|
||||
).onComplete {
|
||||
case Success(rowsAffected) => DatabaseConnection.logger.debug(s"$rowsAffected row(s) updated all-meetings endedAt=now() on Meeting table!")
|
||||
case Failure(e) => DatabaseConnection.logger.debug(s"Error updating all-meetings endedAt=now() on Meeting table: $e")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,76 @@
|
||||
package org.bigbluebutton.core.db
|
||||
import org.bigbluebutton.common2.msgs.{BbbCommonEnvCoreMsg, NotifyAllInMeetingEvtMsg, NotifyRoleInMeetingEvtMsg, NotifyUserInMeetingEvtMsg}
|
||||
import PostgresProfile.api._
|
||||
import spray.json.JsValue
|
||||
|
||||
import scala.util.{Failure, Success}
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
|
||||
case class NotificationDbModel(
|
||||
// notificationId: String,
|
||||
meetingId: String,
|
||||
notificationType: String,
|
||||
icon: String,
|
||||
messageId: String,
|
||||
messageDescription: String,
|
||||
messageValues: JsValue,
|
||||
role: Option[String],
|
||||
userMeetingId: Option[String],
|
||||
userId: Option[String],
|
||||
createdAt: java.sql.Timestamp,
|
||||
)
|
||||
|
||||
class NotificationDbTableDef(tag: Tag) extends Table[NotificationDbModel](tag, None, "notification") {
|
||||
val meetingId = column[String]("meetingId")
|
||||
val notificationType = column[String]("notificationType")
|
||||
val icon = column[String]("icon")
|
||||
val messageId = column[String]("messageId")
|
||||
val messageDescription = column[String]("messageDescription")
|
||||
val messageValues = column[JsValue]("messageValues")
|
||||
val role = column[Option[String]]("role")
|
||||
val userMeetingId = column[Option[String]]("userMeetingId")
|
||||
val userId = column[Option[String]]("userId")
|
||||
val createdAt = column[java.sql.Timestamp]("createdAt")
|
||||
override def * = (meetingId, notificationType, icon, messageId, messageDescription, messageValues, role, userMeetingId, userId, createdAt) <> (NotificationDbModel.tupled, NotificationDbModel.unapply)
|
||||
}
|
||||
|
||||
object NotificationDAO {
|
||||
def insert(notification: BbbCommonEnvCoreMsg) = {
|
||||
|
||||
val (meetingId, notificationType, icon, messageId, messageDescription, messageValues, role, userId) = notification.core match {
|
||||
case event: NotifyAllInMeetingEvtMsg =>
|
||||
(event.body.meetingId, event.body.notificationType, event.body.icon, event.body.messageId, event.body.messageDescription, event.body.messageValues, None, None)
|
||||
case event: NotifyRoleInMeetingEvtMsg =>
|
||||
(event.body.meetingId, event.body.notificationType, event.body.icon, event.body.messageId, event.body.messageDescription, event.body.messageValues, Some(event.body.role), None)
|
||||
case event: NotifyUserInMeetingEvtMsg =>
|
||||
(event.body.meetingId, event.body.notificationType, event.body.icon, event.body.messageId, event.body.messageDescription, event.body.messageValues, None, Some(event.body.userId))
|
||||
case _ =>
|
||||
("","", "", "", "", Vector(""), None, None)
|
||||
}
|
||||
|
||||
if (notificationType != "") {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[NotificationDbTableDef].forceInsert(
|
||||
NotificationDbModel(
|
||||
meetingId,
|
||||
notificationType,
|
||||
icon,
|
||||
messageId,
|
||||
messageDescription,
|
||||
JsonUtils.vectorToJson(messageValues),
|
||||
role,
|
||||
userMeetingId = userId match {
|
||||
case Some(u) => Some(meetingId)
|
||||
case _ => None
|
||||
},
|
||||
userId,
|
||||
createdAt = new java.sql.Timestamp(System.currentTimeMillis())
|
||||
)
|
||||
)
|
||||
).onComplete {
|
||||
case Success(rowsAffected) => DatabaseConnection.logger.debug(s"$rowsAffected row(s) inserted/updated on Notification table!")
|
||||
case Failure(e) => DatabaseConnection.logger.debug(s"Error inserting/updating Notification: $e")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -13,11 +13,12 @@ object Permission {
|
||||
val allowedRoles = List("MODERATOR","VIEWER","PRESENTER")
|
||||
}
|
||||
|
||||
case class PluginDataChannelMessageDbModel(
|
||||
case class PluginDataChannelEntryDbModel(
|
||||
meetingId: String,
|
||||
pluginName: String,
|
||||
dataChannel: String,
|
||||
// messageId: Option[String] = None,
|
||||
channelName: String,
|
||||
subChannelName: String,
|
||||
// entryId: Option[String] = None,
|
||||
payloadJson: JsValue,
|
||||
fromUserId: String,
|
||||
toRoles: Option[List[String]],
|
||||
@ -26,28 +27,30 @@ case class PluginDataChannelMessageDbModel(
|
||||
deletedAt: Option[java.sql.Timestamp],
|
||||
)
|
||||
|
||||
class PluginDataChannelMessageDbTableDef(tag: Tag) extends Table[PluginDataChannelMessageDbModel](tag, None, "pluginDataChannelMessage") {
|
||||
class PluginDataChannelEntryDbTableDef(tag: Tag) extends Table[PluginDataChannelEntryDbModel](tag, None, "pluginDataChannelEntry") {
|
||||
val meetingId = column[String]("meetingId", O.PrimaryKey)
|
||||
val pluginName = column[String]("pluginName", O.PrimaryKey)
|
||||
val dataChannel = column[String]("dataChannel", O.PrimaryKey)
|
||||
// val messageId = column[Option[String]]("messageId", O.PrimaryKey) //// The messageId is generated by the database
|
||||
val channelName = column[String]("channelName", O.PrimaryKey)
|
||||
val subChannelName = column[String]("subChannelName")
|
||||
// val entryId = column[Option[String]]("messageId", O.PrimaryKey) //// The messageId is generated by the database
|
||||
val payloadJson = column[JsValue]("payloadJson")
|
||||
val fromUserId = column[String]("fromUserId")
|
||||
val toRoles = column[Option[List[String]]]("toRoles")
|
||||
val toUserIds = column[Option[List[String]]]("toUserIds")
|
||||
val createdAt = column[java.sql.Timestamp]("createdAt")
|
||||
val deletedAt = column[Option[java.sql.Timestamp]]("deletedAt")
|
||||
override def * = (meetingId, pluginName, dataChannel, payloadJson, fromUserId, toRoles, toUserIds, createdAt, deletedAt) <> (PluginDataChannelMessageDbModel.tupled, PluginDataChannelMessageDbModel.unapply)
|
||||
override def * = (meetingId, pluginName, channelName, subChannelName, payloadJson, fromUserId, toRoles, toUserIds, createdAt, deletedAt) <> (PluginDataChannelEntryDbModel.tupled, PluginDataChannelEntryDbModel.unapply)
|
||||
}
|
||||
|
||||
object PluginDataChannelMessageDAO {
|
||||
def insert(meetingId: String, pluginName: String, dataChannel: String, senderUserId: String, payloadJson: String, toRoles: List[String], toUserIds: List[String]) = {
|
||||
object PluginDataChannelEntryDAO {
|
||||
def insert(meetingId: String, pluginName: String, channelName: String, subChannelName: String, senderUserId: String, payloadJson: String, toRoles: List[String], toUserIds: List[String]) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[PluginDataChannelMessageDbTableDef].forceInsert(
|
||||
PluginDataChannelMessageDbModel(
|
||||
TableQuery[PluginDataChannelEntryDbTableDef].forceInsert(
|
||||
PluginDataChannelEntryDbModel(
|
||||
meetingId = meetingId,
|
||||
pluginName = pluginName,
|
||||
dataChannel = dataChannel,
|
||||
channelName = channelName,
|
||||
subChannelName = subChannelName,
|
||||
payloadJson = JsonUtils.stringToJson(payloadJson),
|
||||
fromUserId = senderUserId,
|
||||
toRoles = toRoles.map(_.toUpperCase).filter(Permission.allowedRoles.contains) match {
|
||||
@ -60,54 +63,62 @@ object PluginDataChannelMessageDAO {
|
||||
)
|
||||
)
|
||||
).onComplete {
|
||||
case Success(rowsAffected) => DatabaseConnection.logger.debug(s"$rowsAffected row(s) inserted on PluginDataChannelMessage table!")
|
||||
case Failure(e) => DatabaseConnection.logger.debug(s"Error inserting PluginDataChannelMessage: $e")
|
||||
case Success(rowsAffected) => DatabaseConnection.logger.debug(s"$rowsAffected row(s) inserted on PluginDataChannelEntry table!")
|
||||
case Failure(e) => DatabaseConnection.logger.debug(s"Error inserting PluginDataChannelEntry: $e")
|
||||
}
|
||||
}
|
||||
|
||||
def reset(meetingId: String, pluginName: String, dataChannel: String) = {
|
||||
def reset(meetingId: String, pluginName: String,
|
||||
channelName: String, subChannelName: String) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[PluginDataChannelMessageDbTableDef]
|
||||
TableQuery[PluginDataChannelEntryDbTableDef]
|
||||
.filter(_.meetingId === meetingId)
|
||||
.filter(_.pluginName === pluginName)
|
||||
.filter(_.dataChannel === dataChannel)
|
||||
.filter(_.channelName === channelName)
|
||||
.filter(_.subChannelName === subChannelName)
|
||||
.filter(_.deletedAt.isEmpty)
|
||||
.map(u => (u.deletedAt))
|
||||
.update(Some(new java.sql.Timestamp(System.currentTimeMillis())))
|
||||
).onComplete {
|
||||
case Success(rowsAffected) => DatabaseConnection.logger.debug(s"$rowsAffected row(s) updated deleted=now() on pluginDataChannelMessage table!")
|
||||
case Failure(e) => DatabaseConnection.logger.error(s"Error updating deleted=now() pluginDataChannelMessage: $e")
|
||||
case Success(rowsAffected) => DatabaseConnection.logger.debug(s"$rowsAffected row(s) updated deleted=now() on pluginDataChannelEntry table!")
|
||||
case Failure(e) => DatabaseConnection.logger.error(s"Error updating deleted=now() pluginDataChannelEntry: $e")
|
||||
}
|
||||
}
|
||||
|
||||
def getMessageSender(meetingId: String, pluginName: String, dataChannel: String, messageId: String): String = {
|
||||
def getMessageSender(meetingId: String, pluginName: String, channelName: String,
|
||||
subChannelName: String, entryId: String): String = {
|
||||
val query = sql"""SELECT "fromUserId"
|
||||
FROM "pluginDataChannelMessage"
|
||||
FROM "pluginDataChannelEntry"
|
||||
WHERE "deletedAt" is null
|
||||
AND "meetingId" = ${meetingId}
|
||||
AND "pluginName" = ${pluginName}
|
||||
AND "dataChannel" = ${dataChannel}
|
||||
AND "messageId" = ${messageId}""".as[String].headOption
|
||||
AND "channelName" = ${channelName}
|
||||
AND "subChannelName" = ${subChannelName}
|
||||
AND "entryId" = ${entryId}""".as[String].headOption
|
||||
|
||||
Await.result(DatabaseConnection.db.run(query), Duration.Inf) match {
|
||||
case Some(userId) => userId
|
||||
case None => {
|
||||
logger.debug("Message {} not found in database (maybe it was deleted).", messageId)
|
||||
logger.debug("Message {} not found in database (maybe it was deleted).", entryId)
|
||||
""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def delete(meetingId: String, pluginName: String, dataChannel: String, messageId: String) = {
|
||||
def delete(meetingId: String, pluginName: String,
|
||||
channelName: String, subChannelName: String, entryId: String) = {
|
||||
DatabaseConnection.db.run(
|
||||
sqlu"""UPDATE "pluginDataChannelMessage" SET
|
||||
sqlu"""UPDATE "pluginDataChannelEntry" SET
|
||||
"deletedAt" = current_timestamp
|
||||
WHERE "meetingId" = ${meetingId}
|
||||
WHERE "deletedAt" is null
|
||||
AND "meetingId" = ${meetingId}
|
||||
AND "pluginName" = ${pluginName}
|
||||
AND "dataChannel" = ${dataChannel}
|
||||
AND "messageId" = ${messageId}"""
|
||||
AND "channelName" = ${channelName}
|
||||
AND "subChannelName" = ${subChannelName}
|
||||
AND "entryId" = ${entryId}"""
|
||||
).onComplete {
|
||||
case Success(rowsAffected) => DatabaseConnection.logger.debug(s"$rowsAffected row(s) updated deleted=now() on pluginDataChannelMessage table!")
|
||||
case Failure(e) => DatabaseConnection.logger.debug(s"Error updating deleted=now() pluginDataChannelMessage: $e")
|
||||
case Success(rowsAffected) => DatabaseConnection.logger.debug(s"$rowsAffected row(s) updated deleted=now() on pluginDataChannelEntry table!")
|
||||
case Failure(e) => DatabaseConnection.logger.debug(s"Error updating deleted=now() pluginDataChannelEntry: $e")
|
||||
}
|
||||
}
|
||||
|
@ -8,25 +8,28 @@ import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.util.{ Failure, Success }
|
||||
|
||||
case class PollResponseDbModel(
|
||||
pollId: String,
|
||||
optionId: Option[Int],
|
||||
userId: Option[String]
|
||||
pollId: String,
|
||||
optionId: Option[Int],
|
||||
meetingId: Option[String],
|
||||
userId: Option[String]
|
||||
)
|
||||
|
||||
class PollResponseDbTableDef(tag: Tag) extends Table[PollResponseDbModel](tag, None, "poll_response") {
|
||||
val pollId = column[String]("pollId")
|
||||
val optionId = column[Option[Int]]("optionId")
|
||||
val meetingId = column[Option[String]]("meetingId")
|
||||
val userId = column[Option[String]]("userId")
|
||||
val * = (pollId, optionId, userId) <> (PollResponseDbModel.tupled, PollResponseDbModel.unapply)
|
||||
val * = (pollId, optionId, meetingId, userId) <> (PollResponseDbModel.tupled, PollResponseDbModel.unapply)
|
||||
}
|
||||
|
||||
object PollResponseDAO {
|
||||
def insert(poll: Poll, userId: String, seqOptionIds: Seq[Int]) = {
|
||||
def insert(poll: Poll, meetingId: String, userId: String, seqOptionIds: Seq[Int]) = {
|
||||
|
||||
//Clear previous responses of the user and add all
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[PollResponseDbTableDef]
|
||||
.filter(_.pollId === poll.id)
|
||||
.filter(_.meetingId === meetingId)
|
||||
.filter(_.userId === userId)
|
||||
.delete
|
||||
).onComplete {
|
||||
@ -39,6 +42,9 @@ object PollResponseDAO {
|
||||
PollResponseDbModel(
|
||||
pollId = poll.id,
|
||||
optionId = Some(optionId),
|
||||
meetingId = {
|
||||
if (poll.isSecret) None else Some(meetingId)
|
||||
},
|
||||
userId = {
|
||||
if (poll.isSecret) None else Some(userId)
|
||||
}
|
||||
@ -57,6 +63,7 @@ object PollResponseDAO {
|
||||
PollResponseDbModel(
|
||||
pollId = poll.id,
|
||||
optionId = None,
|
||||
meetingId = Some(meetingId),
|
||||
userId = Some(userId)
|
||||
)
|
||||
)
|
||||
|
@ -3,6 +3,7 @@ package org.bigbluebutton.core.db
|
||||
import com.github.tminglei.slickpg._
|
||||
import org.apache.pekko.http.scaladsl.model.ParsingException
|
||||
import org.bigbluebutton.common2.domain.SimpleVoteOutVO
|
||||
import spray.json.DefaultJsonProtocol.{ StringJsonFormat, vectorFormat }
|
||||
import spray.json.{ JsArray, JsBoolean, JsNumber, JsObject, JsString, JsValue, JsonWriter, _ }
|
||||
|
||||
import scala.util.{ Failure, Success, Try }
|
||||
@ -55,6 +56,10 @@ object JsonUtils {
|
||||
genericMap.toJson
|
||||
}
|
||||
|
||||
def vectorToJson(genericVector: Vector[String]) = {
|
||||
genericVector.toJson
|
||||
}
|
||||
|
||||
def stringToJson(jsonString: String): JsValue = {
|
||||
Try(jsonString.parseJson) match {
|
||||
case Success(jsValue) => jsValue
|
||||
|
@ -1,13 +1,14 @@
|
||||
package org.bigbluebutton.core.db
|
||||
|
||||
import org.bigbluebutton.common2.msgs.AnnotationVO
|
||||
import PostgresProfile.api._
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.util.{ Failure, Success }
|
||||
import slick.jdbc.PostgresProfile.api._
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
|
||||
case class PresAnnotationDbModel(
|
||||
annotationId: String,
|
||||
pageId: String,
|
||||
meetingId: String,
|
||||
userId: String,
|
||||
annotationInfo: String,
|
||||
lastHistorySequence: Int,
|
||||
@ -17,17 +18,18 @@ case class PresAnnotationDbModel(
|
||||
class PresAnnotationDbTableDef(tag: Tag) extends Table[PresAnnotationDbModel](tag, None, "pres_annotation") {
|
||||
val annotationId = column[String]("annotationId", O.PrimaryKey)
|
||||
val pageId = column[String]("pageId")
|
||||
val meetingId = column[String]("meetingId")
|
||||
val userId = column[String]("userId")
|
||||
val annotationInfo = column[String]("annotationInfo")
|
||||
val lastHistorySequence = column[Int]("lastHistorySequence")
|
||||
val lastUpdatedAt = column[java.sql.Timestamp]("lastUpdatedAt")
|
||||
// def whiteboard = foreignKey("whiteboard_fk", whiteboardId, Whiteboards)(_.whiteboardId, onDelete = ForeignKeyAction.Cascade)
|
||||
def * = (annotationId, pageId, userId, annotationInfo, lastHistorySequence, lastUpdatedAt) <> (PresAnnotationDbModel.tupled, PresAnnotationDbModel.unapply)
|
||||
def * = (annotationId, pageId, meetingId, userId, annotationInfo, lastHistorySequence, lastUpdatedAt) <> (PresAnnotationDbModel.tupled, PresAnnotationDbModel.unapply)
|
||||
}
|
||||
|
||||
object PresAnnotationDAO {
|
||||
def insertOrUpdate(annotation: AnnotationVO, annotationDiff: AnnotationVO) = {
|
||||
PresAnnotationHistoryDAO.insert(annotationDiff).onComplete {
|
||||
def insertOrUpdate(meetingId: String, annotation: AnnotationVO, annotationDiff: AnnotationVO) = {
|
||||
PresAnnotationHistoryDAO.insert(meetingId, annotationDiff).onComplete {
|
||||
case Success(sequence) => {
|
||||
DatabaseConnection.logger.debug(s"Sequence generated to PresAnnotationHistory record: $sequence")
|
||||
DatabaseConnection.db.run(
|
||||
@ -35,6 +37,7 @@ object PresAnnotationDAO {
|
||||
PresAnnotationDbModel(
|
||||
annotationId = annotation.id,
|
||||
pageId = annotation.wbId,
|
||||
meetingId = meetingId,
|
||||
userId = annotation.userId,
|
||||
annotationInfo = JsonUtils.mapToJson(annotation.annotationInfo).compactPrint,
|
||||
lastHistorySequence = sequence.getOrElse(0),
|
||||
@ -42,8 +45,8 @@ object PresAnnotationDAO {
|
||||
)
|
||||
)
|
||||
).onComplete {
|
||||
case Success(rowsAffected) => DatabaseConnection.logger.debug(s"$rowsAffected row(s) inserted on PresAnnotation table!")
|
||||
case Failure(e) => DatabaseConnection.logger.debug(s"Error inserting PresAnnotation: $e")
|
||||
case Success(rowsAffected) => DatabaseConnection.logger.debug(s"$rowsAffected row(s) inserted or updated on PresAnnotation table!")
|
||||
case Failure(e) => DatabaseConnection.logger.debug(s"Error inserting or updating PresAnnotation: $e")
|
||||
}
|
||||
|
||||
}
|
||||
@ -51,15 +54,44 @@ object PresAnnotationDAO {
|
||||
}
|
||||
}
|
||||
|
||||
def delete(wbId: String, userId: String, annotationId: String) = {
|
||||
def prepareInsertOrUpdate(meetingId: String, annotation: AnnotationVO) = {
|
||||
TableQuery[PresAnnotationDbTableDef].insertOrUpdate(
|
||||
PresAnnotationDbModel(
|
||||
annotationId = annotation.id,
|
||||
pageId = annotation.wbId,
|
||||
meetingId = meetingId,
|
||||
userId = annotation.userId,
|
||||
annotationInfo = JsonUtils.mapToJson(annotation.annotationInfo).compactPrint,
|
||||
lastHistorySequence = 0,
|
||||
lastUpdatedAt = new java.sql.Timestamp(System.currentTimeMillis())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
PresAnnotationHistoryDAO.delete(wbId, userId, annotationId).onComplete {
|
||||
def insertOrUpdateMap(meetingId: String, annotations: Array[AnnotationVO]) = {
|
||||
DatabaseConnection.db.run(
|
||||
DBIO.sequence(
|
||||
annotations.map { annotation =>
|
||||
prepareInsertOrUpdate(meetingId, annotation)
|
||||
}.toVector
|
||||
).transactionally
|
||||
)
|
||||
.onComplete {
|
||||
case Success(rowsAffected) =>
|
||||
DatabaseConnection.logger.debug(s"${rowsAffected.sum} row(s) inserted or updated on PresAnnotation table!")
|
||||
case Failure(e) =>
|
||||
DatabaseConnection.logger.debug(s"Error inserting or updating PresAnnotation: $e")
|
||||
}
|
||||
}
|
||||
|
||||
def delete(wbId: String, meetingId: String, userId: String, annotationId: String) = {
|
||||
PresAnnotationHistoryDAO.delete(wbId, meetingId, userId, annotationId).onComplete {
|
||||
case Success(sequence) => {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[PresAnnotationDbTableDef]
|
||||
.filter(_.annotationId === annotationId)
|
||||
.map(a => (a.annotationInfo, a.lastHistorySequence, a.lastUpdatedAt))
|
||||
.update("", sequence.getOrElse(0), new java.sql.Timestamp(System.currentTimeMillis()))
|
||||
.map(a => (a.annotationInfo, a.lastHistorySequence, a.meetingId, a.userId, a.lastUpdatedAt))
|
||||
.update("", sequence.getOrElse(0), meetingId, userId, new java.sql.Timestamp(System.currentTimeMillis()))
|
||||
).onComplete {
|
||||
case Success(rowsAffected) => DatabaseConnection.logger.debug(s"$rowsAffected row(s) updated annotationInfo=null on PresAnnotation table!")
|
||||
case Failure(e) => DatabaseConnection.logger.debug(s"Error updating annotationInfo=null PresAnnotation: $e")
|
||||
@ -69,4 +101,16 @@ object PresAnnotationDAO {
|
||||
}
|
||||
}
|
||||
|
||||
def delete(meetingId: String, userId: String, annotationIds: Array[String]) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[PresAnnotationDbTableDef]
|
||||
.filter(_.annotationId inSet annotationIds)
|
||||
.map(a => (a.annotationInfo, a.lastHistorySequence, a.meetingId, a.userId, a.lastUpdatedAt))
|
||||
.update("", 0, meetingId, userId, new java.sql.Timestamp(System.currentTimeMillis()))
|
||||
).onComplete {
|
||||
case Success(rowsAffected) => DatabaseConnection.logger.debug(s"$rowsAffected row(s) updated annotationInfo=null on PresAnnotation table!")
|
||||
case Failure(e) => DatabaseConnection.logger.debug(s"Error updating annotationInfo=null PresAnnotation: $e")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -7,6 +7,7 @@ case class PresAnnotationHistoryDbModel(
|
||||
sequence: Option[Int] = None,
|
||||
annotationId: String,
|
||||
pageId: String,
|
||||
meetingId: String,
|
||||
userId: String,
|
||||
annotationInfo: String
|
||||
// lastUpdatedAt: java.sql.Timestamp = new java.sql.Timestamp(System.currentTimeMillis())
|
||||
@ -16,16 +17,17 @@ class PresAnnotationHistoryDbTableDef(tag: Tag) extends Table[PresAnnotationHist
|
||||
val sequence = column[Option[Int]]("sequence", O.PrimaryKey, O.AutoInc)
|
||||
val annotationId = column[String]("annotationId")
|
||||
val pageId = column[String]("pageId")
|
||||
val meetingId = column[String]("meetingId")
|
||||
val userId = column[String]("userId")
|
||||
val annotationInfo = column[String]("annotationInfo")
|
||||
// val lastUpdatedAt = column[java.sql.Timestamp]("lastUpdatedAt")
|
||||
// def whiteboard = foreignKey("whiteboard_fk", whiteboardId, Whiteboards)(_.whiteboardId, onDelete = ForeignKeyAction.Cascade)
|
||||
def * = (sequence, annotationId, pageId, userId, annotationInfo) <> (PresAnnotationHistoryDbModel.tupled, PresAnnotationHistoryDbModel.unapply)
|
||||
def * = (sequence, annotationId, pageId, meetingId, userId, annotationInfo) <> (PresAnnotationHistoryDbModel.tupled, PresAnnotationHistoryDbModel.unapply)
|
||||
}
|
||||
|
||||
object PresAnnotationHistoryDAO {
|
||||
|
||||
def insert(annotationDiff: AnnotationVO) = {
|
||||
def insert(meetingId: String, annotationDiff: AnnotationVO) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[PresAnnotationHistoryDbTableDef].returning(
|
||||
TableQuery[PresAnnotationHistoryDbTableDef].map(_.sequence)
|
||||
@ -33,13 +35,14 @@ object PresAnnotationHistoryDAO {
|
||||
None,
|
||||
annotationId = annotationDiff.id,
|
||||
pageId = annotationDiff.wbId,
|
||||
meetingId = meetingId,
|
||||
userId = annotationDiff.userId,
|
||||
annotationInfo = JsonUtils.mapToJson(annotationDiff.annotationInfo).compactPrint
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
def delete(wbId: String, userId: String, annotationId: String) = {
|
||||
def delete(wbId: String, meetingId: String, userId: String, annotationId: String) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[PresAnnotationHistoryDbTableDef].returning(
|
||||
TableQuery[PresAnnotationHistoryDbTableDef].map(_.sequence)
|
||||
@ -47,6 +50,7 @@ object PresAnnotationHistoryDAO {
|
||||
None,
|
||||
annotationId = annotationId,
|
||||
pageId = wbId,
|
||||
meetingId = meetingId,
|
||||
userId = userId,
|
||||
annotationInfo = ""
|
||||
)
|
||||
|
@ -8,6 +8,7 @@ import scala.util.{ Failure, Success }
|
||||
|
||||
case class PresPageCursorDbModel(
|
||||
pageId: String,
|
||||
meetingId: String,
|
||||
userId: String,
|
||||
xPercent: Double,
|
||||
yPercent: Double,
|
||||
@ -16,11 +17,11 @@ case class PresPageCursorDbModel(
|
||||
|
||||
class PresPageCursorDbTableDef(tag: Tag) extends Table[PresPageCursorDbModel](tag, None, "pres_page_cursor") {
|
||||
override def * = (
|
||||
pageId, userId, xPercent, yPercent, lastUpdatedAt
|
||||
pageId, meetingId, userId, xPercent, yPercent, lastUpdatedAt
|
||||
) <> (PresPageCursorDbModel.tupled, PresPageCursorDbModel.unapply)
|
||||
def pk = primaryKey("pres_page_cursor_pkey", (pageId, userId))
|
||||
val pageId = column[String]("pageId")
|
||||
val userId = column[String]("userId")
|
||||
val pageId = column[String]("pageId", O.PrimaryKey)
|
||||
val meetingId = column[String]("meetingId", O.PrimaryKey)
|
||||
val userId = column[String]("userId", O.PrimaryKey)
|
||||
val xPercent = column[Double]("xPercent")
|
||||
val yPercent = column[Double]("yPercent")
|
||||
val lastUpdatedAt = column[java.sql.Timestamp]("lastUpdatedAt")
|
||||
@ -28,11 +29,12 @@ class PresPageCursorDbTableDef(tag: Tag) extends Table[PresPageCursorDbModel](ta
|
||||
|
||||
object PresPageCursorDAO {
|
||||
|
||||
def insertOrUpdate(pageId: String, userId: String, xPercent: Double, yPercent: Double) = {
|
||||
def insertOrUpdate(pageId: String, meetingId: String, userId: String, xPercent: Double, yPercent: Double) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[PresPageCursorDbTableDef].insertOrUpdate(
|
||||
PresPageCursorDbModel(
|
||||
pageId = pageId,
|
||||
meetingId = meetingId,
|
||||
userId = userId,
|
||||
xPercent = xPercent,
|
||||
yPercent = yPercent,
|
||||
|
@ -7,34 +7,36 @@ import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.util.{Failure, Success}
|
||||
|
||||
case class PresPageWritersDbModel(
|
||||
pageId: String,
|
||||
userId: String,
|
||||
changedModeOn: Long,
|
||||
pageId: String,
|
||||
meetingId: String,
|
||||
userId: String,
|
||||
changedModeOn: Long,
|
||||
)
|
||||
|
||||
class PresPageWritersDbTableDef(tag: Tag) extends Table[PresPageWritersDbModel](tag, None, "pres_page_writers") {
|
||||
override def * = (
|
||||
pageId, userId, changedModeOn) <> (PresPageWritersDbModel.tupled, PresPageWritersDbModel.unapply)
|
||||
def pk = primaryKey("pres_page_writers_pkey", (pageId, userId))
|
||||
val pageId = column[String]("pageId")
|
||||
val userId = column[String]("userId")
|
||||
pageId, meetingId, userId, changedModeOn) <> (PresPageWritersDbModel.tupled, PresPageWritersDbModel.unapply)
|
||||
val pageId = column[String]("pageId", O.PrimaryKey)
|
||||
val meetingId = column[String]("meetingId", O.PrimaryKey)
|
||||
val userId = column[String]("userId", O.PrimaryKey)
|
||||
val changedModeOn = column[Long]("changedModeOn")
|
||||
}
|
||||
|
||||
object PresPageWritersDAO {
|
||||
|
||||
def updateMultiuser(whiteboard: Whiteboard) = {
|
||||
def updateMultiuser(meetingId: String, whiteboard: Whiteboard) = {
|
||||
|
||||
val deleteQuery = TableQuery[PresPageWritersDbTableDef]
|
||||
.filter(_.pageId === whiteboard.id)
|
||||
|
||||
if(whiteboard.multiUser.length > 0) {
|
||||
deleteQuery.filter(_.meetingId === meetingId)
|
||||
deleteQuery.filterNot(_.userId inSet whiteboard.multiUser)
|
||||
}
|
||||
|
||||
DatabaseConnection.db.run(deleteQuery.delete).onComplete {
|
||||
case Success(rowsAffected) => DatabaseConnection.logger.debug(s"Users deleted from Whiteboard ${whiteboard.id}")
|
||||
case Failure(e) => DatabaseConnection.logger.error(s"Error deleting users from whiteboard: $e")
|
||||
case Success(rowsAffected) => DatabaseConnection.logger.debug(s"Users deleted from pres_page_writers ${whiteboard.id}")
|
||||
case Failure(e) => DatabaseConnection.logger.error(s"Error deleting users from pres_page_writers: $e")
|
||||
}
|
||||
|
||||
for {
|
||||
@ -44,6 +46,7 @@ object PresPageWritersDAO {
|
||||
TableQuery[PresPageWritersDbTableDef].insertOrUpdate(
|
||||
PresPageWritersDbModel(
|
||||
pageId = whiteboard.id,
|
||||
meetingId = meetingId,
|
||||
userId = userId,
|
||||
changedModeOn = whiteboard.changedModeOn
|
||||
)
|
||||
|
@ -35,10 +35,11 @@ object SharedNotesSessionDAO {
|
||||
}
|
||||
}
|
||||
|
||||
def delete(intId: String, sessionId: String) = {
|
||||
def delete(meetingId: String, userId: String, sessionId: String) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[SharedNotesSessionDbTableDef]
|
||||
.filter(_.userId === intId)
|
||||
.filter(_.meetingId === meetingId)
|
||||
.filter(_.userId === userId)
|
||||
.filter(_.sessionId === sessionId)
|
||||
.delete
|
||||
).onComplete {
|
||||
|
@ -1,5 +1,6 @@
|
||||
package org.bigbluebutton.core.db
|
||||
|
||||
import org.bigbluebutton.ClientSettings.{getConfigPropertyValueByPathAsBooleanOrElse, getConfigPropertyValueByPathAsIntOrElse}
|
||||
import org.bigbluebutton.core.apps.TimerModel
|
||||
import org.bigbluebutton.core.apps.TimerModel.{getAccumulated, getEndedAt, getIsActive, getRunning, getStartedAt, getStopwatch, getTime, getTrack}
|
||||
import slick.jdbc.PostgresProfile.api._
|
||||
@ -33,25 +34,31 @@ class TimerDbTableDef(tag: Tag) extends Table[TimerDbModel](tag, None, "timer")
|
||||
}
|
||||
|
||||
object TimerDAO {
|
||||
def insert(meetingId: String) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[TimerDbTableDef].insertOrUpdate(
|
||||
TimerDbModel(
|
||||
meetingId = meetingId,
|
||||
stopwatch = true,
|
||||
running = false,
|
||||
active = false,
|
||||
time = 300000,
|
||||
accumulated = 0,
|
||||
startedOn = 0,
|
||||
endedOn = 0,
|
||||
songTrack = "noTrack",
|
||||
def insert(meetingId: String, clientSettings: Map[String, Object]) = {
|
||||
val timerEnabled = getConfigPropertyValueByPathAsBooleanOrElse(clientSettings, "public.timer.enabled", alternativeValue = true)
|
||||
if(timerEnabled) {
|
||||
val timerDefaultTimeInMinutes = getConfigPropertyValueByPathAsIntOrElse(clientSettings, "public.timer.time", 5)
|
||||
val timerDefaultTimeInMilli = timerDefaultTimeInMinutes * 60000
|
||||
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[TimerDbTableDef].insertOrUpdate(
|
||||
TimerDbModel(
|
||||
meetingId = meetingId,
|
||||
stopwatch = true,
|
||||
running = false,
|
||||
active = false,
|
||||
time = timerDefaultTimeInMilli,
|
||||
accumulated = 0,
|
||||
startedOn = 0,
|
||||
endedOn = 0,
|
||||
songTrack = "noTrack",
|
||||
)
|
||||
)
|
||||
)
|
||||
).onComplete {
|
||||
).onComplete {
|
||||
case Success(rowsAffected) => DatabaseConnection.logger.debug(s"$rowsAffected row(s) inserted on Timer table!")
|
||||
case Failure(e) => DatabaseConnection.logger.debug(s"Error inserting Timer: $e")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def update(meetingId: String, timerModel: TimerModel) = {
|
||||
|
@ -7,17 +7,19 @@ import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.util.{Failure, Success }
|
||||
|
||||
case class UserBreakoutRoomDbModel(
|
||||
breakoutRoomId: String,
|
||||
userId: String,
|
||||
isDefaultName: Boolean,
|
||||
sequence: Int,
|
||||
shortName: String,
|
||||
currentlyInRoom: Boolean,
|
||||
breakoutRoomId: String,
|
||||
meetingId: String,
|
||||
userId: String,
|
||||
isDefaultName: Boolean,
|
||||
sequence: Int,
|
||||
shortName: String,
|
||||
currentlyInRoom: Boolean,
|
||||
)
|
||||
|
||||
class UserBreakoutRoomDbTableDef(tag: Tag) extends Table[UserBreakoutRoomDbModel](tag, None, "user_breakoutRoom") {
|
||||
override def * = (
|
||||
breakoutRoomId, userId, isDefaultName, sequence, shortName, currentlyInRoom) <> (UserBreakoutRoomDbModel.tupled, UserBreakoutRoomDbModel.unapply)
|
||||
breakoutRoomId, meetingId, userId, isDefaultName, sequence, shortName, currentlyInRoom) <> (UserBreakoutRoomDbModel.tupled, UserBreakoutRoomDbModel.unapply)
|
||||
val meetingId = column[String]("meetingId", O.PrimaryKey)
|
||||
val userId = column[String]("userId", O.PrimaryKey)
|
||||
val breakoutRoomId = column[String]("breakoutRoomId")
|
||||
val isDefaultName = column[Boolean]("isDefaultName")
|
||||
@ -28,11 +30,11 @@ class UserBreakoutRoomDbTableDef(tag: Tag) extends Table[UserBreakoutRoomDbModel
|
||||
|
||||
object UserBreakoutRoomDAO {
|
||||
|
||||
def updateLastBreakoutRoom(userId: String, breakoutRoom: BreakoutRoom2x) = {
|
||||
|
||||
def updateLastBreakoutRoom(meetingId: String, userId: String, breakoutRoom: BreakoutRoom2x) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[UserBreakoutRoomDbTableDef].insertOrUpdate(
|
||||
UserBreakoutRoomDbModel(
|
||||
meetingId = meetingId,
|
||||
userId = userId,
|
||||
breakoutRoomId = breakoutRoom.id,
|
||||
isDefaultName = breakoutRoom.isDefaultName,
|
||||
@ -49,10 +51,11 @@ object UserBreakoutRoomDAO {
|
||||
}
|
||||
}
|
||||
|
||||
def updateLastBreakoutRoom(usersInRoom: Vector[String], breakoutRoom: BreakoutRoom2x) = {
|
||||
def updateLastBreakoutRoom(meetingId:String, usersInRoom: Vector[String], breakoutRoom: BreakoutRoom2x) = {
|
||||
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[UserBreakoutRoomDbTableDef]
|
||||
.filter(_.meetingId === meetingId)
|
||||
.filterNot(_.userId inSet usersInRoom)
|
||||
.filter(_.breakoutRoomId === breakoutRoom.id)
|
||||
.map(u_bk => u_bk.currentlyInRoom)
|
||||
@ -68,6 +71,7 @@ object UserBreakoutRoomDAO {
|
||||
} yield {
|
||||
TableQuery[UserBreakoutRoomDbTableDef].insertOrUpdate(
|
||||
UserBreakoutRoomDbModel(
|
||||
meetingId = meetingId,
|
||||
userId = userId,
|
||||
breakoutRoomId = breakoutRoom.id,
|
||||
isDefaultName = breakoutRoom.isDefaultName,
|
||||
|
@ -7,25 +7,28 @@ import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.util.{Failure, Success}
|
||||
|
||||
case class UserCameraDbModel(
|
||||
streamId: String,
|
||||
streamId: String,
|
||||
meetingId: String,
|
||||
userId: String,
|
||||
)
|
||||
|
||||
class UserCameraDbTableDef(tag: Tag) extends Table[UserCameraDbModel](tag, None, "user_camera") {
|
||||
override def * = (
|
||||
streamId, userId) <> (UserCameraDbModel.tupled, UserCameraDbModel.unapply)
|
||||
streamId, meetingId, userId) <> (UserCameraDbModel.tupled, UserCameraDbModel.unapply)
|
||||
val streamId = column[String]("streamId", O.PrimaryKey)
|
||||
val meetingId = column[String]("meetingId")
|
||||
val userId = column[String]("userId")
|
||||
}
|
||||
|
||||
object UserCameraDAO {
|
||||
|
||||
def insert(webcam: WebcamStream) = {
|
||||
def insert(meetingId: String, webcam: WebcamStream) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[UserCameraDbTableDef].forceInsert(
|
||||
UserCameraDbModel(
|
||||
streamId = webcam.streamId,
|
||||
userId = webcam.userId
|
||||
meetingId = meetingId,
|
||||
userId = webcam.userId,
|
||||
)
|
||||
)
|
||||
).onComplete {
|
||||
|
@ -14,7 +14,7 @@ case class UserClientSettingsDbModel(
|
||||
|
||||
class UserClientSettingsDbTableDef(tag: Tag) extends Table[UserClientSettingsDbModel](tag, "user_clientSettings") {
|
||||
val userId = column[String]("userId", O.PrimaryKey)
|
||||
val meetingId = column[String]("meetingId")
|
||||
val meetingId = column[String]("meetingId", O.PrimaryKey)
|
||||
val userClientSettingsJson = column[JsValue]("userClientSettingsJson")
|
||||
|
||||
override def * : ProvenShape[UserClientSettingsDbModel] = (userId, meetingId, userClientSettingsJson) <> (UserClientSettingsDbModel.tupled, UserClientSettingsDbModel.unapply)
|
||||
|
@ -5,22 +5,24 @@ import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.util.{ Failure, Success }
|
||||
|
||||
case class UserConnectionStatusDbModel(
|
||||
userId: String,
|
||||
meetingId: String,
|
||||
connectionAliveAt: Option[java.sql.Timestamp],
|
||||
userClientResponseAt: Option[java.sql.Timestamp],
|
||||
networkRttInMs: Option[Double]
|
||||
userId: String,
|
||||
meetingId: String,
|
||||
connectionAliveAt: Option[java.sql.Timestamp],
|
||||
networkRttInMs: Option[Double],
|
||||
status: String,
|
||||
statusUpdatedAt: Option[java.sql.Timestamp]
|
||||
)
|
||||
|
||||
class UserConnectionStatusDbTableDef(tag: Tag) extends Table[UserConnectionStatusDbModel](tag, None, "user_connectionStatus") {
|
||||
override def * = (
|
||||
userId, meetingId, connectionAliveAt, userClientResponseAt, networkRttInMs
|
||||
userId, meetingId, connectionAliveAt, networkRttInMs, status, statusUpdatedAt
|
||||
) <> (UserConnectionStatusDbModel.tupled, UserConnectionStatusDbModel.unapply)
|
||||
val userId = column[String]("userId", O.PrimaryKey)
|
||||
val meetingId = column[String]("meetingId")
|
||||
val meetingId = column[String]("meetingId", O.PrimaryKey)
|
||||
val connectionAliveAt = column[Option[java.sql.Timestamp]]("connectionAliveAt")
|
||||
val userClientResponseAt = column[Option[java.sql.Timestamp]]("userClientResponseAt")
|
||||
val networkRttInMs = column[Option[Double]]("networkRttInMs")
|
||||
val status = column[String]("status")
|
||||
val statusUpdatedAt = column[Option[java.sql.Timestamp]]("statusUpdatedAt")
|
||||
}
|
||||
|
||||
object UserConnectionStatusDAO {
|
||||
@ -32,8 +34,9 @@ object UserConnectionStatusDAO {
|
||||
userId = userId,
|
||||
meetingId = meetingId,
|
||||
connectionAliveAt = None,
|
||||
userClientResponseAt = None,
|
||||
networkRttInMs = None
|
||||
networkRttInMs = None,
|
||||
status = "normal",
|
||||
statusUpdatedAt = None
|
||||
)
|
||||
)
|
||||
).onComplete {
|
||||
@ -42,28 +45,24 @@ object UserConnectionStatusDAO {
|
||||
}
|
||||
}
|
||||
|
||||
def updateUserAlive(userId: String) = {
|
||||
def updateUserAlive(meetingId: String, userId: String, rtt: Option[Double], status: String) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[UserConnectionStatusDbTableDef]
|
||||
.filter(_.meetingId === meetingId)
|
||||
.filter(_.userId === userId)
|
||||
.map(t => (t.connectionAliveAt))
|
||||
.update(Some(new java.sql.Timestamp(System.currentTimeMillis())))
|
||||
.map(t => (t.connectionAliveAt, t.networkRttInMs, t.status, t.statusUpdatedAt))
|
||||
.update(
|
||||
(
|
||||
Some(new java.sql.Timestamp(System.currentTimeMillis())),
|
||||
rtt,
|
||||
status,
|
||||
Some(new java.sql.Timestamp(System.currentTimeMillis())),
|
||||
)
|
||||
)
|
||||
).onComplete {
|
||||
case Success(rowsAffected) => DatabaseConnection.logger.debug(s"$rowsAffected row(s) updated connectionAliveAt on UserConnectionStatus table!")
|
||||
case Failure(e) => DatabaseConnection.logger.debug(s"Error updating connectionAliveAt on UserConnectionStatus: $e")
|
||||
}
|
||||
}
|
||||
|
||||
def updateUserRtt(userId: String, networkRttInMs: Double) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[UserConnectionStatusDbTableDef]
|
||||
.filter(_.userId === userId)
|
||||
.map(t => (t.networkRttInMs, t.userClientResponseAt))
|
||||
.update((Some(networkRttInMs), Some(new java.sql.Timestamp(System.currentTimeMillis()))))
|
||||
).onComplete {
|
||||
case Success(rowsAffected) => DatabaseConnection.logger.debug(s"$rowsAffected row(s) updated networkRttInMs on UserConnectionStatus table!")
|
||||
case Failure(e) => DatabaseConnection.logger.debug(s"Error updating networkRttInMs on UserConnectionStatus: $e")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,27 +7,30 @@ import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.util.{ Failure, Success }
|
||||
|
||||
case class UserCustomParameterDbModel(
|
||||
meetingId: String,
|
||||
userId: String,
|
||||
parameter: String,
|
||||
value: String
|
||||
)
|
||||
|
||||
class UserCustomParameterDbTableDef(tag: Tag) extends Table[UserCustomParameterDbModel](tag, "user_customParameter") {
|
||||
val meetingId = column[String]("meetingId", O.PrimaryKey)
|
||||
val userId = column[String]("userId", O.PrimaryKey)
|
||||
val parameter = column[String]("parameter", O.PrimaryKey)
|
||||
val value = column[String]("value")
|
||||
|
||||
override def * : ProvenShape[UserCustomParameterDbModel] = (userId, parameter, value) <> (UserCustomParameterDbModel.tupled, UserCustomParameterDbModel.unapply)
|
||||
override def * : ProvenShape[UserCustomParameterDbModel] = (meetingId, userId, parameter, value) <> (UserCustomParameterDbModel.tupled, UserCustomParameterDbModel.unapply)
|
||||
}
|
||||
|
||||
object UserCustomParameterDAO {
|
||||
def insert(userId: String, customParameters: Map[String, String]) = {
|
||||
def insert(meetingId: String, userId: String, customParameters: Map[String, String]) = {
|
||||
DatabaseConnection.db.run(DBIO.sequence(
|
||||
for {
|
||||
parameter <- customParameters
|
||||
} yield {
|
||||
TableQuery[UserCustomParameterDbTableDef].insertOrUpdate(
|
||||
UserCustomParameterDbModel(
|
||||
meetingId = meetingId,
|
||||
userId = userId,
|
||||
parameter = parameter._1,
|
||||
value = parameter._2
|
||||
|
@ -6,9 +6,9 @@ import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.util.{Failure, Success}
|
||||
|
||||
case class UserDbModel(
|
||||
meetingId: String,
|
||||
userId: String,
|
||||
extId: String,
|
||||
meetingId: String,
|
||||
name: String,
|
||||
role: String,
|
||||
avatar: String = "",
|
||||
@ -32,10 +32,11 @@ case class UserDbModel(
|
||||
|
||||
class UserDbTableDef(tag: Tag) extends Table[UserDbModel](tag, None, "user") {
|
||||
override def * = (
|
||||
userId,extId,meetingId,name,role,avatar,color, sessionToken, authToken, authed,joined,joinErrorCode, joinErrorMessage, banned,loggedOut,guest,guestStatus,registeredOn,excludeFromDashboard, enforceLayout) <> (UserDbModel.tupled, UserDbModel.unapply)
|
||||
meetingId,userId,extId,name,role,avatar,color, sessionToken, authToken, authed,joined,joinErrorCode,
|
||||
joinErrorMessage, banned,loggedOut,guest,guestStatus,registeredOn,excludeFromDashboard, enforceLayout) <> (UserDbModel.tupled, UserDbModel.unapply)
|
||||
val meetingId = column[String]("meetingId", O.PrimaryKey)
|
||||
val userId = column[String]("userId", O.PrimaryKey)
|
||||
val extId = column[String]("extId")
|
||||
val meetingId = column[String]("meetingId")
|
||||
val name = column[String]("name")
|
||||
val role = column[String]("role")
|
||||
val avatar = column[String]("avatar")
|
||||
@ -89,7 +90,7 @@ object UserDAO {
|
||||
case Success(rowsAffected) => {
|
||||
DatabaseConnection.logger.debug(s"$rowsAffected row(s) inserted in User table!")
|
||||
UserConnectionStatusDAO.insert(meetingId, regUser.id)
|
||||
UserCustomParameterDAO.insert(regUser.id, regUser.customParameters)
|
||||
UserCustomParameterDAO.insert(meetingId, regUser.id, regUser.customParameters)
|
||||
UserClientSettingsDAO.insert(regUser.id, meetingId)
|
||||
ChatUserDAO.insertUserPublicChat(meetingId, regUser.id)
|
||||
}
|
||||
@ -100,6 +101,7 @@ object UserDAO {
|
||||
def update(regUser: RegisteredUser) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[UserDbTableDef]
|
||||
.filter(_.meetingId === regUser.meetingId)
|
||||
.filter(_.userId === regUser.id)
|
||||
.map(u => (u.guest, u.guestStatus, u.role, u.authed, u.joined, u.banned, u.loggedOut))
|
||||
.update((regUser.guest, regUser.guestStatus, regUser.role, regUser.authed, regUser.joined, regUser.banned, regUser.loggedOut))
|
||||
@ -113,18 +115,20 @@ object UserDAO {
|
||||
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[UserDbTableDef]
|
||||
.filter(_.meetingId === voiceUserState.meetingId)
|
||||
.filter(_.userId === voiceUserState.intId)
|
||||
.map(u => (u.guest, u.guestStatus, u.authed, u.joined))
|
||||
.update((false, "ALLOW", true, true))
|
||||
).onComplete {
|
||||
case Success(rowsAffected) => DatabaseConnection.logger.debug(s"$rowsAffected row(s) updated on user voice table!")
|
||||
case Failure(e) => DatabaseConnection.logger.debug(s"Error updating user voice: $e")
|
||||
case Success(rowsAffected) => DatabaseConnection.logger.debug(s"$rowsAffected row(s) updated on user table!")
|
||||
case Failure(e) => DatabaseConnection.logger.debug(s"Error updating user table: $e")
|
||||
}
|
||||
}
|
||||
|
||||
def updateJoinError(userId: String, joinErrorCode: String, joinErrorMessage: String) = {
|
||||
def updateJoinError(meetingId: String, userId: String, joinErrorCode: String, joinErrorMessage: String) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[UserDbTableDef]
|
||||
.filter(_.meetingId === meetingId)
|
||||
.filter(_.userId === userId)
|
||||
.map(u => (u.joined, u.joinErrorCode, u.joinErrorMessage))
|
||||
.update((false, Some(joinErrorCode), Some(joinErrorMessage)))
|
||||
@ -134,11 +138,11 @@ object UserDAO {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def softDelete(intId: String) = {
|
||||
def softDelete(meetingId: String, userId: String) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[UserDbTableDef]
|
||||
.filter(_.userId === intId)
|
||||
.filter(_.meetingId === meetingId)
|
||||
.filter(_.userId === userId)
|
||||
.map(u => (u.loggedOut))
|
||||
.update((true))
|
||||
).onComplete {
|
||||
@ -159,6 +163,62 @@ object UserDAO {
|
||||
}
|
||||
}
|
||||
|
||||
def transferUserToBreakoutRoomAsAudioOnly(userId: String, meetingIdFrom: String, meetingIdTo: String) = {
|
||||
|
||||
//Create a copy of the user using the same userId, but with the meetingId of the breakoutRoom
|
||||
//The user will be flagged by `transferredFromParentMeeting=true`
|
||||
DatabaseConnection.db.run(
|
||||
sqlu"""
|
||||
WITH upsert AS (
|
||||
UPDATE "user"
|
||||
SET "loggedOut"=false
|
||||
where "userId" = ${userId}
|
||||
and "meetingId" = ${meetingIdTo}
|
||||
RETURNING *)
|
||||
insert into "user"("meetingId","userId","extId","name","role","guest","authed","guestStatus","locked",
|
||||
"color","loggedOut","expired","ejected","joined","registeredOn","transferredFromParentMeeting","clientType")
|
||||
select
|
||||
${meetingIdTo} as "meetingId",
|
||||
"userId",
|
||||
"extId",
|
||||
"name",
|
||||
"role",
|
||||
true as "guest",
|
||||
true as "authed",
|
||||
'ALLOW' as "guestStatus",
|
||||
false as "locked",
|
||||
"color",
|
||||
"loggedOut",
|
||||
"expired",
|
||||
"ejected",
|
||||
"joined",
|
||||
"registeredOn",
|
||||
true as "transferredFromParentMeeting",
|
||||
'dial-in-user' as "clientType"
|
||||
from "user"
|
||||
where "userId" = ${userId}
|
||||
and "meetingId" = ${meetingIdFrom}
|
||||
and NOT EXISTS (SELECT * FROM upsert)
|
||||
"""
|
||||
).onComplete {
|
||||
case Success(rowsAffected) => DatabaseConnection.logger.debug(s"$rowsAffected row(s) inserted in user (transferredFromParentMeeting) table")
|
||||
case Failure(e) => DatabaseConnection.logger.error(s"Error inserting user (transferredFromParentMeeting): $e")
|
||||
}
|
||||
|
||||
//Set user as loggedOut in the old meeting (if it is from transferred origin)
|
||||
DatabaseConnection.db.run(
|
||||
sqlu"""update "user"
|
||||
set "loggedOut" = true
|
||||
where "userId" = ${userId}
|
||||
and "meetingId" = ${meetingIdFrom}
|
||||
and "transferredFromParentMeeting" is true
|
||||
"""
|
||||
).onComplete {
|
||||
case Success(rowsAffected) => DatabaseConnection.logger.debug(s"$rowsAffected row(s) updated in user (transferredFromParentMeeting) table")
|
||||
case Failure(e) => DatabaseConnection.logger.error(s"Error updating user (transferredFromParentMeeting): $e")
|
||||
}
|
||||
}
|
||||
|
||||
def permanentlyDeleteAllFromMeeting(meetingId: String) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[UserDbTableDef]
|
||||
|
@ -7,6 +7,7 @@ import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.util.{ Failure, Success }
|
||||
|
||||
case class UserReactionDbModel(
|
||||
meetingId: String,
|
||||
userId: String,
|
||||
reactionEmoji: String,
|
||||
durationInSeconds: Int,
|
||||
@ -14,19 +15,21 @@ case class UserReactionDbModel(
|
||||
)
|
||||
|
||||
class UserReactionDbTableDef(tag: Tag) extends Table[UserReactionDbModel](tag, "user_reaction") {
|
||||
val meetingId = column[String]("meetingId")
|
||||
val userId = column[String]("userId")
|
||||
val reactionEmoji = column[String]("reactionEmoji")
|
||||
val durationInSeconds = column[Int]("durationInSeconds")
|
||||
val createdAt = column[java.sql.Timestamp]("createdAt")
|
||||
|
||||
override def * : ProvenShape[UserReactionDbModel] = (userId, reactionEmoji, durationInSeconds, createdAt) <> (UserReactionDbModel.tupled, UserReactionDbModel.unapply)
|
||||
override def * : ProvenShape[UserReactionDbModel] = (meetingId, userId, reactionEmoji, durationInSeconds, createdAt) <> (UserReactionDbModel.tupled, UserReactionDbModel.unapply)
|
||||
}
|
||||
|
||||
object UserReactionDAO {
|
||||
def insert(userId: String, reactionEmoji: String, durationInSeconds: Int) = {
|
||||
def insert(meetingId: String, userId: String, reactionEmoji: String, durationInSeconds: Int) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[UserReactionDbTableDef].forceInsert(
|
||||
UserReactionDbModel(
|
||||
meetingId = meetingId,
|
||||
userId = userId,
|
||||
reactionEmoji = reactionEmoji,
|
||||
durationInSeconds = durationInSeconds,
|
||||
|
@ -7,30 +7,36 @@ import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.util.{Failure, Success}
|
||||
|
||||
case class UserStateDbModel(
|
||||
userId: String,
|
||||
emoji: String = "none",
|
||||
away: Boolean = false,
|
||||
raiseHand: Boolean = false,
|
||||
guestStatus: String,
|
||||
guestStatusSetByModerator: Option[String],
|
||||
guestLobbyMessage: Option[String],
|
||||
mobile: Boolean,
|
||||
clientType: String,
|
||||
disconnected: Boolean = false,
|
||||
expired: Boolean = false,
|
||||
ejected: Boolean = false,
|
||||
ejectReason: Option[String],
|
||||
ejectReasonCode: Option[String],
|
||||
ejectedByModerator: Option[String],
|
||||
presenter: Boolean = false,
|
||||
pinned: Boolean = false,
|
||||
locked: Boolean = false,
|
||||
speechLocale: String,
|
||||
meetingId: String,
|
||||
userId: String,
|
||||
emoji: String = "none",
|
||||
away: Boolean = false,
|
||||
raiseHand: Boolean = false,
|
||||
guestStatus: String,
|
||||
guestStatusSetByModerator: Option[String],
|
||||
guestLobbyMessage: Option[String],
|
||||
mobile: Boolean,
|
||||
clientType: String,
|
||||
disconnected: Boolean = false,
|
||||
expired: Boolean = false,
|
||||
ejected: Boolean = false,
|
||||
ejectReason: Option[String],
|
||||
ejectReasonCode: Option[String],
|
||||
ejectedByModerator: Option[String],
|
||||
presenter: Boolean = false,
|
||||
pinned: Boolean = false,
|
||||
locked: Boolean = false,
|
||||
speechLocale: String,
|
||||
inactivityWarningDisplay: Boolean = false,
|
||||
inactivityWarningTimeoutSecs: Option[Long],
|
||||
)
|
||||
|
||||
class UserStateDbTableDef(tag: Tag) extends Table[UserStateDbModel](tag, None, "user") {
|
||||
override def * = (
|
||||
userId,emoji,away,raiseHand,guestStatus,guestStatusSetByModerator,guestLobbyMessage,mobile,clientType,disconnected,expired,ejected,ejectReason,ejectReasonCode,ejectedByModerator,presenter,pinned,locked,speechLocale) <> (UserStateDbModel.tupled, UserStateDbModel.unapply)
|
||||
meetingId, userId,emoji,away,raiseHand,guestStatus,guestStatusSetByModerator,guestLobbyMessage,mobile,clientType,disconnected,
|
||||
expired,ejected,ejectReason,ejectReasonCode,ejectedByModerator,presenter,pinned,locked,speechLocale,
|
||||
inactivityWarningDisplay, inactivityWarningTimeoutSecs) <> (UserStateDbModel.tupled, UserStateDbModel.unapply)
|
||||
val meetingId = column[String]("meetingId", O.PrimaryKey)
|
||||
val userId = column[String]("userId", O.PrimaryKey)
|
||||
val emoji = column[String]("emoji")
|
||||
val away = column[Boolean]("away")
|
||||
@ -50,12 +56,15 @@ class UserStateDbTableDef(tag: Tag) extends Table[UserStateDbModel](tag, None, "
|
||||
val pinned = column[Boolean]("pinned")
|
||||
val locked = column[Boolean]("locked")
|
||||
val speechLocale = column[String]("speechLocale")
|
||||
val inactivityWarningDisplay = column[Boolean]("inactivityWarningDisplay")
|
||||
val inactivityWarningTimeoutSecs = column[Option[Long]]("inactivityWarningTimeoutSecs")
|
||||
}
|
||||
|
||||
object UserStateDAO {
|
||||
def update(userState: UserState) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[UserStateDbTableDef]
|
||||
.filter(_.meetingId === userState.meetingId)
|
||||
.filter(_.userId === userState.intId)
|
||||
.map(u => (u.presenter, u.pinned, u.locked, u.speechLocale, u.emoji, u.away, u.raiseHand, u.mobile, u.clientType, u.disconnected))
|
||||
.update((userState.presenter, userState.pin, userState.locked, userState.speechLocale, userState.emoji, userState.away, userState.raiseHand, userState.mobile, userState.clientType, userState.userLeftFlag.left))
|
||||
@ -65,9 +74,10 @@ object UserStateDAO {
|
||||
}
|
||||
}
|
||||
|
||||
def updateEjected(userId: String, ejectReason: String, ejectReasonCode: String, ejectedByModerator: String) = {
|
||||
def updateEjected(meetingId: String, userId: String, ejectReason: String, ejectReasonCode: String, ejectedByModerator: String) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[UserStateDbTableDef]
|
||||
.filter(_.meetingId === meetingId)
|
||||
.filter(_.userId === userId)
|
||||
.map(u => (u.ejected, u.ejectReason, u.ejectReasonCode, u.ejectedByModerator))
|
||||
.update((true, Some(ejectReason), Some(ejectReasonCode), Some(ejectedByModerator)))
|
||||
@ -77,10 +87,11 @@ object UserStateDAO {
|
||||
}
|
||||
}
|
||||
|
||||
def updateExpired(intId: String, expired: Boolean) = {
|
||||
def updateExpired(meetingId: String, userId: String, expired: Boolean) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[UserStateDbTableDef]
|
||||
.filter(_.userId === intId)
|
||||
.filter(_.meetingId === meetingId)
|
||||
.filter(_.userId === userId)
|
||||
.map(u => (u.expired))
|
||||
.update((expired))
|
||||
).onComplete {
|
||||
@ -89,10 +100,11 @@ object UserStateDAO {
|
||||
}
|
||||
}
|
||||
|
||||
def updateGuestStatus(intId: String, guestStatus: String, guestStatusSetByModerator: String) = {
|
||||
def updateGuestStatus(meetingId: String, userId: String, guestStatus: String, guestStatusSetByModerator: String) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[UserStateDbTableDef]
|
||||
.filter(_.userId === intId)
|
||||
.filter(_.meetingId === meetingId)
|
||||
.filter(_.userId === userId)
|
||||
.map(u => (u.guestStatus, u.guestStatusSetByModerator))
|
||||
.update((guestStatus,
|
||||
guestStatusSetByModerator match {
|
||||
@ -107,10 +119,11 @@ object UserStateDAO {
|
||||
}
|
||||
}
|
||||
|
||||
def updateGuestLobbyMessage(intId: String, guestLobbyMessage: String) = {
|
||||
def updateGuestLobbyMessage(meetingId: String, userId: String, guestLobbyMessage: String) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[UserStateDbTableDef]
|
||||
.filter(_.userId === intId)
|
||||
.filter(_.meetingId === meetingId)
|
||||
.filter(_.userId === userId)
|
||||
.map(u => u.guestLobbyMessage)
|
||||
.update(Some(guestLobbyMessage))
|
||||
).onComplete {
|
||||
@ -119,4 +132,22 @@ object UserStateDAO {
|
||||
}
|
||||
}
|
||||
|
||||
def updateInactivityWarning(meetingId: String, userId: String, inactivityWarningDisplay: Boolean, inactivityWarningTimeoutSecs: Long) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[UserStateDbTableDef]
|
||||
.filter(_.meetingId === meetingId)
|
||||
.filter(_.userId === userId)
|
||||
.map(u => (u.inactivityWarningDisplay, u.inactivityWarningTimeoutSecs))
|
||||
.update((inactivityWarningDisplay,
|
||||
inactivityWarningTimeoutSecs match {
|
||||
case 0 => None
|
||||
case timeout: Long => Some(timeout)
|
||||
case _ => None
|
||||
}))
|
||||
).onComplete {
|
||||
case Success(rowsAffected) => DatabaseConnection.logger.debug(s"$rowsAffected row(s) updated inactivityWarningDisplay on user table!")
|
||||
case Failure(e) => DatabaseConnection.logger.error(s"Error updating inactivityWarningDisplay user: $e")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,46 @@
|
||||
package org.bigbluebutton.core.db
|
||||
|
||||
import org.bigbluebutton.core.models.{ VoiceUserState }
|
||||
import slick.jdbc.PostgresProfile.api._
|
||||
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.util.{ Failure, Success }
|
||||
|
||||
case class UserTranscriptionErrorDbModel(
|
||||
meetingId: String,
|
||||
userId: String,
|
||||
errorCode: String,
|
||||
errorMessage: String,
|
||||
lastUpdatedAt: java.sql.Timestamp = new java.sql.Timestamp(System.currentTimeMillis())
|
||||
)
|
||||
|
||||
class UserTranscriptionErrorDbTableDef(tag: Tag) extends Table[UserTranscriptionErrorDbModel](tag, None, "user_transcriptionError") {
|
||||
override def * = (
|
||||
meetingId, userId, errorCode, errorMessage, lastUpdatedAt
|
||||
) <> (UserTranscriptionErrorDbModel.tupled, UserTranscriptionErrorDbModel.unapply)
|
||||
val meetingId = column[String]("meetingId", O.PrimaryKey)
|
||||
val userId = column[String]("userId", O.PrimaryKey)
|
||||
val errorCode = column[String]("errorCode")
|
||||
val errorMessage = column[String]("errorMessage")
|
||||
val lastUpdatedAt = column[java.sql.Timestamp]("lastUpdatedAt")
|
||||
}
|
||||
|
||||
object UserTranscriptionErrorDAO {
|
||||
def insert(userId: String, meetingId: String, errorCode: String, errorMessage: String) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[UserTranscriptionErrorDbTableDef].insertOrUpdate(
|
||||
UserTranscriptionErrorDbModel(
|
||||
meetingId = meetingId,
|
||||
userId = userId,
|
||||
errorCode = errorCode,
|
||||
errorMessage = errorMessage,
|
||||
lastUpdatedAt = new java.sql.Timestamp(System.currentTimeMillis()),
|
||||
)
|
||||
)
|
||||
).onComplete {
|
||||
case Success(rowsAffected) => DatabaseConnection.logger.debug(s"$rowsAffected row(s) inserted on user_transcriptionError table!")
|
||||
case Failure(e) => DatabaseConnection.logger.debug(s"Error inserting user_transcriptionError: $e")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -7,6 +7,7 @@ import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.util.{Failure, Success }
|
||||
|
||||
case class UserVoiceConfStateDbModel(
|
||||
meetingId: String,
|
||||
userId: String,
|
||||
voiceConf: String,
|
||||
voiceConfCallSession: String,
|
||||
@ -16,8 +17,9 @@ case class UserVoiceConfStateDbModel(
|
||||
|
||||
class UserVoiceConfStateDbTableDef(tag: Tag) extends Table[UserVoiceConfStateDbModel](tag, None, "user_voice") {
|
||||
override def * = (
|
||||
userId, voiceConf, voiceConfCallSession, voiceConfClientSession, voiceConfCallState
|
||||
meetingId, userId, voiceConf, voiceConfCallSession, voiceConfClientSession, voiceConfCallState
|
||||
) <> (UserVoiceConfStateDbModel.tupled, UserVoiceConfStateDbModel.unapply)
|
||||
val meetingId = column[String]("meetingId", O.PrimaryKey)
|
||||
val userId = column[String]("userId", O.PrimaryKey)
|
||||
val voiceConf = column[String]("voiceConf")
|
||||
val voiceConfCallSession = column[String]("voiceConfCallSession")
|
||||
@ -26,10 +28,11 @@ class UserVoiceConfStateDbTableDef(tag: Tag) extends Table[UserVoiceConfStateDbM
|
||||
}
|
||||
|
||||
object UserVoiceConfStateDAO {
|
||||
def insertOrUpdate(userId: String, voiceConf: String, voiceConfCallSession: String, clientSession: String, callState: String) = {
|
||||
def insertOrUpdate(meetingId: String, userId: String, voiceConf: String, voiceConfCallSession: String, clientSession: String, callState: String) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[UserVoiceConfStateDbTableDef].insertOrUpdate(
|
||||
UserVoiceConfStateDbModel(
|
||||
meetingId = meetingId,
|
||||
userId = userId,
|
||||
voiceConf = voiceConf,
|
||||
voiceConfCallSession = voiceConfCallSession,
|
||||
@ -38,9 +41,7 @@ object UserVoiceConfStateDAO {
|
||||
)
|
||||
)
|
||||
).onComplete {
|
||||
case Success(rowsAffected) => {
|
||||
DatabaseConnection.logger.debug(s"$rowsAffected row(s) inserted on user_voice table!")
|
||||
}
|
||||
case Success(rowsAffected) => DatabaseConnection.logger.debug(s"$rowsAffected row(s) inserted on user_voice table!")
|
||||
case Failure(e) => DatabaseConnection.logger.debug(s"Error inserting voice: $e")
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.util.{Failure, Success }
|
||||
|
||||
case class UserVoiceDbModel(
|
||||
meetingId: String,
|
||||
userId: String,
|
||||
voiceUserId: String,
|
||||
callerName: String,
|
||||
@ -25,9 +26,10 @@ case class UserVoiceDbModel(
|
||||
|
||||
class UserVoiceDbTableDef(tag: Tag) extends Table[UserVoiceDbModel](tag, None, "user_voice") {
|
||||
override def * = (
|
||||
userId, voiceUserId, callerName, callerNum, callingWith, joined, listenOnly,
|
||||
meetingId, userId, voiceUserId, callerName, callerNum, callingWith, joined, listenOnly,
|
||||
muted, spoke, talking, floor, lastFloorTime, startTime, endTime
|
||||
) <> (UserVoiceDbModel.tupled, UserVoiceDbModel.unapply)
|
||||
val meetingId = column[String]("meetingId", O.PrimaryKey)
|
||||
val userId = column[String]("userId", O.PrimaryKey)
|
||||
val voiceUserId = column[String]("voiceUserId")
|
||||
val callerName = column[String]("callerName")
|
||||
@ -54,6 +56,7 @@ object UserVoiceDAO {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[UserVoiceDbTableDef].insertOrUpdate(
|
||||
UserVoiceDbModel(
|
||||
meetingId = voiceUserState.meetingId,
|
||||
userId = voiceUserState.intId,
|
||||
voiceUserId = voiceUserState.voiceUserId,
|
||||
callerName = voiceUserState.callerName,
|
||||
@ -99,13 +102,15 @@ object UserVoiceDAO {
|
||||
"spoke" = true,
|
||||
"endTime" = null,
|
||||
"startTime" = (case when "talking" is false then $now else "startTime" end)
|
||||
WHERE "userId" = ${voiceUserState.intId}"""
|
||||
WHERE "meetingId" = ${voiceUserState.meetingId}
|
||||
AND "userId" = ${voiceUserState.intId}"""
|
||||
} else {
|
||||
sqlu"""UPDATE user_voice SET
|
||||
"talking" = false,
|
||||
"startTime" = null,
|
||||
"endTime" = (case when "talking" is true then $now else "endTime" end)
|
||||
WHERE "userId" = ${voiceUserState.intId}"""
|
||||
WHERE "meetingId" = ${voiceUserState.meetingId}
|
||||
AND "userId" = ${voiceUserState.intId}"""
|
||||
}
|
||||
|
||||
DatabaseConnection.db.run(updateSql).onComplete {
|
||||
@ -114,10 +119,11 @@ object UserVoiceDAO {
|
||||
}
|
||||
}
|
||||
|
||||
def delete(intId: String) = {
|
||||
def delete(meetingId: String, userId: String) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[UserDbTableDef]
|
||||
.filter(_.userId === intId)
|
||||
.filter(_.meetingId === meetingId)
|
||||
.filter(_.userId === userId)
|
||||
.map(u => (u.loggedOut))
|
||||
.update((true))
|
||||
).onComplete {
|
||||
@ -126,7 +132,7 @@ object UserVoiceDAO {
|
||||
}
|
||||
}
|
||||
|
||||
def deleteUserVoice(userId: String) = {
|
||||
def deleteUserVoice(meetingId: String,userId: String) = {
|
||||
//Meteor sets this props instead of removing
|
||||
// muted: false
|
||||
// talking: false
|
||||
@ -136,6 +142,7 @@ object UserVoiceDAO {
|
||||
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[UserVoiceDbTableDef]
|
||||
.filter(_.meetingId === meetingId)
|
||||
.filter(_.userId === userId)
|
||||
.map(u => (u.muted, u.talking, u.listenOnly, u.joined, u.spoke, u.startTime, u.endTime))
|
||||
.update((false, false, false, false, false, None, None))
|
||||
|
@ -1,60 +0,0 @@
|
||||
package org.bigbluebutton.core.db
|
||||
|
||||
import org.bigbluebutton.core.apps.whiteboard.Whiteboard
|
||||
import slick.jdbc.PostgresProfile.api._
|
||||
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.util.{Failure, Success}
|
||||
|
||||
case class UserWhiteboardDbModel(
|
||||
whiteboardId: String,
|
||||
userId: String,
|
||||
changedModeOn: Long,
|
||||
)
|
||||
|
||||
class UserWhiteboardDbTableDef(tag: Tag) extends Table[UserWhiteboardDbModel](tag, None, "user_whiteboard") {
|
||||
override def * = (
|
||||
whiteboardId, userId, changedModeOn) <> (UserWhiteboardDbModel.tupled, UserWhiteboardDbModel.unapply)
|
||||
def pk = primaryKey("user_whiteboard_pkey", (whiteboardId, userId))
|
||||
val whiteboardId = column[String]("whiteboardId")
|
||||
val userId = column[String]("userId")
|
||||
val changedModeOn = column[Long]("changedModeOn")
|
||||
}
|
||||
|
||||
object UserWhiteboardDAO {
|
||||
|
||||
def updateMultiuser(whiteboard: Whiteboard) = {
|
||||
|
||||
val deleteQuery = TableQuery[UserWhiteboardDbTableDef]
|
||||
.filter(_.whiteboardId === whiteboard.id)
|
||||
|
||||
if(whiteboard.multiUser.length > 0) {
|
||||
deleteQuery.filterNot(_.userId inSet whiteboard.multiUser)
|
||||
}
|
||||
|
||||
DatabaseConnection.db.run(deleteQuery.delete).onComplete {
|
||||
case Success(rowsAffected) => DatabaseConnection.logger.debug(s"Users deleted from Whiteboard ${whiteboard.id}")
|
||||
case Failure(e) => DatabaseConnection.logger.error(s"Error deleting users from whiteboard: $e")
|
||||
}
|
||||
|
||||
for {
|
||||
userId <- whiteboard.multiUser
|
||||
} yield {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[UserWhiteboardDbTableDef].insertOrUpdate(
|
||||
UserWhiteboardDbModel(
|
||||
whiteboardId = whiteboard.id,
|
||||
userId = userId,
|
||||
changedModeOn = whiteboard.changedModeOn
|
||||
)
|
||||
)
|
||||
).onComplete {
|
||||
case Success(rowsAffected) => {
|
||||
DatabaseConnection.logger.debug(s"$rowsAffected row(s) inserted on user_whiteboard table!")
|
||||
}
|
||||
case Failure(e) => DatabaseConnection.logger.error(s"Error inserting user_whiteboard: $e")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -42,4 +42,5 @@ object MeetingEndReason {
|
||||
val BREAKOUT_ENDED_BY_MOD = "BREAKOUT_ENDED_BY_MOD"
|
||||
val ENDED_DUE_TO_NO_AUTHED_USER = "ENDED_DUE_TO_NO_AUTHED_USER"
|
||||
val ENDED_DUE_TO_NO_MODERATOR = "ENDED_DUE_TO_NO_MODERATOR"
|
||||
val ENDED_DUE_TO_SERVICE_INTERRUPTION = "ENDED_DUE_TO_SERVICE_INTERRUPTION"
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user