Compare commits

..

615 Commits

Author SHA1 Message Date
snyk-bot
dffea814d4
fix: record-and-playback/core/Gemfile & record-and-playback/core/Gemfile.lock to reduce vulnerabilities
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-RUBY-REXML-7814166
2024-08-24 07:09:56 +00:00
Daniel Petri Rocha
6f08344a70
fix: Breakout rooms show incorrect presentation filename (#20947)
* Pass arbitrary filename

* Use shortname as presName in breakout room

* Show selected filename in the room
2024-08-22 13:24:19 -03:00
Paulo Lanzarin
1484f516d0
Merge pull request #20998 from bigbluebutton/bbb27sfu2142
[2.7] build(bbb-webrtc-sfu): v2.14.2
2024-08-21 19:56:47 -03:00
Paulo Lanzarin
8be32a7bf3
build(bbb-webrtc-sfu): v2.14.2
v2.14.2
---
* refactor(audio): set FLOWING logs to INFO level
* build(mediasoup): v3.14.11
2024-08-21 16:18:16 -03:00
Gabriel Luiz Porfirio
f66f07d177
test: Backport share camera as content test to 2.7 (#20964)
* backport camera as content test

* add test to ci
2024-08-21 14:56:39 -03:00
Gabriel Luiz Porfirio
7a8abd0127
backport disable self-view test (#20982) 2024-08-21 14:56:21 -03:00
Gabriel Luiz Porfirio
3dd588d704
test: Backporting timer/stopwatch test to 2.7 (#20954)
* backporting timer test

* adding test on ci
2024-08-21 14:56:06 -03:00
Gabriel Luiz Porfirio
ff0b2f33b6
test: removing temporally external video test from ci (#20955)
* removing external video test from ci, adds @flaky flag
2024-08-20 13:36:57 -03:00
Paulo Lanzarin
7371aa6c18
Merge pull request #20921 from prlanzarin/u27/fix/tlo-unhold-unmute-delay
fix(audio): change unmute/unhold flow to work around FS unmute stutter
2024-08-15 12:37:29 -03:00
Anton Barboza de Sá
36b5a16c15
docs: Testing plan update (what's new features) (#20913)
* docs: update test links on release notes and spec files

* docs: add tests for 'what's new on 2.7' features

* Update docs/docs/testing/release-testing.md

Co-authored-by: Anton Georgiev <antobinary@users.noreply.github.com>

* test: pass the bbb version in the doc links

---------

Co-authored-by: Anton Georgiev <antobinary@users.noreply.github.com>
2024-08-14 09:50:03 -04:00
Anton Georgiev
562a13f527
chore: update link to which locales are supported by Gladia (#20925) 2024-08-13 13:44:20 -04:00
prlanzarin
cf6202c572 fix(audio): change unmute/unhold flow to work around FS unmute stutter
FS has an intermittent issue where unmuting a HELD channel sometimes
takes significantly (seconds) longer than usual.
conference <XYZ> unmute <WVU> simply gets stuck with no FS_API response,
which delays the unmute action whenever transparent listen only is
active.

Apparently, unholding the channel PRIOR TO unmuting works around the
issue - at least it could not be reproduced with the scenario at hand.
The unmute API already triggered an unhold in FS internally, which is
the reason why this was not done beforehand. The aforementioned issue is
way worse than an extra "redudant" API call, though.

Always unhold audio channels manually _before_ unmuting.
2024-08-13 13:18:22 -03:00
prlanzarin
e6e1f28036 feat(audio): channel threshold for transparent listen only activation
Transparent listen only is currently only worth it for meetings with a
number of duplex audio channels larger than a certain value (dependant
on system performance). That is due to the fact that global audio
bridges created for the mechanism also use significant CPU (roughly the
same as an unheld duplex channel), which means it's cost is usually
offset only once there are enough potential channels to be held in a
conference.

This commit adds a new optional feature that introduces some dynamicity
for the mechanism: it'll only be triggered after at least
@voiceConf.transparentListenOnlyThreshold number of muted duplex
audio channels are present in a conference.
The default is 0 (always trigger transparent listen only if the general
mechanism is activated).
2024-08-13 13:18:21 -03:00
transifex-integration[bot]
b4a11facd4
Translate en.json in ja (#20903)
100% translated source file: 'en.json'
on 'ja'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-08-12 13:02:12 -04:00
Anton Georgiev
ea7867340f
fix: docs/package.json & docs/package-lock.json to reduce vulnerabilities (#20900)
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JS-INFLIGHT-6095116

Co-authored-by: snyk-bot <snyk-bot@snyk.io>
2024-08-12 13:01:51 -04:00
transifex-integration[bot]
07c0433ba0
Translate en.json in pt_BR (#20881)
100% translated source file: 'en.json'
on 'pt_BR'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-08-09 11:16:59 -04:00
Anton Georgiev
a642391caf
docs: added a link to 2.7.12 2024-08-07 16:46:41 -04:00
Daniel Petri Rocha
656cdb44cf
fix(bbb-export-annotations): Handle text rendering issue (#20857)
* Handle error when imagemagick fails to render

* Update bbb-export-annotations/workers/process.js

Co-authored-by: Anton Georgiev <antobinary@users.noreply.github.com>

* Update bbb-export-annotations/workers/process.js

Co-authored-by: Anton Georgiev <antobinary@users.noreply.github.com>

* Add more detailed logs

---------

Co-authored-by: Anton Georgiev <antobinary@users.noreply.github.com>
2024-08-06 16:21:45 -04:00
transifex-integration[bot]
352f3ebd58
Translate en.json in tr (#20854)
100% translated source file: 'en.json'
on 'tr'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-08-06 13:03:22 -04:00
transifex-integration[bot]
565a8bfcd4
Translate en.json in et (#20865)
100% translated source file: 'en.json'
on 'et'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-08-06 13:00:14 -04:00
Anton Georgiev
cf966e396b
chore: Bump release to 2.7.12 2024-08-02 19:31:05 -04:00
KDSBrowne
466e328477
fix: Ensure size estimate is applied to text shapes while typing (#20809)
* ensure size estimate is applied to text shape while typing

* add comment and comma
2024-08-02 18:47:39 -04:00
Paulo Lanzarin
06d1a74cdc
Merge pull request #20849 from prlanzarin/u27/fix/video-preview-borked-did
fix(video): webcam fails to be loaded on preview when changing profiles
2024-08-02 16:25:28 -03:00
prlanzarin
2c6de02f1c fix(video): webcam fails to be loaded on preview when changing profiles
There's an issue where permission-less sessions of video-preview
fail to change video profiles. Whenever gUM is on prompt mode,
deviceIds are obfuscated, which means getInitialCamera will need to
infer the deviceId based on the current media stream.
Since the virtual bg worker is now called synchronously (e28a595),
it'll be extracted incorrectly from the virtual effect MediaStream
(rather  than the original stream) - which causes getInitialCamera to
use the effect's deviceId rather than the original stream's deviceId.

Guarantee that deviceId inference via MediaStreamTrack uses
BBBVideoStream's originalStream (so that virtual effect streams are
bypassed). Also remove the call to updateDeviceId in getInitialCamera
since it's redundant since commit e28a595.
2024-08-02 13:23:11 -03:00
Ramón Souza
d4ee755a2d
Merge pull request #20831 from JoVictorNunes/fix-slide-snapshot-overflowing-27
fix(presentation): presentation snapshot overflowing the slide [2.7]
2024-08-02 10:02:36 -03:00
Anton Georgiev
3eb3e345af
docs: fix name of errorRedirectUrl in api docs (#20839) 2024-08-01 16:27:58 -04:00
Anton Georgiev
ca18587289
docs: remove extra entry for webcamBackgroundURL (#20838) 2024-08-01 16:27:43 -04:00
Paulo Lanzarin
f85bc7f976
Merge pull request #20832 from prlanzarin/u27/fix/broken-present-camera
fix(video): camera cannot be shared as content
2024-08-01 15:09:30 -03:00
prlanzarin
6ec1272a2b fix(video): camera cannot be shared as content
A change in e28a595b52 introduced an issue where the "Share camera as
content" modal always has it's "share" action flagged as disabled. This
is due to a short-circuit introduced in the initial gUM procedure that
does not clear the "disabled" state before exiting.

Properly reset the "disabled" sharing state after the initial gUM in
video-preview when "Share camera as content" is used, thus fixing the
aforementioned issue.
2024-08-01 14:33:52 -03:00
Paulo Lanzarin
894515ddb6
Merge pull request #20829 from bigbluebutton/u27sfu2141
build(bbb-webrtc-sfu): v2.14.1
2024-08-01 12:43:07 -03:00
João Victor
450a36d244 fix(presentation): presentation snapshot overflowing the slide 2024-08-01 12:21:38 -03:00
Paulo Lanzarin
3282f230a9
build(bbb-webrtc-sfu): v2.14.1
v2.14.1
---
* fix(screenshare): presenter/viewer stop logs on all scenarios
* refactor(screenshare): add presenter data to viewer logs
* refactor(video): add video negotiation and flowing logs
* build(mediasoup): 3.14.9
2024-08-01 12:02:54 -03:00
Anton Georgiev
20d4944ce6
Merge pull request #20752 from prlanzarin/u27/fix/tlo-br-ralam-sfu2140
fix(audio): transparent listen only state inconsistencies, build(bbb-webrtc-sfu): v2.14.0
2024-08-01 10:13:41 -04:00
transifex-integration[bot]
80780ddde1
Updates for project BigBlueButton v2.7 HTML5 client and language ar (#20827)
* Translate en.json in ar

100% translated source file: 'en.json'
on 'ar'.

* Translate en.json in ar

100% translated source file: 'en.json'
on 'ar'.

---------

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-08-01 09:47:04 -04:00
Ramón Souza
31ac4e7b52
Merge pull request #20798 from KDSBrowne/bbb-20621
fix: Improve screen reader accessibility for polling modal
2024-07-31 14:40:19 -03:00
transifex-integration[bot]
0ea1d8894f
Translate en.json in fa_IR (#20808)
100% translated source file: 'en.json'
on 'fa_IR'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-07-31 09:12:41 -04:00
transifex-integration[bot]
dc11f2977b
Translate en.json in eu (#20791)
100% translated source file: 'en.json'
on 'eu'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-07-30 13:53:44 -04:00
transifex-integration[bot]
8287fe04d7
Translate en.json in fa_IR (#20792)
100% translated source file: 'en.json'
on 'fa_IR'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-07-30 13:53:24 -04:00
Anton Georgiev
4f193ba67a
docs: added link to 2.7.10 2024-07-30 11:31:27 -04:00
Anton Georgiev
7274fd90da
chore: Bump release to 2.7.11 2024-07-30 11:28:42 -04:00
Gustavo Trott
c441b8531a
fix: Dial-in -- add missing webcamBackground prop for dial-in users (#20799) 2024-07-30 11:27:40 -04:00
Anton Georgiev
99d1262ff1
refactor: enable warn logs; add a warning when we are skipping an annotation (#20786) 2024-07-30 09:30:25 -04:00
KDSBrowne
59deebdbcb update poll vote modal with header element for additional screen reader access 2024-07-30 13:04:57 +00:00
Ramón Souza
1e2731ef63
Merge pull request #20788 from JoVictorNunes/virtual-bg-enhancements-0726
enhancement(webcam): custom virtual backgrounds
2024-07-29 10:41:35 -03:00
João Victor
565f8a14c7 test: Update virtual background thumbnail image 2024-07-29 08:56:51 -03:00
transifex-integration[bot]
6cd9d0513e
Translate en.json in it_IT (#20790)
100% translated source file: 'en.json'
on 'it_IT'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-07-26 16:18:28 -04:00
João Victor
e28a595b52 enhancement(webcam): custom virtual backgrounds 2024-07-26 16:48:17 -03:00
João Victor Nunes
027115aa14
fix(webcam): client failing to apply virtual background effect (#20777)
* fix(webcam): client failing to apply virtual background effect

* fix: check for already dispatched background

* fix: make webcam start up with last selected virtual background
2024-07-25 15:49:32 -04:00
Fred Dixon
e1eabefc56
Update install.md
Fixed reference to starting greenlight (no '\b' needed)
2024-07-25 06:53:15 -03:00
Anton Georgiev
c35580ece4
Update new-features.md 2024-07-24 21:41:20 -04:00
Anton Georgiev
3b8e7e1968
Merge pull request #20774 from antobinary/docs-2710
docs: 2.7.10 features breakouts with own pres; ban posts from user
2024-07-24 21:23:46 -04:00
Anton Georgiev
06c5a2eece docs: 2.7.10 features breakouts with own pres; ban posts from user 2024-07-24 21:20:35 -04:00
Anton Georgiev
290b03e35f
Merge pull request #20773 from bigbluebutton/dependabot/npm_and_yarn/bbb-learning-dashboard/npm_and_yarn-5c1bc6e16d
build(deps-dev): bump postcss from 8.4.33 to 8.4.34 in /bbb-learning-dashboard in the npm_and_yarn group across 1 directory
2024-07-24 18:27:17 -04:00
dependabot[bot]
4f9ca0e7a3
build(deps-dev): bump postcss
Bumps the npm_and_yarn group with 1 update in the /bbb-learning-dashboard directory: [postcss](https://github.com/postcss/postcss).


Updates `postcss` from 8.4.33 to 8.4.34
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.4.33...8.4.34)

---
updated-dependencies:
- dependency-name: postcss
  dependency-type: direct:development
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-24 22:03:22 +00:00
Anton Georgiev
d0c28c84ec
Merge pull request #20772 from bigbluebutton/dependabot/npm_and_yarn/bbb-learning-dashboard/npm_and_yarn-985204e52f
build(deps-dev): bump postcss from 8.4.32 to 8.4.33 in /bbb-learning-dashboard in the npm_and_yarn group across 1 directory
2024-07-24 17:59:53 -04:00
dependabot[bot]
2c20dc3329
build(deps-dev): bump postcss
Bumps the npm_and_yarn group with 1 update in the /bbb-learning-dashboard directory: [postcss](https://github.com/postcss/postcss).


Updates `postcss` from 8.4.32 to 8.4.33
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.4.32...8.4.33)

---
updated-dependencies:
- dependency-name: postcss
  dependency-type: direct:development
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-24 20:18:03 +00:00
Anton Georgiev
2beb822cbe
Merge pull request #20771 from bigbluebutton/dependabot/npm_and_yarn/bbb-learning-dashboard/npm_and_yarn-f05eb9a4c1
build(deps): bump the npm_and_yarn group across 5 directories with 6 updates
2024-07-24 16:13:55 -04:00
dependabot[bot]
91b39664f9
build(deps): bump the npm_and_yarn group across 5 directories with 6 updates
Bumps the npm_and_yarn group with 1 update in the /bbb-learning-dashboard directory: [postcss](https://github.com/postcss/postcss).
Bumps the npm_and_yarn group with 2 updates in the /bigbluebutton-html5 directory: [postcss](https://github.com/postcss/postcss) and [braces](https://github.com/micromatch/braces).
Bumps the npm_and_yarn group with 1 update in the /bigbluebutton-tests/playwright directory: [follow-redirects](https://github.com/follow-redirects/follow-redirects).
Bumps the npm_and_yarn group with 2 updates in the /bigbluebutton-tests/puppeteer directory: [braces](https://github.com/micromatch/braces) and [follow-redirects](https://github.com/follow-redirects/follow-redirects).
Bumps the npm_and_yarn group with 6 updates in the /docs directory:

| Package | From | To |
| --- | --- | --- |
| [postcss](https://github.com/postcss/postcss) | `8.4.32` | `8.4.40` |
| [braces](https://github.com/micromatch/braces) | `3.0.2` | `3.0.3` |
| [express](https://github.com/expressjs/express) | `4.18.2` | `4.19.2` |
| [follow-redirects](https://github.com/follow-redirects/follow-redirects) | `1.15.3` | `1.15.6` |
| [webpack-dev-middleware](https://github.com/webpack/webpack-dev-middleware) | `5.3.3` | `5.3.4` |
| [ws](https://github.com/websockets/ws) | `7.5.9` | `7.5.10` |



Updates `postcss` from 8.4.31 to 8.4.32
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.4.31...8.4.32)

Updates `postcss` from 8.4.31 to 8.4.40
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.4.31...8.4.32)

Updates `braces` from 3.0.2 to 3.0.3
- [Changelog](https://github.com/micromatch/braces/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/braces/compare/3.0.2...3.0.3)

Updates `follow-redirects` from 1.15.4 to 1.15.6
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.4...v1.15.6)

Updates `braces` from 3.0.2 to 3.0.3
- [Changelog](https://github.com/micromatch/braces/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/braces/compare/3.0.2...3.0.3)

Updates `follow-redirects` from 1.15.4 to 1.15.6
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.4...v1.15.6)

Updates `postcss` from 8.4.32 to 8.4.40
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.4.31...8.4.32)

Updates `braces` from 3.0.2 to 3.0.3
- [Changelog](https://github.com/micromatch/braces/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/braces/compare/3.0.2...3.0.3)

Updates `express` from 4.18.2 to 4.19.2
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/master/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.18.2...4.19.2)

Updates `follow-redirects` from 1.15.3 to 1.15.6
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.4...v1.15.6)

Updates `webpack-dev-middleware` from 5.3.3 to 5.3.4
- [Release notes](https://github.com/webpack/webpack-dev-middleware/releases)
- [Changelog](https://github.com/webpack/webpack-dev-middleware/blob/v5.3.4/CHANGELOG.md)
- [Commits](https://github.com/webpack/webpack-dev-middleware/compare/v5.3.3...v5.3.4)

Updates `ws` from 7.5.9 to 7.5.10
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/7.5.9...7.5.10)

---
updated-dependencies:
- dependency-name: postcss
  dependency-type: direct:development
  dependency-group: npm_and_yarn
- dependency-name: postcss
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: braces
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: follow-redirects
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: braces
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: follow-redirects
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: postcss
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: braces
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: express
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: follow-redirects
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: webpack-dev-middleware
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: ws
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-24 19:48:05 +00:00
Anton Georgiev
8b0175e67b
chore(core): upgrade embedded tomcat (#20767) 2024-07-24 15:41:41 -04:00
Anton Georgiev
5f26293cb2
chore(core): Update grails-plugin-databinding (#20768) 2024-07-24 15:41:25 -04:00
Ramón Souza
d9cf1a07d9
feat(config): introduce allowPresentationManagementInBreakouts to be able to block breakouts pres uploads (#20769)
* introduce allowUploadNewDocsInBreakouts in settings.yml

* rename property

* change default value and property name
2024-07-24 15:36:29 -04:00
Ramón Souza
9d3b6f0b6c
do not display presentation dropdown on breakout update (#20764) 2024-07-24 13:37:44 -04:00
transifex-integration[bot]
31336c8290
Translate en.json in el_GR (#20762)
100% translated source file: 'en.json'
on 'el_GR'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-07-24 09:17:31 -04:00
transifex-integration[bot]
fff955b211
Translate en.json in ar (#20761)
100% translated source file: 'en.json'
on 'ar'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-07-24 09:16:40 -04:00
Anton Georgiev
5387fef101
Merge pull request #20703 from danielpetri1/webcam-background-url
feat: Accept custom webcamBackgroundURL
2024-07-23 15:55:56 -04:00
Anton Georgiev
b248143cae
Merge pull request #20734 from danielpetri1/pass-breakout-pres
feat: Pass a different presentation to each breakout
2024-07-23 11:52:07 -04:00
prlanzarin
437c684423 fix(audio): stuck unmute due to borked callerId(Num)
FreeSWITCH incorrectly generates callerNum headers in its ESL events
when specific, special characters are in place. e.g.:
w_etc_0-bbbID-User;Semi (notice the semicolon) will be generated by
FS as w_etc_0-bbbID-User (everything after the semicolon is ignored).
This breaks callerId comparision for session matching in a few places -
one of the is the unmute/unhold toggle control.

Compare callerNum as prefixes instead of exact strings to match those
scenarios.
This is a temporary fix; we should review callerNum generation in the
future (use Caller-Id-Name in FSESL), as well as stop relying on it
for session matching (use UUIDs and/or client session numbers instead).
Both of these are more involved changes, though.
2024-07-23 09:37:19 -03:00
prlanzarin
6918d4e090 build(bbb-webrtc-sfu): v2.14.0
v2.14.0
---
* feat(mediasoup): add least-loaded worker balancing strategy
* feat(mediasoup): worker transposition (off by default)
* feat(audio): dynamic global audio bridge mechanism
* feat: livekit module, initial implementation
* feat(audio): add signaling support for passive-sendrecv role
* feat(freeswitch): overridable UA string
* feat(audio): muteOnStart detection for conditional dialplans
* feat(audio): mute passive-sendrecv clients on start
* feat(audio): support for mute-and-hold on start
* fix(audio): ignore TLO-incapable clients in hold/unhold metrics
* fix(audio): mute/unmute stuck due to inconsistent hold status
* fix(audio): hold/unhold loop when there are multiple sessions per user
* fix(audio): muteOnStart sessions incorrectly muted on breakout transfers
* fix(audio): header-provided userName incorrectly decoded
* fix(audio): stuck unmute due to borked callerIdNum
* fix(audio): correctly decode user name space chars
* !build(npm): set min Node.js version to >=18.0.0
* build: nodemon@3.1.3
* build: ws@8.17.1
* build(mediasoup): 3.14.8
2024-07-23 09:23:50 -03:00
prlanzarin
1c57db94bb fix(audio): always send unhold
Alway send the unhold command since it doesn't change flip the state
(contrary to the uuid_hold toggle command).

It's not idempotent, though - so always update the internal hold state
to prevent state mismatches preventing channels from being unheld.
2024-07-23 09:23:05 -03:00
prlanzarin
631d5186e5 feat(audio): add memberId to VoiceStateEvent when applicable
We need the voiceUserId (memberId) in IN_CONFERENCE callState events so
that the SFU can bypass dialplan-level mute states when transferring
between breakout rooms.

Add memberId to VoiceCallStateEvent when applicable. For CHANNEL_STATE
events that do not carry it (RINGING, HANGUP), memberId is an empty
string.
2024-07-23 09:22:50 -03:00
prlanzarin
d3e2d3965c fix(audio): do not send FSESL hold cmd if already on hold
This is an edge case with the uuid_hold command being used through
FSESL or fsapi where holding only works via the uuid_hold <toggle>
subcommand, which may cause the channel to be the opposite of what
we want.

Do not execute if the command is asking for the channel to be HELD
and the channel is already HELD.
2024-07-23 09:22:40 -03:00
prlanzarin
025942de5b fix(audio): only enforce hold on mute state mismatch if !muted
There's a routine that's supposed to enforce the channel hold state if
mute and hold states are mismatched. This should only happen in case the
user is unmuted and the channel is held to avoid leaving an user without
inbound or outbound audio by accident. The routine currently checks for
the oppositve scenario as well (muted=true,hold=false), which should not
be enforced because of special scenarios (e.g.: audio-only breakout room
transfers, which have their transparent LO mechanism disabled).

Only enforce hold on muted state mismatch IF muted == false.
2024-07-23 09:22:23 -03:00
prlanzarin
623c90b19f fix(audio): add callerNum to transparent listen only RPCs
There are some scenarios where transparent listen only toggle RPCs are
directed to multiple different sessions in the SFU, which might cause a
hold-unhold loop because they're all anchored to the userId.

Append the callerNum to transparent listen only toggle RPCs so that they
are directed to the appropriate audio sessions in all cases.
2024-07-23 09:20:57 -03:00
Daniel Petri Rocha
4ccc883437 Replace green screen with blank screen, add CORS policy 2024-07-23 10:28:23 +00:00
Daniel Petri Rocha
3648748ce0
Merge pull request #15 from ramonlsouza/pr-20734
pass presentation to breakout - frontend
2024-07-22 16:43:58 +02:00
Guilherme Pereira Leme
baa62ab1ef
fix(bbb-web and html5): removed .odi and .odc file-type supports (back-port) (#20738)
* [backport-20729] just backported and added information to the docs

* [backport-20729] better description

* [backport-20729] prettier documentation on file formats

Co-authored-by: Gustavo Trott <gustavo@trott.com.br>

---------

Co-authored-by: Gustavo Trott <gustavo@trott.com.br>
2024-07-19 14:58:24 -04:00
Anton Georgiev
9377121704
chore: Bump release to 2.7.10 2024-07-19 14:34:14 -04:00
Ramón Souza
7fbf51054b pass presentation to breakout - frontend 2024-07-19 09:53:31 -03:00
Daniel Petri Rocha
8b6cdc6edf Initial implementation to let slides be passed in the backend 2024-07-18 16:37:02 +00:00
transifex-integration[bot]
f390049fea
Translate en.json in ar (#20721)
100% translated source file: 'en.json'
on 'ar'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-07-18 08:57:23 -04:00
transifex-integration[bot]
610f9a2650
Translate en.json in el_GR (#20719)
100% translated source file: 'en.json'
on 'el_GR'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-07-17 15:55:32 -04:00
André Castro
4c6e0289d4
Fix: [2.7] Breakout room invitation option missing from user dropdown (#20691)
* Fix: [2.7] Breakout room invitation option missing from user dropdown

* removing unnecessary code

* Translation key re-name

* modal Change
2024-07-17 14:39:09 -03:00
Daniel Petri Rocha
fa0ad14c35
feat(bbb-html5): Ban specific users from the public chat (#20585)
* Initial user lock changes

* Show lock icon
2024-07-17 12:56:33 -04:00
Daniel Petri Rocha
2317d2f98f
Update docs/docs/data/join.tsx
Co-authored-by: Anton Georgiev <antobinary@users.noreply.github.com>
2024-07-17 18:50:02 +02:00
Daniel Petri Rocha
358a5bd901
Update bigbluebutton-html5/imports/ui/services/virtual-background/index.js
Co-authored-by: Anton Georgiev <antobinary@users.noreply.github.com>
2024-07-17 18:49:51 +02:00
transifex-integration[bot]
15525a6936
Translate en.json in es (#20704)
100% translated source file: 'en.json'
on 'es'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-07-15 15:20:14 -04:00
Daniel Petri Rocha
bfae93eb0e
Remove akka-fsesl changes 2024-07-13 11:55:25 +02:00
Daniel Petri Rocha
864e63ffcc
Remove debug log 2024-07-13 11:26:07 +02:00
Daniel Petri Rocha
f460d54a4e
Remove debug log 2024-07-13 11:23:29 +02:00
Daniel Petri Rocha
cf8f7528d0 Load image in from the URL 2024-07-12 20:06:49 +00:00
transifex-integration[bot]
6dc88facd9
Updates for project BigBlueButton v2.7 HTML5 client and language fr (#20694)
* Translate en.json in fr

100% translated source file: 'en.json'
on 'fr'.

---------

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-07-12 11:21:54 -04:00
Ramón Souza
a46e38fbbe
Merge pull request #20684 from Scroody/i-19354
Fix: Emoji animations are not being turned off by using the slider in settings.
2024-07-11 09:37:20 -03:00
André Möller
da3d8140da Fix: Emoji animations are not being turned off by using the slider in settings. 2024-07-10 16:40:16 -03:00
Ramón Souza
f5665f3bc4
Merge pull request #20669 from JoVictorNunes/issue-20654
fix: external video can be seen through sidebar on mobile
2024-07-10 15:59:11 -03:00
Ramón Souza
0c9e11c0e7
Merge pull request #20673 from Scroody/i-19870
Fix: Breakouts calculation for valid users incorrect
2024-07-10 15:11:45 -03:00
André Möller
fe3b81628f Change of approach 2024-07-10 10:45:08 -03:00
André Möller
ce8bb567a0 Revert "Fix: Breakouts calculation for valid users incorrect"
This reverts commit a86bdc9f1e.
2024-07-10 10:21:12 -03:00
André Möller
a86bdc9f1e Fix: Breakouts calculation for valid users incorrect 2024-07-09 11:11:08 -03:00
Ramón Souza
2ef8b4649f
Merge pull request #20670 from ramonlsouza/issue-20667
fix: Manage Layouts ignores disabledFeatures
2024-07-09 10:34:51 -03:00
Daniel Petri Rocha
a71527a825 Persist webcamBackground in the client 2024-07-09 12:13:50 +00:00
Ramón Souza
59e2609ffa do not display layout button if layouts are disabled 2024-07-09 09:10:06 -03:00
Daniel Petri Rocha
063b77a0fc defaultWebcamBackgroundURL 2024-07-09 12:01:03 +00:00
João Victor
a4756314a7 fix: external video can be seen through sidebar on mobile 2024-07-09 08:38:56 -03:00
Daniel Petri Rocha
de018453f6 Add webcamBackground parameter 2024-07-09 10:47:12 +00:00
Ramón Souza
9539ad09c0
Merge pull request #20639 from ramonlsouza/issue-20569
fix: Layout VIDEO_FOCUS shows empty tiles for other participants when see other viewers is locked
2024-07-05 17:25:20 -03:00
Gustavo Trott
65ebaecc9a
Merge pull request #20641 from ramonlsouza/issue-20029
fix: Enable download of the presentation not possible for temporarily presenters
2024-07-05 13:20:01 -03:00
Ramón Souza
c662a08d12 fix permission for download presentation 2024-07-05 11:35:31 -03:00
Ramón Souza
91762178b9 fix grid mode displaying viewers if see other viewers is locked 2024-07-05 10:04:57 -03:00
Daniel Petri Rocha
fd929a1508 Add green screen background, change documentation 2024-07-02 16:37:26 +00:00
Paul Trudel
b697667364
feat(events): Add user custom data to events.xml (#20566)
* Send custom user data to akka apps

* Add user custom data to registered user

* Add user custom data to user join event

* Store user custom data in Redis

* Rename userCustomData to customParameters

* Rename xml tag to userdata
2024-06-26 11:39:39 -04:00
Anton Georgiev
aeaf206f33
docs: added link to 2.7.9 2024-06-20 15:23:51 -04:00
Anton Georgiev
7b42421f41
docs: Clarify that allowPromoteGuestToModerator is a CREATE parameter (#20559) 2024-06-20 14:24:39 -04:00
Anton Georgiev
6588537bf4
Merge pull request #20546 from danimo/fix/gl3_migration_docs
docs(GL): correct statements about presentations not being migrated and how to fix entity too large errors
2024-06-19 13:19:00 -04:00
Daniel Molkentin
e8a361f11c fix: correct statements about presentations not being migrated and how to fix entity too large errors 2024-06-19 19:05:26 +02:00
Anton Georgiev
61b94e149d
chore: npm audit fix for learning dashboard (#20515)
* chore: npm audit fix for learning dashboard
2024-06-17 20:51:29 -04:00
Anton Georgiev
677177b72b
docs: document allowPromoteGuestToModerator [2.7] (#20514) 2024-06-17 19:12:48 -04:00
Anton Georgiev
7cab994333
chore: Bump release to 2.7.9 2024-06-17 15:32:06 -04:00
Anton Georgiev
77d6f77452
Merge pull request #20468 from bigbluebutton/translations_60cd9b750d2d41cd929b29887b4db1e8_ru
Updates for project BigBlueButton v2.7 HTML5 client and language ru
2024-06-11 14:32:43 -04:00
transifex-integration[bot]
885ba839c6
Translate en.json in ru
100% translated source file: 'en.json'
on 'ru'.
2024-06-11 18:13:33 +00:00
Anton Georgiev
ed929295f4
Merge pull request #20420 from paultrudel/video-metadata-fix
fix(recording): Add participants, raw size, and playback size information to video metadata
2024-06-10 16:59:02 -04:00
Anton Georgiev
a9cd4718ba
fix: only allow POST for insertDocument in UrlMappings.groovy [2.7] (#20432) 2024-06-06 12:10:28 -04:00
transifex-integration[bot]
9080d2e42a
Translate en.json in es_ES (#20423)
100% translated source file: 'en.json'
on 'es_ES'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-06-06 08:35:06 -04:00
transifex-integration[bot]
d966ea759a
Translate en.json in fi (#20412)
100% translated source file: 'en.json'
on 'fi'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-06-06 08:34:07 -04:00
Fred Dixon
b7d2ceff58
Update api.md
Add a link in https://docs.bigbluebutton.org/development/api/#join to the additional parameters in 
https://docs.bigbluebutton.org/administration/customize/#application-parameters
2024-06-06 07:31:48 -04:00
Paul Trudel
7911978d58 Reset gen_webvtt path 2024-06-05 20:08:48 +00:00
Paul Trudel
a239384c39 Added participants, raw size, and playback size to video metadata 2024-06-05 20:06:43 +00:00
Anton Georgiev
89cf90b2cb
Merge pull request #20405 from gustavotrott/backport-allowPromoteGuestToModerator-27
feat (backport 2.7): Introduces `allowPromoteGuestToModerator` config
2024-06-04 16:28:35 -04:00
Anton Georgiev
8efbde2bc5
Merge pull request #20387 from bigbluebutton/revert-20375-snyk-fix-7fdb0811956d5685b1df618bc376de0b
Revert "[Snyk] Fix for 1 vulnerabilities"
2024-06-04 14:35:25 -04:00
Anton Georgiev
859cfc1f85
Merge pull request #20372 from bigbluebutton/antobinary-patch-1
docs: adjust correct default value for breakouts being recorded
2024-06-04 14:33:08 -04:00
Gustavo Trott
37d6aa0140 introduce-allowPromoteGuestToModerator27 2024-06-04 11:36:46 -03:00
Paul Trudel
496a42ff90
fix(API): Allow additional parameters in content type headers (#20396)
* Allow additional values in content type header
2024-06-04 08:22:09 -04:00
transifex-integration[bot]
c0caafd2e6
Translate en.json in et (#20391)
100% translated source file: 'en.json'
on 'et'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-06-03 09:18:07 -04:00
Anton Georgiev
d42861dff9
Revert "[Snyk] Fix for 1 vulnerabilities" 2024-05-31 15:32:47 -04:00
transifex-integration[bot]
443b80904b
Updates for project BigBlueButton v2.7 HTML5 client and language gl (#20381)
* Translate en.json in gl

100% translated source file: 'en.json'
on 'gl'.

---------

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-05-31 10:06:53 -04:00
transifex-integration[bot]
25147a5719
Updates for project BigBlueButton v2.7 HTML5 client and language fr (#20385)
* Translate en.json in fr

100% translated source file: 'en.json'
on 'fr'.

---------

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-05-31 10:03:00 -04:00
Anton Georgiev
4bab8cf0ca
Merge pull request #20375 from bigbluebutton/snyk-fix-7fdb0811956d5685b1df618bc376de0b
[Snyk] Fix for 1 vulnerabilities
2024-05-30 16:08:54 -04:00
snyk-bot
ae70940d0e
fix: record-and-playback/core/Gemfile to reduce vulnerabilities
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-RUBY-NOKOGIRI-7164639
2024-05-30 16:37:27 +00:00
transifex-integration[bot]
fe5b15ee5b
Translate en.json in fa_IR (#20373)
100% translated source file: 'en.json'
on 'fa_IR'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-05-30 11:28:19 -04:00
Anton Georgiev
9b60e6ae5a
docs: adjust correct default value for breakouts being recorded 2024-05-30 10:50:49 -04:00
transifex-integration[bot]
81e025b3d9
Translate en.json in it_IT (#20358)
100% translated source file: 'en.json'
on 'it_IT'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-05-30 10:31:17 -04:00
transifex-integration[bot]
fdb95bb693
Translate en.json in ca (#20363)
100% translated source file: 'en.json'
on 'ca'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-05-30 10:30:19 -04:00
transifex-integration[bot]
acc8ea4809
Translate en.json in uk_UA (#20369)
100% translated source file: 'en.json'
on 'uk_UA'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-05-30 09:32:36 -04:00
Anton Georgiev
8bfe0a9b99
Merge pull request #20347 from schrd/fix-build-umask
build(fix): File permissions in packages should not depend on umask of build system
2024-05-28 10:47:28 -04:00
Daniel Schreiber
fc33fa599d Fix: File permissions in packages should not depend on umask of build system
If the build system for packages has a umask of `0077`, cloned
repositories will have no permissions for group and other. As the build
scripts for some packages just copy from clone git repos, this will
preserve the permissions in the package and prevent the following
services from startup:

* `bbb-html5`
* `etherpad`
* `bbb-pads`
* `bbb-export-annotations`
* `bbb-rap-*`

This patch grants everyone read permissions to the code in the packages.
2024-05-28 16:24:27 +02:00
Anton Georgiev
ee873794e9
Merge pull request #20332 from antobinary/port-docs-27
docs: Various fixes by @MBM1607
2024-05-24 12:04:03 -04:00
mbm_1607
109317f3e5 Update Playback section regarding video playback Fixes: #20300 2024-05-24 12:01:02 -04:00
mbm_1607
285ad950a4 Fix 404 links in docs
Fixes: https://github.com/bigbluebutton/bigbluebutton/issues/20303
2024-05-24 11:52:35 -04:00
mbm_1607
1f774ce888 Fix typos & spelling mistakes 2024-05-24 11:50:25 -04:00
mbm_1607
a3a0bba93a Fix the documentation image attachments
Fixes https://github.com/bigbluebutton/bigbluebutton/issues/20297
2024-05-24 11:43:00 -04:00
Anton Georgiev
45352c7721
Merge pull request #20276 from bigbluebutton/ffdixon-patch-1
docs: Make clear in docs that parameters are case sensitive.
2024-05-24 11:32:43 -04:00
Anton Georgiev
9e2ea86c3d
Merge pull request #20327 from bigbluebutton/translations_60cd9b750d2d41cd929b29887b4db1e8_fr
Updates for project BigBlueButton v2.7 HTML5 client and language fr
2024-05-24 09:00:36 -04:00
transifex-integration[bot]
c697caf00c
Translate en.json in fr
100% translated source file: 'en.json'
on 'fr'.
2024-05-24 08:23:43 +00:00
Anton Georgiev
e28b29bd0c
Merge pull request #20296 from bigbluebutton/snyk-fix-44dd4feb1f5d91a1647f15ddc120f975
[Snyk] Security upgrade rubocop from 1.31.2 to 1.32.0
2024-05-22 09:50:09 -04:00
snyk-bot
ab5dd32744
fix: record-and-playback/core/Gemfile & record-and-playback/core/Gemfile.lock to reduce vulnerabilities
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-RUBY-REXML-6861566
2024-05-17 23:53:33 +00:00
Anton Georgiev
6021da1004
docs: added link to 2.7.8 2024-05-16 08:53:35 -04:00
Fred Dixon
d6f22c2cd7
Update api.md
Note that the API parameters are case-sensitive in BigBlueButton.
2024-05-16 07:07:43 -04:00
Anton Georgiev
f57a1d07de
Merge pull request from GHSA-5966-9hw8-q96q
build: set permissions for resque files [2.7]
2024-05-15 15:06:11 -04:00
Anton Georgiev
04e916798b build: set permissions for resque files [2.7] 2024-05-15 14:32:55 -04:00
Anton Georgiev
d3e78e7d1e
Merge pull request #20216 from KDSBrowne/bbb-20200
fix(whiteboard): Disable Duplication Shortcut Key While Drawing
2024-05-15 12:53:00 -04:00
Anton Georgiev
ea6e9461dc
Merge pull request from GHSA-4m48-49h7-f3c4
fix(sec): API fix duplicates ghsa-4m48-49h7-f3c4 (2.7)
2024-05-15 10:38:58 -04:00
Anton Georgiev
62eb2c53cf
Update docs/docs/new-features.md 2024-05-15 10:36:05 -04:00
Anton Georgiev
63e59ede1e
chore: Bump release to 2.7.8 2024-05-14 13:48:48 -04:00
Anton Georgiev
301cf342a9
Merge pull request #20246 from bigbluebutton/snyk-fix-5a3ce69cdf0f6eaa1814ab6d0aace09f
[Snyk] Security upgrade jest from 27.5.1 to 29.0.0
2024-05-14 13:40:25 -04:00
snyk-bot
ee8b1021b9
fix: bigbluebutton-tests/puppeteer/package.json & bigbluebutton-tests/puppeteer/package-lock.json to reduce vulnerabilities
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JS-BRACES-6838727
- https://snyk.io/vuln/SNYK-JS-MICROMATCH-6838728
2024-05-14 04:47:39 +00:00
Anton Georgiev
220b0a9040
Merge pull request #20222 from KDSBrowne/bbb-20139
fix(whiteboard): Inconsistent Zoom Between Live Session And Recording
2024-05-13 10:40:43 -04:00
Anton Georgiev
5bc104fbf8
Merge pull request #20213 from paultrudel/insertDocument-response-fix
refactor(bbb-web): Add message key to insertDocument responses
2024-05-13 10:40:00 -04:00
Anton Georgiev
376037c31e
Merge pull request #20226 from antobinary/27-docs-may-10
docs: drop plugin @cmfcmf/docusaurus-search-local
2024-05-10 21:24:55 -04:00
Anton Georgiev
a943717c26 docs: drop plugin @cmfcmf/docusaurus-search-local 2024-05-10 21:23:05 -04:00
KDSBrowne
cc53fb58f2 fix inconsistent zoom between live session and recording 2024-05-10 20:36:55 +00:00
KDSBrowne
2b6d313c80 disable duplication shortcut key while drawing 2024-05-10 11:35:04 +00:00
Paul Trudel
aebb693379 Add message key to insertDocument responses 2024-05-09 19:54:41 +00:00
Paul Trudel
122b706035 Readd documentation of API changes to New Features section 2024-05-08 18:37:43 +00:00
Paul Trudel
e757cf15ee Removed unused POST checksum validation code 2024-05-08 14:03:48 +00:00
Paul Trudel
7a1081a974 Update docs to accurately document API functionality 2024-05-08 13:40:46 +00:00
Paul Trudel
06b7628f61 Restrict supported HTTP method types on endpoints 2024-05-07 20:34:20 +00:00
Paul Trudel
b2b57aca03 Remove support for join POST requests and fix checksum calculation for POST requests 2024-05-06 17:56:59 +00:00
Anton Georgiev
4a1c81fa76
Merge pull request #20177 from bigbluebutton/translations_60cd9b750d2d41cd929b29887b4db1e8_eu
Updates for project BigBlueButton v2.7 HTML5 client and language eu
2024-05-06 10:18:51 -04:00
transifex-integration[bot]
6ea1559ced
Translate en.json in eu
100% translated source file: 'en.json'
on 'eu'.
2024-05-05 21:22:35 +00:00
Anton Georgiev
c6b9364204
docs: Added a link to 2.7.7 2024-05-03 13:52:25 -04:00
Anton Georgiev
b2a08bfaff
Merge pull request #20169 from bigbluebutton/translations_60cd9b750d2d41cd929b29887b4db1e8_ja
Updates for project BigBlueButton v2.7 HTML5 client and language ja
2024-05-03 09:22:00 -04:00
transifex-integration[bot]
0f691e8968
Translate en.json in ja
100% translated source file: 'en.json'
on 'ja'.
2024-05-03 13:20:42 +00:00
Anton Georgiev
4c4fc491d3
Merge pull request #20165 from bigbluebutton/translations_60cd9b750d2d41cd929b29887b4db1e8_tr
Updates for project BigBlueButton v2.7 HTML5 client and language tr
2024-05-03 08:51:15 -04:00
transifex-integration[bot]
b6087ab8cb
Translate en.json in tr
100% translated source file: 'en.json'
on 'tr'.
2024-05-03 01:18:47 +00:00
Anton Georgiev
d749a2af08
Merge pull request #20154 from antobinary/npm-bump-may-2
chore: bump npm deps
2024-05-02 17:10:28 -04:00
Anton Georgiev
5810f8b662 chore: bump npm deps 2024-05-02 16:31:19 -04:00
Anton Georgiev
fc6f2581c6
chore: Bump release to 2.7.7 2024-05-02 16:24:01 -04:00
Anton Georgiev
0dc21a34d6
Merge pull request #20152 from prlanzarin/u27/fix/Arthurk12-live-1809
fix(bbb-html5): correct parameter type for wake lock log codes
2024-05-02 16:03:57 -04:00
Anton Georgiev
15e857abe5
Merge pull request #20153 from prlanzarin/u27/fix/Arthurk12-live-crashes-1800
fix(bbb-html5): potential crash in Youtube captions toggle
2024-05-02 16:03:04 -04:00
Anton Georgiev
d30974c771
Merge pull request #20151 from prlanzarin/u27/fix/Arthurk12-live-crashes-1798
fix(bbb-html5): filter poll users array before processing
2024-05-02 16:01:55 -04:00
Anton Georgiev
4d9e20891d
Merge pull request #20150 from prlanzarin/u27/fix/Arthurk12-live-crashes-1783
fix(bbb-html5): validate before getting user-list element attribute
2024-05-02 16:00:17 -04:00
Arthurk12
eb29634a87 fix(external-video): Youtube captions toggle
Ensures setOption and unloadModule are functions before calling.
2024-05-02 16:29:30 -03:00
Arthurk12
4e7d7dd452 fix(wake-lock): correct parameter type for log code
Previously, an object was incorrectly passed as the log code parameter.
Fixes it by ensuring that a string is passed instead.
2024-05-02 16:22:16 -03:00
Arthurk12
8dad2db2e2 fix(poll): filter users array before processing
Fix a crash in the polls live result by filtering out undefined users.
This scenario might happen when getting user information by an id that
is not present in the current usernames list by some inconsistency
between the user's information from the users context and poll
votes/responses.
2024-05-02 16:20:12 -03:00
Arthurk12
41c58d2466 fix(user-list): validate before getting element attribute
Implements check for getAttribute type before calling it.
2024-05-02 16:16:59 -03:00
Ramón Souza
356f6331c1
Merge pull request #20024 from Arthurk12/bbb/2.7/small-screens-toolbar
[2.7] fix(presentation): toolbar width on small screens
2024-05-02 15:32:31 -03:00
Anton Georgiev
64d5afc864
Merge pull request #20129 from bigbluebutton/antobinary-patch-3
chore: Bump requirement for safari versions
2024-05-02 12:19:07 -04:00
transifex-integration[bot]
13f66bddda
Translate en.json in de (#20146)
100% translated source file: 'en.json'
on 'de'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-05-02 11:05:46 -04:00
transifex-integration[bot]
6b4f2de798
Updates for project BigBlueButton v2.7 HTML5 client and language de (#20138)
* Translate en.json in de

100% translated source file: 'en.json'
on 'de'.

---------

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-05-02 09:28:12 -04:00
Fred Dixon
e5a9ce705f
Merge pull request #20105 from schrd/cluster-doc-fix
Docs: fix cluster setup instructions
2024-05-02 07:29:07 -04:00
Anton Georgiev
1fc488bfea
Merge pull request #20131 from bigbluebutton/translations_60cd9b750d2d41cd929b29887b4db1e8_el_GR
Updates for project BigBlueButton v2.7 HTML5 client and language el_GR
2024-05-01 14:41:06 -04:00
transifex-integration[bot]
6a146c0548
Translate en.json in el_GR
100% translated source file: 'en.json'
on 'el_GR'.
2024-05-01 18:15:39 +00:00
Anton Georgiev
400fff96c9
chore: Bump requirement for safari versions 2024-05-01 10:56:30 -04:00
Anton Georgiev
d4ce0b26b1
Merge pull request #20126 from bigbluebutton/translations_60cd9b750d2d41cd929b29887b4db1e8_ar
Updates for project BigBlueButton v2.7 HTML5 client and language ar
2024-05-01 09:23:02 -04:00
Daniel Schreiber
013ba50137 Docs: fix cluster setup instructions
As discovered by @pielonet there were some errors in the cluster setup
documentation.

Add instructions for nginx caching on the proxies as well.
2024-05-01 10:37:42 +02:00
transifex-integration[bot]
b81d624c66
Translate en.json in ar
100% translated source file: 'en.json'
on 'ar'.
2024-05-01 02:55:01 +00:00
Anton Georgiev
54403fb587
Merge pull request #20121 from prlanzarin/u27/fix/ff-pairselection
fix(audio): broken connection stats on Firefox >= 125
2024-04-30 14:42:35 -04:00
Anton Georgiev
d0307e6f21
Merge pull request #20010 from prlanzarin/u27/fix/review-mobile-audio-join
[2.7] fix(audio): review audio modal help screen
2024-04-30 14:41:54 -04:00
Anton Georgiev
850e8af19a
Merge pull request #20124 from prlanzarin/u27/fix/assorted-crashes-redux
fix: crash at meeting-ended due to undefined access + incorrect meetingID
2024-04-30 14:40:04 -04:00
Anton Georgiev
d484867c99
Merge pull request #20122 from prlanzarin/u27/fix/review-mobile-audio-chevron
fix(audio): review device selection in mobile endpoints
2024-04-30 14:39:14 -04:00
Anton Georgiev
403959bc34
Merge pull request #20123 from prlanzarin/u27/fix/assorted-br-crashes
fix: undefined accesses causes crashes in actions-bar breakout utils
2024-04-30 14:38:14 -04:00
Ramón Souza
8bf56ccad9
Merge pull request #20108 from Tainan404/Fix-reaction
Fix: user reaction not showing right emoji
2024-04-30 15:24:06 -03:00
prlanzarin
5f59453548 fix: crash at meeting-ended due to undefined access + incorrect meetingID
Fixes an undefined access crash at the meeting-ended component caused by
trying to access a property of a nullish user document.
Fixes incorrect access to the meetingId property of the user document -
currently fetched as meetingID, which doesn't exist.
2024-04-30 14:44:20 -03:00
prlanzarin
2084392ac7 fix: undefined accesses causes crashes in actions-bar breakout utils
Multiple undefined accesses in actions-bar's service, mainly related to
breakouts and ageneral Meetings info, cause crashes in production
environments - most likely in reconnection scenarios.

Guarantee that nested data is safely accessed.
2024-04-30 14:41:16 -03:00
prlanzarin
141c553b17 fix(audio): review device selection in mobile endpoints
Mobile users have no way to change I/O devices after joining audio.
The removal of the audio options chevron in mobile browsers was supposed
to be replaced by something else - in this case, by the dedicated
leave/join audio button. That didn't happen, leave/join audio button
retained the old behavior.

Review device selection in mobile endpoints via two UI/UX changes:
  - Restore the device selection chevron/icon in mobile endpoints
  - Override the leave/join button action in mobile endpoints so that it
    opens the device selection contextual menu, which also includes the
    "Leave audio" option. This retains the old behavior (leaving audio)
    while also providing an way for users to change devices mid-call in
    mobile browsers.
2024-04-30 14:29:53 -03:00
prlanzarin
9956af9aa1 fix(audio): improve help modal for listen only scenarios
The audio troubleshooting modal has very microphone-specific strings,
which might confuse users trying to join listen only.

Review the Help screen so that listen only scenarios are more generic.
As a bonus, review the unknownError locale with a more actionable text.
2024-04-30 13:59:08 -03:00
prlanzarin
f91402bc4a fix(audio): remove listen only retry routines
Listen only has a built-in retry routine on join failures that's
convoluted half-broken. It stems from the Kurento era where it could
fail randomly due to a myriad of reasons.
Production logs indicate that the retry is seldom used nowadays in
mediasoup-based environments. The presence of the retry also breaks
the error troubleshooting modal when actual failures happening, leaving
users in the dark about what's happening.

Remove the listen only retry code from AudioManager and bubble up any
join failure to the callers.
2024-04-30 13:58:06 -03:00
prlanzarin
a2e22fffb3 fix(audio): broken connection stats on Firefox >= 125
WebRTC-based stats generation in the connection status modal is broken
on Firefox >= 125. A broken type check coupled with a new partially
implemented RTCIceTransport dictionary causes and undefined function
call when fetching the selected candidate pair. Since that error is
unhandled, collection breaks.

Correctly check for the getSelectedCandidatePair method availability in
RTCIceTransport so that it skips to pair inference from getStats if
necessary.
2024-04-30 13:44:29 -03:00
Paul Trudel
698a736d58 Document API validation changes 2024-04-30 08:44:07 -04:00
Tainan Felipe
da60b246d0 Fix: user reaction not showing right emoji 2024-04-26 16:52:28 -03:00
Paul Trudel
fd6bd798f8 Add support for text/xml to create and insertDocument 2024-04-23 14:40:15 -04:00
Paul Trudel
fa38c7747e Removed unused set of supported content types from validator 2024-04-23 12:23:24 -04:00
Paul Trudel
7d156e8828 Added servlet request back to the checksums 2024-04-23 11:44:57 -04:00
Anton Georgiev
be96230894
Merge pull request #20065 from bigbluebutton/translations_60cd9b750d2d41cd929b29887b4db1e8_fr
Updates for project BigBlueButton v2.7 HTML5 client and language fr
2024-04-23 07:56:38 -04:00
transifex-integration[bot]
c83999dd46
Translate en.json in fr
100% translated source file: 'en.json'
on 'fr'.
2024-04-23 07:56:36 +00:00
Paul Trudel
de83c75716 Allow each request to define its own supported content types 2024-04-22 16:11:10 -04:00
Anton Georgiev
ebe0488aa6
Merge pull request #20052 from bigbluebutton/translations_60cd9b750d2d41cd929b29887b4db1e8_el_GR
Updates for project BigBlueButton v2.7 HTML5 client and language el_GR
2024-04-22 08:05:06 -04:00
Anton Georgiev
35c2370aca
Merge pull request #20055 from bigbluebutton/translations_60cd9b750d2d41cd929b29887b4db1e8_ja
Updates for project BigBlueButton v2.7 HTML5 client and language ja
2024-04-22 08:03:23 -04:00
transifex-integration[bot]
ea21caec53
Translate en.json in ja
100% translated source file: 'en.json'
on 'ja'.
2024-04-22 11:52:06 +00:00
transifex-integration[bot]
4cb07ad7e7
Translate en.json in el_GR
100% translated source file: 'en.json'
on 'el_GR'.
2024-04-21 18:17:00 +00:00
Anton Georgiev
0a0e8ef773
Merge pull request #20049 from bigbluebutton/translations_60cd9b750d2d41cd929b29887b4db1e8_ar
Updates for project BigBlueButton v2.7 HTML5 client and language ar
2024-04-19 14:58:59 -04:00
transifex-integration[bot]
503e7420a2
Translate en.json in ar
100% translated source file: 'en.json'
on 'ar'.
2024-04-19 18:31:09 +00:00
Anton Georgiev
0eae452d25
Merge pull request #19987 from lfzawacki/v2.7.x-release-more-languages
[2.7] Support more transcription languages
2024-04-19 11:53:22 -04:00
Anton Georgiev
3c2d89280b
Update bigbluebutton-html5/private/config/settings.yml 2024-04-19 11:24:32 -04:00
Paul Trudel
1b481a9500 Changed content type validation error key and message 2024-04-18 15:29:34 -04:00
Anton Georgiev
5f1c07f4c0
Merge pull request #20042 from bigbluebutton/snyk-fix-8ebee6c1447c58a1f87111817c06d09c
[Snyk] Fix for 1 vulnerabilities
2024-04-18 14:40:55 -04:00
snyk-bot
ffe42d1b10
fix: record-and-playback/core/Gemfile & record-and-playback/core/Gemfile.lock to reduce vulnerabilities
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-RUBY-NOKOGIRI-6228056
2024-04-18 18:03:10 +00:00
Anton Georgiev
b4158cbf14
Merge pull request #20033 from antobinary/port-19815
fix(sec): Bump logback-classic (backport)
2024-04-18 13:53:02 -04:00
Anton Georgiev
b5fe0ac64c
Merge pull request #20034 from antobinary/port-19814
fix(sec): Bump tomcatEmbed to 9.0.86 (#19814) (backport)
2024-04-18 13:52:46 -04:00
Anton Georgiev
304c3136be
Merge pull request #20035 from antobinary/port-19816
fix(sec): Bump org.json:json (backport)
2024-04-18 13:52:25 -04:00
Paul Trudel
e24e358ddd Reject requests with a body but no Content-Type header 2024-04-18 10:58:22 -04:00
Anton Georgiev
a184c67e44 fix(sec): Bump org.json:json 2024-04-17 14:30:10 -04:00
Anton Georgiev
c6ad69f292 fix(sec): Bump logback-classic 2024-04-17 14:29:18 -04:00
Anton Georgiev
3b3e7d840a fix(sec): Bump tomcatEmbed to 9.0.86 (#19814) 2024-04-17 14:24:41 -04:00
Anton Georgiev
f5be95da32
Merge pull request #20026 from Arthurk12/bbb/2.7/multiuser-non-presenter-error
fix(whiteboard): check before manipulating pan tool class list
2024-04-16 19:57:32 -04:00
Arthurk12
49c33b4eea fix(whiteboard): check before manipulating pan tool class list
Since the pan tool is only available for the presenter, it has to be checked
whether it actually exists before attempting to modify its class list.
2024-04-16 16:18:30 -03:00
Arthurk12
45e1724954 fix(presentation): toolbar width on small screens
Forces the toolbar width to be the maximum available width, which is
the width of the media area, on mobile devices. Also allow the toolbar to
overflow with an horizontal scroll when the available width is not enough
to display all of its contents.
2024-04-16 15:46:50 -03:00
transifex-integration[bot]
31537b1910
Updates for project BigBlueButton v2.7 HTML5 client and language fr (#20015)
* Translate en.json in fr

100% translated source file: 'en.json'
on 'fr'.

---------

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-04-16 09:41:34 -04:00
Paul
8e40d91877 Removed support for application/json content 2024-04-15 11:29:03 -04:00
Paul
183983be7f Added request content type validation 2024-04-15 11:29:03 -04:00
Paul
1e9e461f50 Check for pressence of query and body 2024-04-15 11:29:03 -04:00
Anton Georgiev
916d601d2b
Merge pull request #20008 from prlanzarin/u27/fix/crash-videoprovider-onmessage
[2.7] fix(bbb-html5): crash on video-provider unmount
2024-04-12 15:54:17 -04:00
Anton Georgiev
85b5e83bd5
Merge pull request #20013 from prlanzarin/u27/fix/arthurk12-undefined-role-crash
[2.7] fix: add safeguards when returning user roles
2024-04-12 15:53:42 -04:00
Anton Georgiev
6eaf8cd44d
Merge pull request #20004 from prlanzarin/u27/fix/audio-less-toasts
[2.7] fix(audio): minimize redundant audio exit toasts
2024-04-12 15:53:18 -04:00
Anton Georgiev
b98340bd27
Merge pull request #20003 from prlanzarin/u27/fix/ua-invalid-version-number
[2.7] fix: crash due to invalid UA version number in WKWebView (backport)
2024-04-12 15:37:15 -04:00
Anton Georgiev
10cb2f3875
Merge pull request #20012 from prlanzarin/u27/fix/arthurk12-screenreader-crash
[2.7] fix(screen-reader): add safeguards for adding alerts
2024-04-12 15:33:28 -04:00
Anton Georgiev
2f3e709324
Merge pull request #20007 from prlanzarin/u27/fix/invalid-metadataprop-access
[2.7] fix(bbb-html5): crash due to undefined metadataProp access
2024-04-12 15:32:17 -04:00
Anton Georgiev
711487c2c9
Merge pull request #20009 from prlanzarin/u27/fix/onconnectionstatechange-crash-rc
[2.7] fix(bbb-html5): crash when stopping WebRTC peers
2024-04-12 15:15:03 -04:00
Anton Georgiev
e511535adc
Merge pull request #20006 from prlanzarin/u27/fix/audio-answerer-gum-failure
[2.7] fix(audio): acquire streams before negotiation when peer is answerer
2024-04-12 15:14:17 -04:00
Anton Georgiev
fda4a5a2ff
Merge pull request #20005 from prlanzarin/u27/fix/crash-getBoundingClientRect-emojirain
[2.7] fix(reactions): crash when interactionsButton coords are absent
2024-04-12 15:13:33 -04:00
Arthurk12
72032f2397 fix: add safeguards when returning user roles 2024-04-12 15:14:49 -03:00
Arthurk12
6cb0e914ab fix(screen-reader): add safeguards for adding alerts
Adds checks for the alert's text and DOM element before adding screen
reader alerts.
2024-04-12 15:09:23 -03:00
prlanzarin
68f66a1fbb fix(audio): handle NotAllowedError in skipCheck:true scenarios
In scenarios where the join audio flow skips echo test, NotAllowedError
(and any other errors) are all being mashed together under a generic
MEDIA_ERROR object.

Properly handle specific errors in audio-manager so they're correctly
render in the audio modal help screen.
2024-04-12 14:40:51 -03:00
prlanzarin
501d627392 fix(audio): review audio modal help screen
- Adds a new Help view for unknown error codes
- Correctly detect NotAllowedError (permissions) - they are currently
  being treated like unknown errors in the Help modal
- Rephrase NotAllowedError help text; make it more succint and direct
- Rephrase the unknown error help text; make it more succint and direct
  - Add error code and message to that view
- Add public.media.audioTroubleshootingLinks to allow referencing KB
  links on the Help modal
  - See inline docs
2024-04-12 14:40:44 -03:00
prlanzarin
610f3b165b fix(bbb-html5): crash when stopping WebRTC peers
There's a race condition that may cause a client crash whenever a
connectionstatechange callback is cleaned up in a peer without a
valid peer connection present in our custom RTCPeerConnection wrapper.

Check for peerConnection availability in the WebRtcPeer wrapper before
trying to clean up its connectionstatechange callback.
2024-04-12 14:38:34 -03:00
prlanzarin
10a6a840b5 fix(bbb-html5): crash on video-provider unmount
There's a race condition that may cause a client crash whenever a
video-provider's unmount procedure is run, but its signalling websocket
is undefined. The WS's callback handlers are re-assigned without
checking for the socket's availability, causing an unhandled TypeError.

The WS may be undefined in a couple of scenarios, e.g.: unmouting before
the socket was successfully set up, unmounting while a reconnect is in
place etc.

Check whether the socket exists before accessing it in video-provider's
componentWillUnmount routine.
2024-04-12 14:33:35 -03:00
prlanzarin
71f958ca47 fix(bbb-html5): crash due to undefined metadataProp access
A client crash may happen if either the Meeting collection or the
document's metadataProp attribute are undefined whenever the
getFromMeetingSettings util is called to fetch metadata.
It's debatable whether anything is working in the client if the
documents being accessed here are unavailable, but it'll still be logged
and might bork an ongoing reconnect.

Use optional chaining + nullish coalescing to avoid causing TypeErrors
in those situations while also returning default metadata values
properly.
2024-04-12 14:31:38 -03:00
prlanzarin
555a8f6522 fix(audio): acquire streams before negotiation when peer is answerer
When a sendrecv peer acts as the answerer, gUM is only called _after_
the remote offer is received. This is fine, but the error handling runs
different in that scenario in a way that eventual gUM errors are treated
as negotiation errors, leading to inconsistencies when surfacing the
error to end users.

If a peer is acting as answerer and is a transceiver, acquire the local
streams _before_ actual negotiation so that gUM errors are surfaced
correctly (and we spare uneeded negotiation steps).
2024-04-12 14:29:38 -03:00
prlanzarin
66788e9697 fix(reactions): crash when interactionsButton coords are absent
The client may crash whenever a emoji rain animation is triggered, but
the interactions button element cannot be located. This happens because
the button coordinates are fetched without checking whether the element
exists.

Get the coordinate fetching method to return null if the
interactionsButton element cannot be located, and ignore the emoji rain
action if that is the case. Whenever no valid coordinates are found, log
an warning so we can track this and figure out what's happening with the
button.

Fix a few typos in the getInteractionsButtonCoordinates method.
2024-04-12 14:27:20 -03:00
prlanzarin
4e93a4de72 fix(audio): minimize redundant audio exit toasts
Audio exit toasts are fired in some redundant situations, e.g.: when the
error help screen is toast.

Change the logic a bit so that it's only fired when the audio help modal
won't be shown, i.e.: when audio had succesfully connected.
2024-04-12 14:23:25 -03:00
Anton Georgiev
29ea5c3e07
Merge pull request #20001 from ramonlsouza/fix-breakout-styles
fix: breakout styles
2024-04-12 13:12:48 -04:00
prlanzarin
3e845076cb fix: crash due to invalid UA version number in WKWebView
There are some scenarios (e.g. WKWebView) where Bowser can't detect the
Safari version number correctly, which leads to a client crash due to an
invalid string.split call in UnsupportedComponent.

In such cases, use the WebKit version to determine it. If that's not the
case and the version number is still unavailable, log an warning and
return Infinity so that we do not deny access to the user (even if
we're uncertain about whether it's a supported browser);
2024-04-12 14:06:44 -03:00
Ramón Souza
e4cced4b92 fix breakout styles 2024-04-12 13:35:01 -03:00
Lucas Fialho Zawacki
9676afceaf feat(transcription): Bump bbb-transcription-controller 2024-04-11 16:39:30 -03:00
Lucas Fialho Zawacki
f1bad0257d feat(transcription): Add translation strings for ca-ES and documentation links 2024-04-10 16:32:11 -03:00
Lucas Fialho Zawacki
33a704981e feat(captions): Remove speechVoices check before transcription 2024-04-10 11:33:10 -03:00
transifex-integration[bot]
fcbfcb1bbc
Translate en.json in zh_TW (#19979)
100% translated source file: 'en.json'
on 'zh_TW'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-04-10 10:19:47 -04:00
Anton Georgiev
8374e8b21a
Merge pull request #19797 from JoVictorNunes/issue-19181
fix(poll): avoid rendering polling component twice
2024-04-05 11:06:46 -04:00
Anton Georgiev
8502b50d1b
Merge pull request #19779 from danielpetri1/PR-19707
fix(bbb-export-annotations): Flag to force CairoSVG to embed images
2024-03-27 22:45:52 -04:00
transifex-integration[bot]
7bf1cdd028
Translate en.json in eu (#19920)
100% translated source file: 'en.json'
on 'eu'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-03-27 17:50:15 -04:00
Anton Georgiev
c7006d8d3f
Merge pull request #19875 from bigbluebutton/translations_60cd9b750d2d41cd929b29887b4db1e8_fa_IR
Updates for project BigBlueButton v2.7 HTML5 client and language fa_IR
2024-03-21 14:41:58 -04:00
transifex-integration[bot]
efa3ca0245
Translate en.json in fa_IR
100% translated source file: 'en.json'
on 'fa_IR'.
2024-03-21 16:47:27 +00:00
transifex-integration[bot]
6f4cb742d8
Updates for project BigBlueButton v2.7 HTML5 client and language tr (#19863)
* Translate en.json in tr

100% translated source file: 'en.json'
on 'tr'.

---------

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-03-20 20:16:32 -04:00
Anton Georgiev
3359289e1a
docs: added link to 2.7.6 2024-03-19 14:33:54 -04:00
Anton Georgiev
fdae7b48f4
chore: Bump release to 2.7.6 2024-03-19 10:10:11 -04:00
Paulo Lanzarin
07db720f3e
Merge pull request #19848 from prlanzarin/u27/build/sfu2133
[2.7] build(bbb-webrtc-sfu): v2.13.3
2024-03-19 11:09:33 -03:00
prlanzarin
2c2d2186ea build(bbb-webrtc-sfu): v2.13.3
* 2.13.3
  * fix(audio): user is deafened when transferring to breakout rooms
  * build(mediasoup): 3.13.24
2024-03-19 10:06:57 -03:00
Marc Kohaupt
990daeeb07
docs: bash script reads /etc/turnserver.conf to get realm and secret. (#18184)
* bash script reads /etc/turnserver.conf to get realm and secret.
2024-03-18 16:27:27 -04:00
Anton Georgiev
ae9a601660
Merge pull request #19810 from bigbluebutton/translations_60cd9b750d2d41cd929b29887b4db1e8_fr
Updates for project BigBlueButton v2.7 HTML5 client and language fr
2024-03-18 10:09:43 -04:00
Anton Georgiev
daf03638ae
Update faq.md 2024-03-17 21:59:46 -04:00
transifex-integration[bot]
2fc3119c14
Translate en.json in el_GR (#19821)
100% translated source file: 'en.json'
on 'el_GR'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-03-15 14:56:52 -04:00
transifex-integration[bot]
2466bb289e
Translate en.json in fr
100% translated source file: 'en.json'
on 'fr'.
2024-03-15 14:42:31 +00:00
transifex-integration[bot]
a0733d2c5b
Translate en.json in fr
100% translated source file: 'en.json'
on 'fr'.
2024-03-15 14:42:07 +00:00
Anton Georgiev
882ce76d75
Merge pull request #19803 from bigbluebutton/bbb27bwr070
[2.7] build(bbb-webrtc-recorder): v0.7.0
2024-03-14 18:09:01 -04:00
Anton Georgiev
9ada7458d3
Merge pull request #19801 from bigbluebutton/bbb27sfu2132
[2.7] build(bbb-webrtc-sfu): v2.13.2
2024-03-14 18:08:18 -04:00
Paulo Lanzarin
766f5e3af7
build(bbb-webrtc-recorder): v0.7.0
### v0.7.0

* fix: panic due to invalid OPUS samples pushed to builder
* build(docker): go 1.21
* build: bump pion/webrtc/v3 to v3.2.24
2024-03-14 14:09:29 -03:00
Paulo Lanzarin
f41aec10d4
build(bbb-webrtc-sfu): v2.13.2
### v2.13.2

* feat: add incrementBy util to prometheus-agent
* feat(core): add event callback and dispatch metrics
* fix: another edge case where subprocesses fail to recover

### v2.13.1

* fix: subprocesses fail to recover from multiple crashes

### v2.13.0

* feat: add inbound queue size and job failure metrics
* feat: add dry-run recording mode
* feat: add time_to_mute/unmute metrics
* feat: add warn logs for when hold/mute actions exceed max bucket time
* feat(mediasoup): add mediasoup_ice_transport_protocol metric
* feat(mediasoup): per-worker resource metrics
* feat(mediasoup): add worker label to transport/router/prod/cons metrics
* fix(audio): log and track metrics for hold/unhold timeouts
* fix(bbb-webrtc-recorder): exception when removing nullish recording callbacks
* fix(mediasoup): check for null producers
* fix(screenshare): resolve subscriberAnswer job
* fix(audio): prevent false positives in TLO toggle metrics
* fix(test): wait for recorder to boot in stress test script
* fix: set appropriate initial bitrates
* fix(mediasoup): max bitrate for consumer-only transports not effective
* fix(mediasoup): missing rtcp-fb and header exts in consumer-only offers
* fix(audio): stricter adherence to router.mediaCodecs settings
* fix(video): exception when destructuring null camera source
* fix(mediasoup): only call consumer.changeProducer when appropriate
* fix(mediasoup): capture icestatechange == disconnected
* fix(mediasoup): invalid RTP header exts in default config
* refactor: replace logger lib, Winston -> Pino
* chore(mediasoup): expose webRtcTransport's iceConsentTimeout config
* build: mediasoup-client@3.7.4
* build: mediasoup@3.13.23
* build: bump Docker and nvmrc to Node.js 20 (LTS)
2024-03-14 14:07:43 -03:00
danielpetri1
1b84bb318a Set default flag value to false 2024-03-14 15:39:55 +00:00
transifex-integration[bot]
ac8acfe507
Updates for project BigBlueButton v2.7 HTML5 client and language ja (#19780)
* Translate en.json in ja

100% translated source file: 'en.json'
on 'ja'.
---------

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-03-14 10:42:24 -04:00
João Victor
64c4567d06 fix(poll): avoid rendering polling component twice 2024-03-14 11:20:08 -03:00
danielpetri1
2c3939d147 Set CairoSVG unsafe flag 2024-03-11 21:18:39 +00:00
Ramón Souza
578daa130a
Merge pull request #19774 from bigbluebutton/antobinary-patch-2
fix(client): undefined currentUserAway
2024-03-11 16:52:17 -03:00
Anton Georgiev
c69b79872b
fix(client): undefined currentUserAway 2024-03-11 09:50:23 -04:00
transifex-integration[bot]
e1e00ea24d
Translate en.json in de (#19771)
100% translated source file: 'en.json'
on 'de'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-03-10 09:03:11 -04:00
transifex-integration[bot]
7b34845c0b
Translate en.json in ar (#19770)
100% translated source file: 'en.json'
on 'ar'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-03-10 09:02:18 -04:00
Anton Georgiev
fe76d76913
Merge pull request #19768 from bigbluebutton/antobinary-patch-1
fix(locale): Remove duplicate localization row
2024-03-09 20:10:21 -05:00
Anton Georgiev
8e067c4eef
fix(locale): Remove duplicate localization row 2024-03-09 20:08:12 -05:00
Anton Georgiev
980056a2e8
docs: Add a link for 2.7.5 2024-03-08 15:32:53 -05:00
Anton Georgiev
d90caf77dc
chore: Update copyright year 2024-03-08 14:52:48 -05:00
Anton Georgiev
2d66db96a1
Merge pull request #19762 from antobinary/recording-cc-disable
!fix(captions): disable recording event TranscriptUpdatedEvent
2024-03-07 16:29:48 -05:00
Anton Georgiev
b418f115fe !fix(captions): disable recording event TranscriptUpdatedEvent 2024-03-07 15:43:17 -05:00
Anton Georgiev
4e8a708c95
Merge pull request #19608 from lfzawacki/gladia-2.7
fix: Several Gladia transcription fixes
2024-03-07 15:32:54 -05:00
Anton Georgiev
6e9fbfb216
Merge pull request #19755 from antobinary/cdn-fix
fix(bbb-html5): Use CDN for resource of layouts
2024-03-07 15:11:24 -05:00
Anton Georgiev
4b469f03c5
Merge pull request #19758 from bigbluebutton/poppler-utils
build(export-annotations): Add dependency poppler-utils
2024-03-07 15:10:29 -05:00
paulseto
fdbab50205
test: update playwright tests to support sha256 and sha512 algorithms (#19725)
* update to support sha256 and sha512 algorithms

* Update bigbluebutton-tests/playwright/.env.template

Co-authored-by: Anton Barboza de Sá <antonbsa.bck@gmail.com>

---------

Co-authored-by: Anton Georgiev <antobinary@users.noreply.github.com>
Co-authored-by: Anton Barboza de Sá <antonbsa.bck@gmail.com>
2024-03-07 15:09:54 -05:00
Anton Georgiev
2fec7076b6
Merge pull request #19760 from antobinary/docs-march-07
docs: Update FreeSWITCH configs - Nine digits PIN
2024-03-07 14:39:12 -05:00
wilkis
70be65b20a Update customize.md 2024-03-07 14:37:12 -05:00
Anton Georgiev
3466f41fbf
Merge pull request #19759 from antobinary/docs-port-march-7
docs: drop old links #18295 from wilkis3/wilkis3-doc-admin-install-links (backport)
2024-03-07 14:34:28 -05:00
Anton Georgiev
a6c8012277 Merge pull request #18295 from wilkis3/wilkis3-doc-admin-install-links
Update Links In install.md Doc
2024-03-07 14:31:48 -05:00
Anton Georgiev
1f8ca310f1
feat(config): add checkSumAlgorithmForBreakouts in akka-apps (port) (#19754)
* feat(config): add checkSumAlgorithmForBreakouts in akka-apps (port)
2024-03-07 13:19:34 -05:00
Anton Georgiev
9506144857
build(export-annotations): Add dependency poppler-utils 2024-03-07 13:13:16 -05:00
Gustavo Trott
83f75cc727
Fix akka-apps: reStart ignoring /etc config (backport) #19757 2024-03-07 13:09:05 -05:00
Anton Georgiev
b26e32d519 fix(bbb-html5): Use CDN for resource of layouts 2024-03-07 11:11:03 -05:00
Anton Georgiev
6635b0ec14
chore: Bump release to 2.7.5 2024-03-07 10:42:12 -05:00
Ramón Souza
361717c69a
Merge pull request #19734 from ramonlsouza/issue-19180
fix: Download presentation popup window is broken
2024-03-06 17:51:11 -03:00
Anton Georgiev
ca7c2d1589
fix(sec): bump postgresql to 42.7.2 (#19660) 2024-03-05 21:08:30 -05:00
transifex-integration[bot]
3390d30fc8
Translate en.json in fr (#19740)
100% translated source file: 'en.json'
on 'fr'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-03-05 11:28:20 -05:00
Ramón Souza
f6b2d276a7 fix download presentation popup 2024-03-04 10:26:50 -03:00
Benjamin Brauner
25e619a4f6 update function redis.createClient to use redis host+port from config/settings.json otherwise redis use default host (localhost) and default port (6379)
)
2024-02-29 10:36:16 +01:00
Ramón Souza
abea38e718
Merge pull request #18762 from Scroody/I-18444
refactor: Changes to layout toast's workflow
2024-02-28 16:16:35 -03:00
André
6cf3cd47fb Change of approach for the debounce 2024-02-28 15:41:51 -03:00
Ramón Souza
4879d3e688
Merge pull request #19616 from JoVictorNunes/issue-19571
fix(layout): `defaultLayout` join parameter
2024-02-27 13:17:20 -03:00
André
f255f4b69e Later alterations 2024-02-26 15:52:24 -03:00
Daniel Petri Rocha
80d4bdbfef
fix(bbb-export-annotations): handle missing textbox size in Tldraw (#19672) 2024-02-23 20:20:16 -05:00
Jesus Federico
95d013d645
fix: bigbluebutton-html5/package.json & bigbluebutton-html5/package-lock.json to reduce vulnerabilities (#19678)
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JS-SANITIZEHTML-6256334

Co-authored-by: snyk-bot <snyk-bot@snyk.io>
2024-02-23 20:10:22 -05:00
transifex-integration[bot]
a4c6f98d59
Translate en.json in pt (#19671)
100% translated source file: 'en.json'
on 'pt'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-02-23 10:15:31 -05:00
Anton Georgiev
1ed6d0fdd2
docs: capitalize Support title (#19658) 2024-02-21 09:34:56 -05:00
Anton Georgiev
78ece5f05c
feat(config): Add option to disabled "Download session data" on Learning Dashboard (backport) (#19641)
* Add option disabledFeatures=learningDashboardDownloadSessionData

* docs: document learningDashboardDownloadSessionData

---------

Co-authored-by: Gustavo Trott <gustavo@trott.com.br>
2024-02-20 09:21:57 -05:00
Anton Georgiev
96a583b3e5
Record raiseHand, away and Reaction events (#19642)
Co-authored-by: Gustavo Trott <gustavo@trott.com.br>
2024-02-20 09:20:56 -05:00
André Castro
fbf5cfa7d2
Update bigbluebutton-html5/imports/ui/components/notifications/container.jsx
Co-authored-by: Ramón Souza <contato@ramonsouza.com>
2024-02-19 10:56:21 -03:00
Jan Kessler
2f091ffd3d
refactor: End meeting button tweaks (#19261)
* use label endMeetingForAll also for end button in settings dropdown

* change end button icon in settings dropdown from icon-bbb-application to icon-bbb-close
2024-02-16 15:50:52 -05:00
transifex-integration[bot]
5f0eb9ecb9
Updates for project BigBlueButton v2.7 HTML5 client and language fr (#19594)
* Translate en.json in fr

100% translated source file: 'en.json'
on 'fr'.

---------

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-02-16 15:48:17 -05:00
Anton Georgiev
51519e9c7a
fix: Reduce logs in SendWhiteboardAnnotationPubMsgHdlr.scala (#19634) 2024-02-16 15:47:13 -05:00
Anton Georgiev
1f97a6f253
fix: Drop heavy log from sendBulkAnnotations.js (#19633) 2024-02-16 15:46:18 -05:00
Anton Georgiev
95c945f4b3
fix: Aviod presentation conversion causing a crash (#19600) 2024-02-14 14:48:30 -05:00
João Victor
fa872e2b55 fix(layout): defaultLayout join parameter 2024-02-09 18:02:13 -03:00
Ramón Souza
04714848cf
Merge pull request #19609 from Scroody/i-18917
Fix: Modal of the inactivity inspection does not show up
2024-02-09 15:55:56 -03:00
transifex-integration[bot]
08a50f8c01
Translate en.json in nb_NO (#19613)
100% translated source file: 'en.json'
on 'nb_NO'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-02-09 09:52:11 -05:00
Lucas Fialho Zawacki
17c132376a Bump bbb-transcription-controller tag 2024-02-09 11:40:21 -03:00
André
22be736c88 Fix: Modal of the inactivity inspection does not show up 2024-02-08 14:59:14 -03:00
Lucas Fialho Zawacki
aca3730d9f fix(captions): Use default transcription value with external providers 2024-02-08 14:50:31 -03:00
Lucas Fialho Zawacki
388858000c feat(gladia): Print Gladia errors in the console 2024-02-08 14:50:24 -03:00
Lucas Fialho Zawacki
a744193536 fix(): Use captions.dication flag to show/hide dication button 2024-02-08 14:50:17 -03:00
Lucas Fialho Zawacki
8d741fa016 fix(captions): Fix caption display 2024-02-08 14:48:44 -03:00
Fred Dixon
0e38681e32
Merge pull request #19602 from bigbluebutton/ffdixon-patch-1
Unset all local variables
2024-02-08 08:53:25 -04:00
Fred Dixon
5d6c066acb
Unset all local variables 2024-02-08 07:54:11 -04:00
Anton Georgiev
5f963c4465
Merge pull request #19597 from kepstin/issue-19178-workaround
recording: work around invalid locale in caption events
2024-02-07 09:40:19 -05:00
Calvin Walton
34f8cf30ba recording: work around invalid locale in caption events
This is a workaround for #19178 - but it does not fix the issue. The
caption recording events with invalid empty `<locale/>` are simply
dropped with a warning message, to allow the recording and any valid
caption streams present to be processed.
2024-02-06 16:13:39 -05:00
Anton Georgiev
b22a9d0c8b
Merge pull request #19588 from bigbluebutton/antobinary-patch-3
docs: Close code block in customize md
2024-02-06 09:03:59 -05:00
Anton Georgiev
b4528a0032
docs: Close code block in customize md 2024-02-06 09:02:10 -05:00
transifex-integration[bot]
d924e23069
Translate en.json in fr (#19525)
100% translated source file: 'en.json'
on 'fr'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-02-05 09:24:57 -05:00
transifex-integration[bot]
aa1af6b83f
Translate en.json in hu_HU (#19565)
100% translated source file: 'en.json'
on 'hu_HU'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-02-05 09:24:14 -05:00
Ramón Souza
5cf2b78d22
Merge pull request #19538 from ramonlsouza/19536-27
fix: Incorrect hover style on the upload presentation button in the polling menu (2.7)
2024-02-05 10:51:08 -03:00
Ramón Souza
8d3473cd4d
Merge pull request #19557 from ramonlsouza/issue-19505
fix: Upload the exported users list to presentation breaks the whiteboard
2024-02-05 10:50:09 -03:00
Ramón Souza
e13fc75f6d fix presentation uploader crash 2024-02-01 15:49:13 -03:00
Ramón Souza
4ede1a1218 remove no presentation button styles in poll panel 2024-01-30 10:40:12 -03:00
transifex-integration[bot]
5398df1a8a
Translate en.json in lt_LT (#19492)
100% translated source file: 'en.json'
on 'lt_LT'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-01-23 09:41:25 -05:00
Paulo Lanzarin
22efe4647f
build(bbb-webrtc-sfu): v2.12.2 (#19460)
## CHANGELOG

* fix(screenshare): resolve subscriberAnswer job
* fix(bbb-webrtc-recorder): exception when removing nullish recording callbacks
* fix(mediasoup): check for null producers
* build(mediasoup): 3.12.16
2024-01-22 11:11:19 -05:00
Paulo Lanzarin
1babc38e7e
build(bbb-webrtc-recorder): v0.6.0 (#19459)
* feat: recorder.writeToDevNull option to write files to /dev/null (testing)
  * fix: panic due to negative seqnums in sequence unwrapper
2024-01-22 11:11:02 -05:00
Paulo Lanzarin
e1dc4b55e4
fix(bbb-html5): customHeartbeat would not close stale sessions, + (#19017)
* fix(bbb-html5): customHeartbeat would not close stale sessions, +

The [disabled by default] custom heartbeat included in Meteor's server
does not end connections when they are considered unhealthy/stale, which
deviates a bit from the default implementation. See:
https://github.com/bigbluebutton/bigbluebutton/pull/11486.

This commit includes a call to the default heartbeat termination timeout
so sockets are correctly cleaned up when the custom heartbeat is
activated. It also adds a customHeartbeatUseDataFrames config to allow
controlling whether the custom heartbeat should use WS data frames as
valid heartbeats as well - this should only be useful for
testing/debugging purposes and the default behavior (true) is
maintained.

As a side note: this change spun off from an investigation where some
problematic networks were triggering periodic client re-connects due to
the default heartbeat failing. Investigation points to the control
frames being put alongside fragmented WS data frames and the server side
failing to recognize the former - which means pong frames would be missed and
the health check would fail. Since the default heartbeat _does not_
account for data frame traffic (eg DDP payloads), it would shut down the
client's WS even though it was healthy.
The custom heartbeat _does_ account for data frames, which mitigates
that scenario and prevents unecessary reconnections.

* fix(bbb-html5): frontend crash due to undefined vars in customHeartbeat 

Meteor frontends may crash when customHeartbeat is enabled
due to an undefined access in the heartbeat`s logger.

Add optional chaining to the session props access so it won`t crash and tune down some log levels around that area.
2024-01-22 11:10:41 -05:00
transifex-integration[bot]
262cd0b735
Translate en.json in sv_SE (#19469)
100% translated source file: 'en.json'
on 'sv_SE'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-01-19 08:52:39 -05:00
Anton Georgiev
55238d0b50
docs: fix link to gladia io 2024-01-16 09:26:30 -05:00
Anton Georgiev
afe30cf678
Merge pull request #19438 from bigbluebutton/antobinary-patch-2
docs: Tweaks to gladia io docs
2024-01-16 09:19:51 -05:00
Anton Georgiev
d54fd57c00
docs: Tweaks to gladia io docs 2024-01-16 09:18:11 -05:00
Fred Dixon
551028ba51
Update customize.md
Added text for using Gladia.io in 2.7.4.
2024-01-16 09:51:53 -04:00
Anton Georgiev
75af5c03e7
docs: 2.7.4 and info link added 2024-01-15 15:53:37 -05:00
Anton Georgiev
792add0a3d
Merge pull request #19266 from Ithanil/fix_raise-hand_away_reactions
Fix: away and raiseHands 'reactions' being hidden by avatar image
2024-01-15 12:29:08 -05:00
Anton Georgiev
e59d6dcea8
Merge pull request #19434 from ramonlsouza/default-animations
feat: join param for default animations setting value
2024-01-15 10:41:27 -05:00
Ramón Souza
8495777d5b feat: join param for default animations setting value 2024-01-15 11:59:40 -03:00
Anton Georgiev
7551eaebb0
chore: Bump release to 2.7.4 2024-01-11 20:55:39 -05:00
Anton Georgiev
fd8c927140
Merge pull request from GHSA-j42p-fh2w-24q6
fix(sec): validate URL for external upload of presentation
2024-01-11 16:16:38 -05:00
Anton Georgiev
59cdb136ad
Merge pull request from GHSA-r3vv-c788-9fph
fix(sec): filter tags in presentation name
2024-01-11 16:07:18 -05:00
Anton Georgiev
f50e10b5ea fix(sec): filter tags in presentation name 2024-01-10 14:15:56 -05:00
Ramón Souza
35bf9b537c
Merge pull request #19281 from Arthurk12/bbb/2.7/19278
fix(chat): exported presentation notification
2024-01-10 15:57:13 -03:00
Jesus Federico
45585215cc
fix: bbb-export-annotations/package.json & bbb-export-annotations/package-lock.json to reduce vulnerabilities (#19389)
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JS-AXIOS-6144788

Co-authored-by: snyk-bot <snyk-bot@snyk.io>
2024-01-05 15:18:29 -05:00
Anton Georgiev
bb2ecb7c66
test: bigbluebutton-tests/playwright/package.json & bigbluebutton-tests/playwright/package-lock.json to reduce vulnerabilities (#19392)
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JS-AXIOS-6144788

Co-authored-by: snyk-bot <snyk-bot@snyk.io>
2024-01-05 15:16:04 -05:00
Anton Georgiev
aadb5f688f
test: bigbluebutton-tests/puppeteer/package.json & bigbluebutton-tests/puppeteer/package-lock.json to reduce vulnerabilities (#19394)
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JS-AXIOS-6144788

Co-authored-by: snyk-bot <snyk-bot@snyk.io>
2024-01-05 15:13:54 -05:00
Anton Georgiev
b8c2f3f774
fix: bigbluebutton-html5/package.json & bigbluebutton-html5/package-lock.json to reduce vulnerabilities (#19395)
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JS-AXIOS-6144788

Co-authored-by: snyk-bot <snyk-bot@snyk.io>
2024-01-05 15:12:48 -05:00
Anton Georgiev
e64ab86dd7
fix: Bump spring-boot-starter-validation to 2.7.17 to match bbb-web (#19385) 2024-01-05 09:34:03 -05:00
Jesus Federico
47c5a04e21
fix: bigbluebutton-html5/package.json & bigbluebutton-html5/package-lock.json to reduce vulnerabilities (#19366)
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JS-AXIOS-6124857

Co-authored-by: snyk-bot <snyk-bot@snyk.io>
2024-01-04 16:25:30 -05:00
Jesus Federico
d4cea455c1
fix: bigbluebutton-tests/puppeteer/package.json & bigbluebutton-tests/puppeteer/package-lock.json to reduce vulnerabilities (#19364)
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JS-AXIOS-6124857

Co-authored-by: snyk-bot <snyk-bot@snyk.io>
2024-01-04 16:23:41 -05:00
Anton Georgiev
e778f5857c
Merge pull request #19383 from KDSBrowne/27-zoom-jitter
fix: Improve Wheel Zoom Stability
2024-01-04 16:13:28 -05:00
KDSBrowne
fe6993d699 fix wheel zoom jitter 2024-01-03 17:58:25 +00:00
Anton Georgiev
e7840e19c5
build(sec): upgrade FreeSWITCH to 1.10.11 +sofia-sip +libks (#19377) 2024-01-02 14:09:50 -05:00
transifex-integration[bot]
86caf70e3b
Updates for project BigBlueButton v2.7 HTML5 client and language ko_KR (#19350)
* Translate en.json in ko_KR

100% translated source file: 'en.json'
on 'ko_KR'.

---------

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-01-02 09:47:13 -05:00
transifex-integration[bot]
bb126a953f
Translate en.json in et (#19375)
100% translated source file: 'en.json'
on 'et'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-01-02 09:46:15 -05:00
transifex-integration[bot]
98a62c0fab
Updates for project BigBlueButton v2.7 HTML5 client and language uk_UA (#19373)
* Translate en.json in uk_UA

100% translated source file: 'en.json'
on 'uk_UA'.

---------

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-01-02 09:45:38 -05:00
transifex-integration[bot]
3da6812407
Updates for project BigBlueButton v2.7 HTML5 client and language fr (#19345)
* Translate en.json in fr

100% translated source file: 'en.json'
on 'fr'.

---------

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-01-02 09:44:43 -05:00
transifex-integration[bot]
66b3f00e4b
Updates for project BigBlueButton v2.7 HTML5 client and language fr (#19342)
* Translate en.json in fr

100% translated source file: 'en.json'
on 'fr'.

---------

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2023-12-15 08:25:33 -05:00
transifex-integration[bot]
d5f7e7d0e4
Updates for project BigBlueButton v2.7 HTML5 client and language fr (#19322)
* Translate en.json in fr

100% translated source file: 'en.json'
on 'fr'.

---------

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2023-12-12 14:31:39 -05:00
Paulo Lanzarin
dedd455863
Merge pull request #19315 from bigbluebutton/u27/build/bwr052
build(bbb-webrtc-recorder): v0.5.2
2023-12-08 12:53:56 -03:00
Paulo Lanzarin
999ed90a56
build(bbb-webrtc-recorder): v0.5.2
Fixes a crash found during field trials.

See: https://github.com/bigbluebutton/bbb-webrtc-recorder/blob/v0.5.2/CHANGELOG.md#v052
2023-12-08 10:37:58 -03:00
Anton Georgiev
5db198e6a5
updated greenlight docs to include user:set_admin_role rake task (#19311)
Co-authored-by: SilentFlameCR <rodrigues.rahul77@gmail.com>
2023-12-07 15:53:02 -05:00
Anton Georgiev
54bcd9076e
Merge pull request #19299 from antobinary/v2.7.x-release
docs: use npm only - drop yarn [2.7 portion]
2023-12-06 15:47:29 -05:00
Anton Georgiev
ddb7fb77f5 add package.json docusaurus 2023-12-06 13:54:54 -05:00
Anton Georgiev
94534455b8 drop broken link; npx to run docusaurus 2023-12-06 10:45:21 -05:00
Anton Georgiev
d0a703e734 wip remove yarn 2023-12-06 10:25:33 -05:00
Anton Georgiev
14b8603164 wip remove yarn 2023-12-06 10:22:20 -05:00
Anton Georgiev
59a23ed98d wip - drop yarn from docs 2023-12-06 10:13:14 -05:00
Anton Georgiev
a8d2307b9a
docs: comply to MDX v3 (stricter markdown) (#19285) 2023-12-05 10:42:14 -05:00
Arthurk12
333b6727b9 fix(chat): exported presentation notification
Adds a specific function to handle the creation of the exported presentatio's
toast notification that were missing.
2023-12-04 17:39:32 -03:00
Anton Georgiev
13e27ab154
fix: bbb-recording-imex/pom.xml to reduce vulnerabilities (#19277)
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JAVA-CHQOSLOGBACK-6097492
- https://snyk.io/vuln/SNYK-JAVA-CHQOSLOGBACK-6097493

Co-authored-by: snyk-bot <snyk-bot@snyk.io>
2023-12-04 13:56:09 -05:00
transifex-integration[bot]
5f7c747698
Updates for project BigBlueButton v2.7 HTML5 client and language ru (#19270)
* Translate en.json in ru

100% translated source file: 'en.json'
on 'ru'.

---------

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2023-12-04 10:07:11 -05:00
transifex-integration[bot]
a9f68154cf
Translate en.json in ar (#19272)
100% translated source file: 'en.json'
on 'ar'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2023-12-04 10:06:38 -05:00
Gustavo Trott
4f8fa07702
Merge pull request #19232 from Ithanil/labelless_leave_meeting_button 2023-12-01 07:24:17 -03:00
Jan Kessler
62c7f5a35a fix away and raiseHands 'reactions' being hidden by avatar image 2023-11-30 19:24:14 +01:00
Lucas
125d70699b
feat: Initial implementation of Gladia transcriptions to BBB 2.7 (#19091)
* Demo changes

* Revert "feat(captions): no longer writes in the pad"

This reverts commit a76de8c458.

* feat(transcriptoin): Add config options for the transcription backend

* feat(transcription): Add autodetect option to cc chevron

* feat(transcription): Move transcription options into settings modal

* feat(transcription): Set transcription options via userdata

* fix(transcription): Correct userdata for settings transcription params

* feat(transcriptions): options to auto enable caption button

* feat(transcriptions): Option to hide old CC pad funcionality

* fix(transcription): Fix PR comments

* fix(transcription): Refactor updateTranscript to prevent null user and make it more readable

* feat(transcription): bbb_transcription_provider can be set via userdata

* fix(transcription): Use base10 for parseInt

* fix(transcriptions): Fix CC language divider when using webspeech

* fix(transcriptions): Use a default pad in the settings instead of hardcoding 'en'

We still need to use a language pad such as 'en', but in the future we can better
separate these systems.

* fix(transcription): Add a special permission for automatic transcription updates to the pad and restore old per user updates permission

* feature(transcriptions): Include transcriptions submenu and locales

* chore: bump bbb-transcription-controller to v0.2.0

* fix(transcription): Add missing menu files

* fix(transcription): Fix transcription provider options in settings.yml

* fix: setting password for bbb-transcription-controller

* build: add gladia-proxy.log for transcription-controller

* fix(transcriptions): Remove transcript splitting and floor logic from akka apps

* fix(captions): Show long utterances as split captions, show multiple speaker captions

* chore: bump bbb-transcription-controller to 0.2.1

---------

Co-authored-by: Anton Georgiev <anto.georgiev@gmail.com>
2023-11-30 10:10:36 -05:00
Jan Kessler
c88c23302e add and use label endMeetingForAll in dropdown of leave meeting button 2023-11-30 15:40:36 +01:00
transifex-integration[bot]
2a38249ddf
Updates for project BigBlueButton v2.7 HTML5 client and language ru (#19255)
* Translate en.json in ru

100% translated source file: 'en.json'
on 'ru'.

---------

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2023-11-30 08:34:46 -05:00
Anton Georgiev
453bb8fe73
fix: bbb-recording-imex/pom.xml to reduce vulnerabilities (#19249)
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JAVA-CHQOSLOGBACK-6094942
- https://snyk.io/vuln/SNYK-JAVA-CHQOSLOGBACK-6094943

Co-authored-by: snyk-bot <snyk-bot@snyk.io>
2023-11-30 08:13:46 -05:00
Jan Kessler
283a029e6c change end meeting icon in leave-button dropdown from icon-bbb-application to icon-bbb-close 2023-11-29 14:28:11 +01:00
Jan Kessler
08115a93a6 remove divider in settings dropdown, if leave button is enabled 2023-11-29 10:53:22 +01:00
Jan Kessler
630c79e5c7 add aria-label to leave meeting button
add description to leave meeting button
2023-11-29 10:38:37 +01:00
Jan Kessler
742733f7a8 fine-tuning of left/right margin for leave-meeting button 2023-11-29 09:33:48 +01:00
Jan Kessler
2ac1e7cb97 also remove end meeting from settings dropdown if direct leave button is enabled 2023-11-28 17:58:07 +01:00
Jan Kessler
f19aac1895 add dropdown selection for leave/end on leave meeting button 2023-11-28 17:55:34 +01:00
Jan Kessler
409cf1decb add margin and tooltip instead of label to new leave meeting button 2023-11-27 16:46:19 +01:00
transifex-integration[bot]
5a9c3a140a
Updates for project BigBlueButton v2.7 HTML5 client and language ru (#19214)
* Translate en.json in ru

100% translated source file: 'en.json'
on 'ru'.

---------

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2023-11-27 10:21:35 -05:00
transifex-integration[bot]
e15f50e7a8
Translate en.json in es_ES (#19212)
100% translated source file: 'en.json'
on 'es_ES'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2023-11-27 10:20:11 -05:00
transifex-integration[bot]
a8495c8433
Translate en.json in es (#19211)
100% translated source file: 'en.json'
on 'es'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2023-11-27 10:19:48 -05:00
Anton Georgiev
8eb425b4bc
Merge pull request #19166 from srikantharika/v2.7.x-release
doc: what's new in 2.7 link not proper
2023-11-27 09:17:05 -05:00
Anton Georgiev
d683ab2240
Update links formatting 2023-11-27 09:16:42 -05:00
Anton Georgiev
3daf0ba7d3
Merge branch 'v2.7.x-release' into v2.7.x-release 2023-11-27 09:10:42 -05:00
Anton Georgiev
44d655523f
Merge pull request #19206 from gustavotrott/fix-app-btn-encodeUrl
fix (backport): Button 'Open Tablet app' breaks when the meeting name contains white space
2023-11-24 08:53:22 -05:00
Gustavo Trott
cd21fffaaa fix: Button 'Open Tablet app' breaks when the meeting name contains white space 2023-11-24 10:19:40 -03:00
Anton Georgiev
9e8acbe007
Merge pull request #19205 from farhatahmad/v3-docs
Greenlight v3 docs: More cleanup and reorg
2023-11-23 14:49:18 -05:00
farhatahmad
c541c2fdc2 Greenlight v3 more docs updates 2023-11-23 14:22:11 -05:00
Anton Georgiev
78f26fd599
Merge pull request #19204 from antobinary/docs-backport
docs: Docs backport
2023-11-23 13:10:28 -05:00
Louis-Michel Couture
ae2fb8ba78 Update outdated reference to index.html path 2023-11-23 13:07:42 -05:00
mbm_1607
5a24e9a520 ✏️ Fix typo in docs issue template 2023-11-23 13:07:42 -05:00
mbm_1607
8b7cfdb54f 📝 Update typo in install.md 2023-11-23 13:07:42 -05:00
farhatahmad
d041fe660b Added entry for OPENID_CONNECT_UID_FIELD 2023-11-23 13:06:16 -05:00
farhatahmad
2282b6220a Greenlight v3 Docs: Add information for migrating local accounts 2023-11-23 13:06:15 -05:00
Ramón Souza
70cccbe9b7
Merge pull request #19127 from KDSBrowne/bb27-smooth-cursor
fix: Add Transitions To Improve Cursor Movement Fluidity
2023-11-23 13:02:41 -03:00
Anton Georgiev
41348a1767
Merge pull request #18890 from tbird20d/patch-1
Update bbb-conf.md - fix typo in word 'easi'
2023-11-23 10:29:58 -05:00
Paul Trudel
374ad5045d
chore: Upgrade Grails to 6.1 (#19193) 2023-11-23 09:45:45 -05:00
transifex-integration[bot]
b61ceb2883
Translate en.json in eu (#19202)
100% translated source file: 'en.json'
on 'eu'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2023-11-23 09:15:26 -05:00
transifex-integration[bot]
cfa15e8b60
Translate en.json in tr (#19198)
100% translated source file: 'en.json'
on 'tr'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2023-11-22 15:49:41 -05:00
Anton Georgiev
bde7fe7dba
Merge pull request #19188 from bigbluebutton/translations_60cd9b750d2d41cd929b29887b4db1e8_fr
Updates for project BigBlueButton v2.7 HTML5 client and language fr
2023-11-21 10:43:47 -05:00
transifex-integration[bot]
5063cb5dfa
Translate en.json in fr
100% translated source file: 'en.json'
on 'fr'.
2023-11-21 15:18:16 +00:00
srikantharika
15b70514fb
Update install.md
link path at line 336 path doesn't exist. modified with actual path.
2023-11-17 23:56:35 +05:30
Anton Georgiev
74c2a259ba
Merge pull request #19163 from bigbluebutton/translations_60cd9b750d2d41cd929b29887b4db1e8_fa_IR
Updates for project BigBlueButton v2.7 HTML5 client and language fa_IR
2023-11-17 07:02:56 -05:00
transifex-integration[bot]
5f45e8b2fc
Translate en.json in fa_IR
100% translated source file: 'en.json'
on 'fa_IR'.
2023-11-17 11:14:23 +00:00
Ramón Souza
32d24e564c
Merge pull request #19114 from ramonlsouza/issue-16945
upgrade tooltip dependency and fix open tooltip on mobile
2023-11-16 13:04:18 -03:00
Anton Georgiev
229fb4ad09
Merge pull request #19111 from bigbluebutton/translations_60cd9b750d2d41cd929b29887b4db1e8_ja
Updates for project BigBlueButton v2.7 HTML5 client and language ja
2023-11-16 09:26:44 -05:00
Anton Georgiev
af05863ad3
Merge pull request #19132 from danielpetri1/patch-4
fix: Bump Etherpad's export rate limiting (2.7)
2023-11-15 15:20:17 -05:00
Ramón Souza
db8452f3f1
Merge pull request #19101 from gabriellpr/rm-flaky-flags
test: Removing flaky flags
2023-11-15 10:01:00 -03:00
Daniel Petri Rocha
6f86883324
Bump importExportRateLimiting to 32
Allows up to 32 export requests within a 90 second window in Etherpad.
2023-11-14 20:03:23 +01:00
Paulo Lanzarin
2471174b51
Merge pull request #19119 from bigbluebutton/sfu2121
build(bbb-webrtc-sfu): v2.12.1
2023-11-13 13:39:57 -03:00
Paulo Lanzarin
852b80850f
build(bbb-webrtc-sfu): v2.12.1
See https://github.com/bigbluebutton/bbb-webrtc-sfu/releases/tag/v2.12.1
2023-11-13 13:03:18 -03:00
Ramón Souza
9dd0bb56e2 upgrade tooltip dependency 2023-11-13 10:51:03 -03:00
transifex-integration[bot]
6a3323ea3a
Translate en.json in ja
100% translated source file: 'en.json'
on 'ja'.
2023-11-11 23:47:45 +00:00
Gabriel Porfirio
1724f9fce2 removing flaky flags 2023-11-10 13:35:47 -03:00
Anton Georgiev
92df679e2c
docs: Added link to 2.7.3 2023-11-09 19:12:54 -05:00
Anton Georgiev
5d671b3b50
Merge pull request #19095 from bigbluebutton/webhooks261
build(bbb-webhooks): v2.6.1
2023-11-09 15:57:34 -05:00
Paulo Lanzarin
31d2bf798e
build(bbb-webhooks): v2.6.1
See https://github.com/bigbluebutton/bbb-webhooks/releases/tag/v2.6.1
2023-11-09 17:09:44 -03:00
Anton Georgiev
bb1a0b75d7
Merge pull request #19071 from bigbluebutton/antobinary-patch-3
chore: Bump bbb-playback to 5.0.2
2023-11-09 10:17:24 -05:00
GuiLeme
bba51c38fa [GHSA-j42p-fh2w-24q6] - validate URL for external upload of presentation. 2023-11-09 10:01:52 -03:00
Anton Georgiev
d71202c195
Merge pull request #19088 from gustavotrott/LDashboard-convert-reaction-to-emojiStatus
fix (learning-dashboard): Learning Dashboard not showing Reactions
2023-11-08 09:11:26 -05:00
Anton Georgiev
f314aaf046
Merge pull request #19084 from prlanzarin/u27/fix/dialin-reguser-dedupe
fix: specify a unique mock authToken for dial-in users, +
2023-11-08 09:03:22 -05:00
Gustavo Trott
8b4b226603 Improve comment to prevent flood 2023-11-08 10:30:51 -03:00
Gustavo Trott
686903a529 In LearningDashboard, convert Reactions to EmojiStatus 2023-11-08 10:21:28 -03:00
KDSBrowne
c7149c931b add transitions to cursors for smoothing 2023-11-08 00:20:59 +00:00
Anton Georgiev
d72e8d98d7
Merge pull request #19083 from bigbluebutton/translations_60cd9b750d2d41cd929b29887b4db1e8_el_GR
Updates for project BigBlueButton v2.7 HTML5 client and language el_GR
2023-11-07 16:17:07 -05:00
prlanzarin
c6ccb19fdc fix: reversed userColor and avatar args in dial-in user creation
userColor and avatar arguments of RegisteredUsers.create were incorrectly placed
2023-11-07 18:04:03 -03:00
prlanzarin
2f12992c20 fix: specify a unique mock authToken for dial-in users
Every dial in user has its RegistedUser authToken set to an empty string,
Since authToken is the RegUser's HashMap indexing key, this causes a
bunch of inconsistencies; eg.: endpoint ejection will stop working if
more than one dial-in user joined a meeting concurrently because the
later dial-in devices overwrite the earlier ones in the RegUsers map.

The authToken is now mocked as the user's intId (which, for dial-in, is
the voice user ID) so that some sort of uniqueness is guaranteed within
the voice conf scope.
2023-11-07 18:02:10 -03:00
transifex-integration[bot]
2f8daf34fa
Translate en.json in el_GR
100% translated source file: 'en.json'
on 'el_GR'.
2023-11-07 19:23:35 +00:00
Anton Georgiev
c594be415a
Merge pull request #19072 from ramonlsouza/issue-18937
fix: The shortcut for raising hand is not functioning as expected @ 2.7.1
2023-11-07 13:17:14 -05:00
Anton Georgiev
1b61900548
Merge pull request #19080 from ramonlsouza/issue-12614
feat: leave meeting button
2023-11-07 09:18:01 -05:00
Ramón Souza
72029590e5 add param to docs 2023-11-07 10:11:55 -03:00
Ramón Souza
fd8f0bddab add danger button hover styles 2023-11-07 10:07:30 -03:00
Ramón Souza
3de1cfed29 leave meeting button 2023-11-07 09:54:17 -03:00
Anton Georgiev
0970160ede
Merge pull request #19070 from bigbluebutton/antobinary-patch-2
chore: Bump bbb-pads to 1.5.2
2023-11-06 15:11:50 -05:00
Anton Georgiev
301b7cd0f2
Merge pull request #19078 from ramonlsouza/issue-19052
refactor: Move manage layouts to three-dots menu
2023-11-06 15:11:22 -05:00
Ramón Souza
37870bb1d2 move manage layouts to three-dots menu 2023-11-06 15:37:52 -03:00
Anton Georgiev
8db78c7200
Merge pull request #19075 from bigbluebutton/translations_60cd9b750d2d41cd929b29887b4db1e8_el_GR
Updates for project BigBlueButton v2.7 HTML5 client and language el_GR
2023-11-06 12:09:07 -05:00
transifex-integration[bot]
80b6251c09
Translate en.json in el_GR
100% translated source file: 'en.json'
on 'el_GR'.
2023-11-06 16:22:06 +00:00
Ramón Souza
bedef5bf89 restore raise hand shortcut 2023-11-06 09:48:38 -03:00
Anton Georgiev
fbe79a07d7
chore: Bump bbb-playback to 5.0.2 2023-11-06 07:12:11 -05:00
Anton Georgiev
b9c619a4a6
chore: Bump bbb-pads to 1.5.2 2023-11-06 06:40:42 -05:00
Ramón Souza
49864dc6e6
Merge pull request #19062 from antobinary/toast-on-self-view
refactor: Add a toast warning you that your webcam is still streaming…
2023-11-06 08:06:58 -03:00
Anton Georgiev
b8e1656d14
Merge pull request #19069 from bigbluebutton/translations_60cd9b750d2d41cd929b29887b4db1e8_es_ES
Updates for project BigBlueButton v2.7 HTML5 client and language es_ES
2023-11-06 05:54:26 -05:00
Anton Georgiev
ab64a9e265
Merge pull request #19068 from bigbluebutton/translations_60cd9b750d2d41cd929b29887b4db1e8_es
Updates for project BigBlueButton v2.7 HTML5 client and language es
2023-11-06 05:53:55 -05:00
transifex-integration[bot]
96b6d02768
Translate en.json in es_ES
100% translated source file: 'en.json'
on 'es_ES'.
2023-11-05 12:29:06 +00:00
transifex-integration[bot]
64a0d73812
Translate en.json in es
100% translated source file: 'en.json'
on 'es'.
2023-11-05 12:28:57 +00:00
Anton Georgiev
188894612d
Merge pull request #19064 from bigbluebutton/translations_60cd9b750d2d41cd929b29887b4db1e8_el_GR
Updates for project BigBlueButton v2.7 HTML5 client and language el_GR
2023-11-02 16:17:00 -04:00
Anton Georgiev
221327e4c5
Update bigbluebutton-html5/imports/ui/components/video-provider/video-list/video-list-item/user-actions/component.jsx
Co-authored-by: Ramón Souza <contato@ramonsouza.com>
2023-11-02 16:06:41 -04:00
transifex-integration[bot]
07f6edd515
Translate en.json in el_GR
100% translated source file: 'en.json'
on 'el_GR'.
2023-11-02 19:40:52 +00:00
Anton Georgiev
17427fbd9b refactor: Add a toast warning you that your webcam is still streaming (self view disabled) 2023-11-02 14:07:30 -04:00
Ramón Souza
cc1caf443f
Merge pull request #19061 from antobinary/rename-songs
refactor: rename Songs to Music in BBB Timer
2023-11-02 13:55:18 -03:00
Anton Georgiev
42b7905065 refactor: rename Songs to Music in BBB Timer 2023-11-02 12:20:25 -04:00
Anton Georgiev
b5e6f528fc
Merge pull request #19055 from gustavotrott/tests-track-build-packge-27
ci (backport 2.7): Refresh package's cache whenever there are changes in its build directory
2023-11-02 06:49:02 -04:00
Anton Georgiev
a8488ac841
Merge pull request #19056 from ramonlsouza/throttle-fix-port
fix: Waiting room indicator sound defective
2023-11-02 06:45:49 -04:00
Paulo Lanzarin
7b9e3e09cd
Merge pull request #19053 from bigbluebutton/sfu212
build(bbb-webrtc-sfu): v2.12.0
2023-11-01 19:21:25 -03:00
Ramón Souza
1b65c36743 improve throttle function 2023-11-01 17:36:46 -03:00
Ramón Souza
0688cba0b4 fix leading:true, trailing:false throttle 2023-11-01 17:36:26 -03:00
Gustavo Trott
b9ebd45ac3 Add build/packages-template for every package cache-key 2023-11-01 17:24:44 -03:00
Anton Georgiev
e5b8b2f7d9
Merge pull request #19046 from bigbluebutton/antobinary-patch-1
chore: Upgrade LibreOffice to 7.6.2
2023-11-01 16:11:03 -04:00
Paulo Lanzarin
06262e309a
build(bbb-webrtc-sfu): v2.12.0
See https://github.com/bigbluebutton/bbb-webrtc-sfu/releases/tag/v2.12.0
2023-11-01 15:36:32 -03:00
Anton Georgiev
34c3918e20
chore: Upgrade LibreOffice to 7.6.2 2023-11-01 06:50:32 -04:00
Anton Georgiev
72eb50860c
chore: bump up release to 2.7.3 2023-11-01 05:37:17 -04:00
Anton Georgiev
bd4edcf726
Merge pull request #19018 from bigbluebutton/snyk-fix-1d44f35e53972d39c7c5389699621548
[Snyk] Security upgrade axios from 0.21.4 to 1.6.0
2023-10-31 13:18:43 -04:00
Anton Georgiev
f910c6ff0f
Merge pull request #19041 from bigbluebutton/antobinary-patch-1
chore: Bump Etherpad to 1.9.4
2023-10-31 08:47:21 -04:00
Anton Georgiev
decfd3335b
chore: Bump Etherpad to 1.9.4 2023-10-30 15:14:50 -04:00
Anton Georgiev
e9f1d76330
Merge pull request #19033 from bigbluebutton/snyk-fix-63c36c1df3ed25c79d200c54fff3c83e
[Snyk] Security upgrade axios from 1.4.0 to 1.6.0
2023-10-30 11:58:29 -04:00
Anton Georgiev
dca4f734ff
Merge pull request #19031 from bigbluebutton/snyk-fix-a8712ee027b5bab9eb85c546983b0a72
[Snyk] Security upgrade axios from 0.26.1 to 1.6.0
2023-10-30 11:58:00 -04:00
snyk-bot
f71e3f8965
fix: bigbluebutton-tests/playwright/package.json & bigbluebutton-tests/playwright/package-lock.json to reduce vulnerabilities
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JS-AXIOS-6032459
2023-10-28 07:59:20 +00:00
snyk-bot
a7e5df126f
fix: bigbluebutton-tests/puppeteer/package.json & bigbluebutton-tests/puppeteer/package-lock.json to reduce vulnerabilities
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JS-AXIOS-6032459
2023-10-27 22:34:00 +00:00
snyk-bot
684d54da66
fix: bigbluebutton-html5/package.json & bigbluebutton-html5/package-lock.json to reduce vulnerabilities
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JS-AXIOS-6032459
2023-10-27 17:26:32 +00:00
Paulo Lanzarin
7021d3fa8d
Merge pull request #19008 from bigbluebutton/sfu2120b2-27
build(bbb-webrtc-sfu): v2.12.0-beta.2
2023-10-25 17:00:23 -03:00
Paulo Lanzarin
bd967e8193
build(bbb-webrtc-sfu): v2.12.0-beta.2
Fixes an issue where Kurento would stall more frequently when compared to versions 2.11.x or lower.
2023-10-25 16:13:33 -03:00
Ramón Souza
7a26d761b0
Merge pull request #19002 from Scroody/I-18919
Fix: Poll answers not being translated in learning dashboard
2023-10-25 11:08:25 -03:00
André
54d56524c9 Fix: Poll answers not being translated in learning dashboard 2023-10-24 15:50:36 -03:00
transifex-integration[bot]
1571573fee
Updates for project BigBlueButton v2.7 HTML5 client and language pt_BR (#18996)
* Translate en.json in pt_BR

100% translated source file: 'en.json'
on 'pt_BR'.

---------

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2023-10-24 10:46:13 -04:00
Ramón Souza
a9973d3cff
Merge pull request #18994 from gabriellpr/update-presentation-screenshot
test: Adds @flaky to other presentation format test
2023-10-24 09:40:44 -03:00
Gabriel Porfirio
4a44e37d93 flaky flag to other presentation format test 2023-10-23 14:36:58 -03:00
Ramón Souza
a1dd1371e8
Merge pull request #18977 from Scroody/patch-2
Fix: Moderator lowering hand from toast broken
2023-10-23 11:40:55 -03:00
Ramón Souza
ed44b33b15
Merge pull request #18958 from Arthurk12/bbb/2.7/18763-1
fix(user-list): center icons on apple devices
2023-10-23 11:39:37 -03:00
André Castro
281308ba4a
Update component.jsx 2023-10-23 11:12:50 -03:00
André Castro
371378cca8
Update bigbluebutton-html5/imports/ui/components/raisehand-notifier/component.jsx
Co-authored-by: Ramón Souza <contato@ramonsouza.com>
2023-10-23 11:11:11 -03:00
André
39de071ab2 Merge remote-tracking branch 'upstream/v2.7.x-release' into patch-2 2023-10-20 14:34:57 -03:00
Anton Georgiev
545712db34
Update new-features.md 2023-10-20 10:37:19 -04:00
Anton Georgiev
ce883f8678
Merge pull request #18990 from bigbluebutton/docs-presentation
docs: add example for preUploadedPresentation
2023-10-20 10:00:04 -04:00
Anton Georgiev
4e1e5e361e
docs: add example for preUploadedPresentation 2023-10-20 09:52:30 -04:00
Gustavo Trott
730803cc20
Merge pull request #18986 from paultrudel/pid-null-error-fix
fix: Null pointer exception when parent meeting does not exist
2023-10-20 10:24:59 -03:00
Paul Trudel
d33a1c028a
Update bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/ApiController.groovy
Co-authored-by: Gustavo Trott <gustavo@trott.com.br>
2023-10-20 08:27:15 -04:00
Paul Trudel
3dc4cb28d9
Update bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/ApiController.groovy
Co-authored-by: Gustavo Trott <gustavo@trott.com.br>
2023-10-20 08:27:09 -04:00
Paul Trudel
bc7c3143ba Prevent null error when parent meeting does not exist 2023-10-19 19:54:43 +00:00
Anton Georgiev
ab370872bf
Merge pull request #18985 from antobinary/docs-preUploadedPresentation
docs: preUploadedPresentation and preUploadedPresentationName
2023-10-19 15:44:07 -04:00
Anton Georgiev
f2dbd891cd docs: preUploadedPresentation and preUploadedPresentationName 2023-10-19 15:25:38 -04:00
Anton Georgiev
65b4c5d5d7 docs: preUploadedPresentation and preUploadedPresentationOverrideDefault 2023-10-19 14:51:08 -04:00
Anton Georgiev
d24cdfde6f
Merge pull request #18975 from Ithanil/fix_isbreakout_api
fix: check for presence of parentMeetingID if isBreakout is true
2023-10-19 14:35:05 -04:00
Anton Georgiev
eb82bbb6de
Merge pull request #18981 from antobinary/spring-bump
chore: upgrade Spring to 2.7.17
2023-10-19 14:27:16 -04:00
Anton Georgiev
134fe725de
Merge pull request #18982 from gabriellpr/fix-presentation-screenshot
test: Update screenshot presentation (3.0 backport)
2023-10-19 14:14:44 -04:00
Gabriel Porfirio
f5175d0b71 fixing screenshots presentations 2023-10-19 14:55:19 -03:00
Anton Georgiev
33f44e1dca
Merge pull request #18953 from GuiLeme/Issue-18924
feat (api): Add preUploadedPresentation param to API's /create via GET
2023-10-19 13:54:37 -04:00
Gustavo Trott
c026ecc727
Update bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/ApiController.groovy 2023-10-19 14:46:10 -03:00
Gustavo Trott
73b7bded08
Update bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/ApiController.groovy 2023-10-19 14:45:59 -03:00
Anton Georgiev
423bf8ab28
Merge pull request #18979 from antobinary/npm-audit-dashboard
chore: npm audit fixes for bbb-learning-dashboard
2023-10-19 13:33:40 -04:00
Anton Georgiev
44bb3a67de
Merge pull request #18978 from antobinary/npm-oct19
chore: npm audit fixes bbb-html5
2023-10-19 13:33:26 -04:00
Anton Georgiev
a2d7743773 chore: upgrade Spring to 2.7.17 2023-10-19 13:11:21 -04:00
Anton Georgiev
df6da10cea chore: upgrade Spring to 2.7.17 2023-10-19 12:42:41 -04:00
Anton Georgiev
77b29d745a chore: npm audit fixes for bbb-learning-dashboard 2023-10-19 12:29:00 -04:00
Anton Georgiev
0693103e14 chore: npm audit fixes 2023-10-19 12:22:29 -04:00
André Castro
94347949d9
Update component.jsx 2023-10-19 13:18:10 -03:00
Anton Georgiev
c14b1510c2
Merge pull request #18974 from antobinary/libreoffice-set-version
(sec)build(bbb-libreoffice): bump to 7.5.7.1
2023-10-19 12:14:30 -04:00
Anton Georgiev
76fd4508c9 tweak tag 2023-10-19 11:11:25 -04:00
GuiLeme
d6670a4145 [issue-18924] - changes in review, and added possibility to insert a name along with URL 2023-10-19 10:27:38 -03:00
Jan Kessler
520668632f fix check for presence of parentMeetingId if isBreakout is true 2023-10-19 10:53:54 +02:00
Anton Georgiev
c125cbc720 build(bbb-libreoffice): bump to 7.5.7.1 2023-10-19 03:52:53 -04:00
Anton Georgiev
c89154d2a8
Merge pull request #18945 from antobinary/lo-from-dockerhub
build(bbb-libreoffice): Switch the LibreOffice Docker image to use the one built by BBB (backport to 2.7)
2023-10-19 03:46:59 -04:00
Anton Georgiev
82b9b1f408
Merge pull request #18970 from antobinary/docs-emoji-rain-2
docs: Add info on reactions animations
2023-10-19 02:30:00 -04:00
Anton Georgiev
f230fea85a docs: Add info on reactions animations toggle 2023-10-18 14:29:09 -04:00
Anton Georgiev
b994e45f67 docs: Add info on reactions animations 2023-10-18 14:24:42 -04:00
Ramón Souza
01c3f6fb45
Merge pull request #18959 from lfzawacki/bbb-2.7
feat(reactions): port new reactions and fix emojiRain
2023-10-18 09:44:08 -03:00
Ramón Souza
577ed647d9
Update bigbluebutton-html5/imports/ui/components/emoji-rain/component.jsx 2023-10-18 09:28:30 -03:00
Lucas Fialho Zawacki
20b4ffe7dd fix(reactions): Remove unused file 2023-10-17 19:06:37 -03:00
germanocaumo
cb075137b3 fix(emoji-rain): increase date comparison trigger
The date comparison check was too strict/wrong, increase it to show the emojis created in the last second to account for delays in connection.
2023-10-17 18:57:37 -03:00
Lucas Fialho Zawacki
b2f25decd6 fix(reactions): Get reaction emoji list from settings.yml 2023-10-17 18:44:05 -03:00
Arthurk12
cb744adf52 fix(user-list): center icons on apple devices
Centers the icons on the user-list that indicate the user's role, audio
state and whiteboard access. This time using a better strategy where the
centralization is achieved with display flex, align-items and
justify-content.
2023-10-17 17:17:23 -03:00
Lucas Fialho Zawacki
5f1bed6d44 fix(reactions): Fix react errors on new emoji-mart version 2023-10-17 16:08:14 -03:00
GuiLeme
a22068be18 [Issue-18924] - Changed parameter name to preUploadedPresentation 2023-10-17 10:38:44 -03:00
GuiLeme
d7d228d047 [Issue-18924] 2023-10-17 10:26:09 -03:00
Anton Georgiev
2e980ca5d4
Merge pull request #18949 from bigbluebutton/translations_60cd9b750d2d41cd929b29887b4db1e8_fr
Updates for project BigBlueButton v2.7 HTML5 client and language fr
2023-10-17 05:57:53 -04:00
transifex-integration[bot]
6283c856fb
Translate en.json in fr
100% translated source file: 'en.json'
on 'fr'.
2023-10-17 09:05:22 +00:00
AtilaU19
11f5481b5a fix(reactions): New style for emoji reactions and visual cooldown 2023-10-16 14:31:32 -03:00
AtilaU19
ac3c7790d4 refactor(emoji-picker): update emoji-mart to latest version 2023-10-16 14:17:11 -03:00
Gustavo Trott
09687431b7 Switch the LibreOffice Docker image to use the one built by BBB 2023-10-16 12:44:52 -04:00
Anton Georgiev
f046ec20af
Merge pull request #18942 from bigbluebutton/translations_60cd9b750d2d41cd929b29887b4db1e8_et
Updates for project BigBlueButton v2.7 HTML5 client and language et
2023-10-16 10:22:25 -04:00
transifex-integration[bot]
f327c988b9
Translate en.json in et
100% translated source file: 'en.json'
on 'et'.
2023-10-16 07:15:15 +00:00
Anton Georgiev
693183291d
chore: bump up release to 2.7.2 2023-10-11 11:51:19 -04:00
Fred Dixon
c4e24e93bf
Merge pull request #18918 from ffdixon/add-video-setup-script
Add script to easily setup video recording format
2023-10-10 06:46:11 -04:00
Fred Dixon
ea2b855bf7 Add script to easily setup video recording format 2023-10-10 06:44:49 -04:00
Fred Dixon
31db461114
Update sidebars.js
Fix syntax error in sidebars.js
2023-10-10 06:05:21 -04:00
Fred Dixon
1dc942243b
Merge pull request #18915 from ffdixon/add-help-document
Add support documentation
2023-10-10 05:12:51 -04:00
Fred Dixon
898d6a6156 Add support documentation 2023-10-10 05:11:25 -04:00
Ramón Souza
f7a77beb61
Merge pull request #18765 from Arthurk12/bbb/2.7/18763
fix(user-list): center icons on safari
2023-10-09 08:13:24 -03:00
Arthurk12
6129314a33 fix(user-list): center icons in chrome on iOS devices 2023-10-06 19:11:49 -03:00
Ramón Souza
fd1a27fe21
Merge pull request #18906 from Tainan404/hotfix-audio-captions
Hotfix: Audio captions not working properly
2023-10-06 17:17:06 -03:00
Tainan Felipe
fb0b98a6af Hotfix: Audio captions not working properly 2023-10-06 18:13:55 +00:00
Ramón Souza
8388d55f80
Merge pull request #18887 from KDSBrowne/bbb-18837
fix: Add Bounds to Presentation Zoom Changer
2023-10-06 15:08:17 -03:00
Anton Georgiev
5cd379910f
Merge pull request #18891 from paultrudel/breakout-rooms-end-fix
fix: End breakout rooms when ENDED_DUE_TO_NO_MODERATOR
2023-10-06 13:09:20 -04:00
Anton Georgiev
c390799eab
Merge pull request #18587 from bigbluebutton/etherpad-192
build(etherpad): Bump etherpad-lite to 1.9.3
2023-10-06 13:07:03 -04:00
Anton Georgiev
d22c9568b8
Merge pull request #18892 from kepstin/deskshare-audio-hang
fix(recording): Deskshare audio processing hang
2023-10-06 13:06:14 -04:00
Anton Georgiev
791074819d
Merge pull request #18685 from gustavotrott/fix-None-user-on-changeEmoji27
fix (akka-apps): None.get error on change user Emoji
2023-10-06 11:30:05 -04:00
transifex-integration[bot]
f0e5d8aa9d
Translate en.json in fa_IR (#18866)
100% translated source file: 'en.json'
on 'fa_IR'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2023-10-06 11:26:37 -04:00
Anton Georgiev
f63bbdceed
Merge pull request #18893 from kepstin/bbb-presentation-video
bbb-presentation-video: Update to 4.0.4
2023-10-05 15:13:26 -04:00
Anton Georgiev
756499bbb0
build: etherpad 1.9.3 2023-10-04 12:50:46 -04:00
Calvin Walton
2d23f82e55 bbb-presentation-video: Update to 4.0.4
Fixes a recording processing crash which can occur if malformed events
are generated by BigBlueButton due to client bugs.
2023-10-03 17:02:49 -04:00
Calvin Walton
d402f519c6 fix(recording): Deskshare audio processing hang
This is a refinement of the fix introduced in 3c1a9cd7c4.

Further investigation of the issue reveals that the cause of the bad
timestamps which result in error messages or hang is when the `apad`
filter does not receive any input audio frames. This happens if the
seekpoint is after the end of audio. The existing seekpoint checks can't
cover this, because in a deskshare file the video stream can continue on
after the audio stream ends.

The `,asetpts=N` filter was added to deal with this problem, and it
works in most cases. But there is a case where it fails - when the
"mismatched length" audio stretching to work around broken recordings
from BigBlueButton 0.81/0.90 kicks in.

The issue there is that the `atrim=start=S` filter (used due to the
difficulty of calculating seeks when stretching) hits the invalid
timestamps and hangs.

I'm working around this issue with a "defense in depth" combination of
two changes:

* Move the `,asetpts=N` filter to be applied before the audio stretch
  filters. This fixes the processing hang.
* Adjust the conditions on the "mismatched length" audio stretching so
  that it only gets applied on audio files likely to be from extremely
  old BigBlueButton versions - those with audio in wav files, or encoded
  to vorbis.

BigBlueButton has been using audio recorded directly to opus by
FreeSWITCH for quite a while, and the handling for gaps or lost packets
is done in current BBB versions by a combination of the libopus decoder
and the use of ffmpeg's `aresample=async=1000` filter to dynamically
stretch, squish, or fill in audio so it becomes a continuous stream
that's locked to the file timestamps. Applying the "mismatched length"
processing on top of that is probably making audio sync issues worse.
2023-10-03 14:21:50 -04:00
Paul Trudel
1dac6867d9 End breakout rooms when no moderator 2023-10-03 18:21:34 +00:00
Tim Bird
f7b16ac973
Update bbb-conf.md - fix typo in word 'easi'
Change 'easi' to 'easy'
2023-10-03 10:57:33 -06:00
KDSBrowne
ea301da3a3 add bounds to presentation zoom changer 2023-10-02 23:24:20 +00:00
Fred Dixon
56edf23a1f
Merge pull request #18884 from prlanzarin/u27/docs/screenshare-qos-conf
docs: add notes on how to tweak screen sharing quality
2023-10-02 14:07:29 -04:00
prlanzarin
97c5c79772 docs: add notes on how to tweak screen sharing quality 2023-10-02 14:51:52 -03:00
Ramón Souza
ef0b78ce30
Merge pull request #18872 from ramonlsouza/fix-video-dropdown-rtl
fix: video dropdown chevron in rtl
2023-09-28 14:39:19 -03:00
Ramón Souza
fde37f08c9 fix video dropdown in rtl 2023-09-28 14:02:32 -03:00
Anton Georgiev
27efad9fc2
Merge pull request #18862 from bigbluebutton/translations_60cd9b750d2d41cd929b29887b4db1e8_eu
Updates for project BigBlueButton v2.7 HTML5 client and lanuage eu on branch v2.7.x-release
2023-09-27 10:04:39 -04:00
transifex-integration[bot]
61df5319e5
Translate en.json in eu
100% translated source file: 'en.json'
on 'eu'.
2023-09-26 20:53:01 +00:00
Ramón Souza
32d6532308
Merge pull request #18851 from ramonlsouza/issue-18816
fix: RTL on mobile - webcam not centered
2023-09-26 17:50:26 -03:00
Ramón Souza
410ca25d01 remove cameraDock margin in rtl 2023-09-26 09:24:59 -03:00
AtilaU19
f1dbc8a8eb feat(reactions): port new reations 2023-09-18 19:02:21 -03:00
Arthurk12
f92d3a1ca5 fix(user-list): center icons on safari
Centers icons indicating presenter, audio state and whiteboard access in the
user list.
2023-09-12 17:06:32 -03:00
imdt
7bce5cf45a Changes to layout toast's workflow 2023-09-12 10:42:55 -03:00
Gustavo Trott
c8668bcfe2 fix: None.get error on change user Emoji 2023-09-01 09:23:01 -03:00
Anton Georgiev
66902996dc
build(etherpad): Bump Etherpad to 1.9.2 2023-08-17 13:38:06 -04:00
2960 changed files with 116658 additions and 151615 deletions

View File

@ -16,8 +16,8 @@ HOW TO WRITE A GOOD PULL REQUEST?
--> -->
### What does this PR do? ### What does this PR do?
<!-- A brief description of each change being made with this pull request. -->
<!-- A brief description of each change being made with this pull request. -->
### Closes Issue(s) ### Closes Issue(s)
<!-- List here all the issues closed by this pull request. Use keyword `closes` before each issue number <!-- List here all the issues closed by this pull request. Use keyword `closes` before each issue number
@ -25,18 +25,12 @@ Closes #123456
--> -->
Closes # Closes #
### Motivation ### Motivation
<!-- What inspired you to submit this pull request? --> <!-- What inspired you to submit this pull request? -->
### How to test
<!-- List here everything that is necessary for the reviewer to be able to test it completely (docs link, step-by-step, bug cases)
- Is there any specific setup needed, different than the default?
- The linked issue contains all necessary content?
- Have you found any different case that might be tested when you were fixing/implementing it?
-->
### More ### More
<!-- Anything else we should know when reviewing? --> <!-- Anything else we should know when reviewing? -->
- [ ] Added/updated documentation - [ ] Added/updated documentation

View File

@ -1,9 +1,12 @@
name: Merge branches name: Merge branches
on:
workflow_call:
runs: runs:
using: composite using: "composite"
steps: steps:
- name: Checkout ${{ github.event.pull_request.base.ref || 'master' }} - name: Checkout ${{ github.event.pull_request.base.ref || 'master' }}
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
ref: ${{ github.event.pull_request.base.ref || '' }} ref: ${{ github.event.pull_request.base.ref || '' }}
fetch-depth: 0 # Fetch all history fetch-depth: 0 # Fetch all history

View File

@ -1,36 +0,0 @@
name: Upload blob report
description: Merge and upload the blob report to GitHub Actions Artifacts
runs:
using: composite
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- name: Install dependencies
shell: bash
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@v4
with:
name: all-blob-reports
path: bigbluebutton-tests/playwright/all-blob-reports
- name: Merge into HTML Report
shell: bash
working-directory: ./bigbluebutton-tests/playwright
run: npx playwright merge-reports --reporter html ./all-blob-reports
- name: Upload HTML tests report
uses: actions/upload-artifact@v4
with:
name: tests-report
overwrite: true
path: |
bigbluebutton-tests/playwright/playwright-report
bigbluebutton-tests/playwright/test-results

7
.github/config.yml vendored
View File

@ -1,7 +0,0 @@
# Configuration for new-pr-welcome - https://github.com/behaviorbot/new-pr-welcome
# Comment to be posted to on PRs from first time contributors in your repository
newPRWelcomeComment: >
Thank you for this contribution!
Could you please confirm if you already sent in the signed Contributor License Agreement? See https://docs.bigbluebutton.org/support/faq.html#why-do-i-need-to-sign-a-contributor-license-agreement-to-contribute-source-code
Thanks in advance!

106
.github/dependabot.yml vendored
View File

@ -1,106 +0,0 @@
version: 2
updates:
# maintaining legacy branch
# no configuration for now
# current branch
## excluding bigbluebutton-tests/playwright, bigbluebutton-tests/puppeteer, docs
- package-ecosystem: npm
directory: "/bbb-export-annotations"
target-branch: "v2.7.x-release"
schedule:
interval: daily
open-pull-requests-limit: 0 # zero means only security pull requests and no (optional) version updates
- package-ecosystem: npm
directory: "/bigbluebutton-html5"
target-branch: "v2.7.x-release"
schedule:
interval: daily
open-pull-requests-limit: 0 # zero means only security pull requests and no (optional) version updates
- package-ecosystem: npm
directory: "/bbb-learning-dashboard"
target-branch: "v2.7.x-release"
schedule:
interval: daily
open-pull-requests-limit: 0 # zero means only security pull requests and no (optional) version updates
- package-ecosystem: gradle
directory: "/bigbluebutton-web"
target-branch: "v2.7.x-release"
schedule:
interval: daily
open-pull-requests-limit: 0 # zero means only security pull requests and no (optional) version updates
- package-ecosystem: bundler
directory: "/record-and-playback/core"
target-branch: "v2.7.x-release"
schedule:
interval: daily
open-pull-requests-limit: 0 # zero means only security pull requests and no (optional) version updates
vendor: true
- package-ecosystem: maven
directory: "/bbb-fsesl-client"
target-branch: "v2.7.x-release"
schedule:
interval: daily
open-pull-requests-limit: 0 # zero means only security pull requests and no (optional) version updates
# upcoming release branch
## excluding bigbluebutton-tests/playwright, bigbluebutton-tests/puppeteer, docs, bbb-graphql-client-test
- package-ecosystem: npm
directory: "/bbb-graphql-actions"
target-branch: "v3.0.x-release"
schedule:
interval: daily
open-pull-requests-limit: 20 # both security and versions updates
- package-ecosystem: npm
directory: "/bbb-export-annotations"
target-branch: "v3.0.x-release"
schedule:
interval: daily
open-pull-requests-limit: 20 # both security and versions updates
- package-ecosystem: npm
directory: "/bigbluebutton-html5"
target-branch: "v3.0.x-release"
schedule:
interval: daily
open-pull-requests-limit: 20 # both security and versions updates
- package-ecosystem: npm
directory: "/bbb-learning-dashboard"
target-branch: "v3.0.x-release"
schedule:
interval: daily
open-pull-requests-limit: 20 # both security and versions updates
- package-ecosystem: gradle
directory: "/bigbluebutton-web"
target-branch: "v3.0.x-release"
schedule:
interval: daily
open-pull-requests-limit: 20 # both security and versions updates
- package-ecosystem: bundler
directory: "/record-and-playback/core"
target-branch: "v3.0.x-release"
schedule:
interval: daily
open-pull-requests-limit: 20 # both security and versions updates
- package-ecosystem: maven
directory: "/bbb-fsesl-client"
target-branch: "v3.0.x-release"
schedule:
interval: daily
open-pull-requests-limit: 20 # both security and versions updates
- package-ecosystem: gomod
directory: "/bbb-graphql-middleware"
target-branch: "v3.0.x-release"
schedule:
interval: daily
open-pull-requests-limit: 20 # both security and versions updates
- package-ecosystem: gomod
directory: "/bbb-graphql-server"
target-branch: "v3.0.x-release"
schedule:
interval: daily
open-pull-requests-limit: 20 # both security and versions updates
# upstream (default) branch
# no configuration for now

View File

@ -1,123 +0,0 @@
name: Automated tests - publish results
on:
workflow_run:
workflows:
- Automated tests
types:
- completed
- requested
env:
isCompleted: ${{ github.event.workflow_run.status == 'completed' }}
jobs:
get-pr-data:
runs-on: ubuntu-latest
concurrency:
group: github-api-request
cancel-in-progress: false
if: ${{ github.event.workflow_run.event == 'pull_request' }}
outputs:
pr-number: ${{ steps.pr.outputs.result || steps.set-env.outputs.pr-number }}
workflow-id: ${{ github.event.workflow_run.id || steps.set-env.outputs.workflow-id }}
steps:
- name: Find associated pull request
if: ${{ !fromJson(env.isCompleted) }}
id: pr
uses: actions/github-script@v7
with:
script: |
const response = await github.rest.search.issuesAndPullRequests({
q: 'repo:${{ github.repository }} is:pr sha:${{ github.event.workflow_run.head_sha }}',
per_page: 1,
})
const items = response.data.items
if (items.length < 1) {
console.error('No PRs found')
return
}
const pullRequestNumber = items[0].number
return pullRequestNumber
- name: Download PR artifact
if: ${{ fromJson(env.isCompleted) }}
uses: actions/github-script@v7
with:
script: |
try {
let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.payload.workflow_run.id,
});
let matchArtifact = allArtifacts.data.artifacts.filter((artifact) => {
return artifact.name == "pr-comment-data"
})[0];
let download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: matchArtifact.id,
archive_format: 'zip',
});
let fs = require('fs');
fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/pr-comment-data.zip`, Buffer.from(download.data));
} catch (error) {
console.log('No artifact found');
}
- name: Unzip artifact
if: ${{ fromJson(env.isCompleted) }}
run: unzip pr-comment-data.zip
- name: Set env variables from artifact
if: ${{ fromJson(env.isCompleted) }}
id: set-env
run: |
echo "pr-number=$(cat ./pr_number)" >> $GITHUB_OUTPUT
echo "workflow-id=$(cat ./workflow_id)" >> $GITHUB_OUTPUT
comment-pr:
runs-on: ubuntu-latest
permissions:
pull-requests: write
needs: get-pr-data
steps:
- name: Find Comment
uses: peter-evans/find-comment@v3
id: fc
with:
issue-number: ${{ needs.get-pr-data.outputs.pr-number }}
comment-author: "github-actions[bot]"
body-includes: Automated tests Summary
- name: Remove previous comment
if: steps.fc.outputs.comment-id != ''
uses: actions/github-script@v7
with:
script: |
github.rest.issues.deleteComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: ${{ steps.fc.outputs.comment-id }}
})
- name: In progress tests comment
if: ${{ !fromJson(env.isCompleted) }}
uses: peter-evans/create-or-update-comment@v4
with:
issue-number: ${{ needs.get-pr-data.outputs.pr-number }}
body: |
<h1>Automated tests Summary</h1>
<h3><strong>:hourglass_flowing_sand:</strong> Tests are running...</h3>
- name: Passing tests comment
if: ${{ github.event.workflow_run.conclusion == 'success' }}
uses: peter-evans/create-or-update-comment@v4
with:
issue-number: ${{ needs.get-pr-data.outputs.pr-number }}
body: |
<h1>Automated tests Summary</h1>
<h3><strong>:white_check_mark:</strong> All the CI tests have passed!</h3>
- name: Failing tests comment
if: ${{ github.event.workflow_run.conclusion != 'success' && fromJson(env.isCompleted) }}
uses: peter-evans/create-or-update-comment@v4
with:
issue-number: ${{ needs.get-pr-data.outputs.pr-number }}
body: |
<h1> Automated tests Summary</h1>
<h3><strong>:rotating_light:</strong> Test workflow has failed</h3>
___
[Click here](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ needs.get-pr-data.outputs.workflow-id }}) to check the action test reports

View File

@ -8,7 +8,6 @@ on:
paths-ignore: paths-ignore:
- "docs/**" - "docs/**"
- "**/*.md" - "**/*.md"
- "bigbluebutton-html5/public/locales/*.json"
pull_request: pull_request:
types: [opened, synchronize, reopened] types: [opened, synchronize, reopened]
paths-ignore: paths-ignore:
@ -33,7 +32,6 @@ jobs:
bbb-export-annotations, bbb-export-annotations,
bbb-learning-dashboard, bbb-learning-dashboard,
bbb-playback-record, bbb-playback-record,
bbb-graphql-server,
bbb-etherpad, bbb-etherpad,
bbb-web, bbb-web,
bbb-fsesl-akka, bbb-fsesl-akka,
@ -53,9 +51,6 @@ jobs:
cache-files-list: bbb-learning-dashboard cache-files-list: bbb-learning-dashboard
- package: bbb-playback-record - package: bbb-playback-record
build-list: bbb-playback bbb-playback-notes bbb-playback-podcast bbb-playback-presentation bbb-playback-screenshare bbb-playback-video bbb-record-core build-list: bbb-playback bbb-playback-notes bbb-playback-podcast bbb-playback-presentation bbb-playback-screenshare bbb-playback-video bbb-record-core
- package: bbb-graphql-server
build-name: bbb-graphql-server
build-list: bbb-graphql-server bbb-graphql-middleware bbb-graphql-actions
- package: bbb-etherpad - package: bbb-etherpad
cache-files-list: bbb-etherpad.placeholder.sh cache-files-list: bbb-etherpad.placeholder.sh
cache-urls-list: https://api.github.com/repos/mconf/ep_pad_ttl/commits https://api.github.com/repos/alangecker/bbb-etherpad-plugin/commits https://api.github.com/repos/mconf/ep_redis_publisher/commits https://api.github.com/repos/alangecker/bbb-etherpad-skin/commits cache-urls-list: https://api.github.com/repos/mconf/ep_pad_ttl/commits https://api.github.com/repos/alangecker/bbb-etherpad-plugin/commits https://api.github.com/repos/mconf/ep_redis_publisher/commits https://api.github.com/repos/alangecker/bbb-etherpad-skin/commits
@ -64,7 +59,7 @@ jobs:
- package: bbb-fsesl-akka - package: bbb-fsesl-akka
cache-files-list: akka-bbb-fsesl bbb-common-message cache-files-list: akka-bbb-fsesl bbb-common-message
- package: bbb-html5 - package: bbb-html5
build-list: bbb-html5 build-list: bbb-html5-nodejs bbb-html5
cache-files-list: bigbluebutton-html5 cache-files-list: bigbluebutton-html5
- package: bbb-freeswitch - package: bbb-freeswitch
build-list: bbb-freeswitch-core bbb-freeswitch-sounds build-list: bbb-freeswitch-core bbb-freeswitch-sounds
@ -74,9 +69,9 @@ jobs:
build-list: bbb-webrtc-sfu bbb-webrtc-recorder build-list: bbb-webrtc-sfu bbb-webrtc-recorder
cache-files-list: bbb-webrtc-sfu.placeholder.sh bbb-webrtc-recorder.placeholder.sh cache-files-list: bbb-webrtc-sfu.placeholder.sh bbb-webrtc-recorder.placeholder.sh
- package: others - package: others
build-list: bbb-mkclean bbb-pads bbb-libreoffice-docker bbb-transcription-controller bigbluebutton bbb-livekit build-list: bbb-mkclean bbb-pads bbb-libreoffice-docker bbb-transcription-controller bigbluebutton
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- name: Merge branches - name: Merge branches
uses: ./.github/actions/merge-branches uses: ./.github/actions/merge-branches
- name: Set cache-key vars - name: Set cache-key vars
@ -91,7 +86,7 @@ jobs:
- name: Handle cache - name: Handle cache
if: matrix.cache-files-list != '' if: matrix.cache-files-list != ''
id: cache-action id: cache-action
uses: actions/cache@v4 uses: actions/cache@v3
with: with:
path: artifacts.tar path: artifacts.tar
key: ${{ runner.os }}-${{ matrix.package }}-${{ env.BIGBLUEBUTTON_RELEASE }}-commits-${{ env.CACHE_KEY_FILES }}-urls-${{ env.CACHE_KEY_URLS }} key: ${{ runner.os }}-${{ matrix.package }}-${{ env.BIGBLUEBUTTON_RELEASE }}-commits-${{ env.CACHE_KEY_FILES }}-urls-${{ env.CACHE_KEY_URLS }}
@ -103,87 +98,79 @@ jobs:
echo "${{ matrix.build-list || matrix.package }}" | xargs -n 1 ./build/setup.sh echo "${{ matrix.build-list || matrix.package }}" | xargs -n 1 ./build/setup.sh
tar cvf artifacts.tar artifacts/ tar cvf artifacts.tar artifacts/
- name: Archive packages - name: Archive packages
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v3
with: with:
name: artifacts_${{ matrix.package }}.tar name: artifacts_${{ matrix.package }}.tar
path: artifacts.tar path: artifacts.tar
install-and-run-tests: install-and-run-tests:
needs: build-package needs: build-package
runs-on: ubuntu-22.04 runs-on: ubuntu-20.04
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
shard: [1, 2, 3, 4, 5, 6, 7, 8] shard: [1/8, 2/8, 3/8, 4/8, 5/8, 6/8, 7/8, 8/8]
env:
shard: ${{ matrix.shard }}/8
MATRIX_SHARD_UNDERSCORED: ${{ matrix.shard }}_8
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- name: Merge branches - name: Merge branches
uses: ./.github/actions/merge-branches uses: ./.github/actions/merge-branches
- run: ./build/get_external_dependencies.sh - run: ./build/get_external_dependencies.sh
- name: Download artifacts_bbb-apps-akka - name: Download artifacts_bbb-apps-akka
uses: actions/download-artifact@v4 uses: actions/download-artifact@v3
with: with:
name: artifacts_bbb-apps-akka.tar name: artifacts_bbb-apps-akka.tar
- run: tar xf artifacts.tar - run: tar xf artifacts.tar
- name: Download artifacts_bbb-config - name: Download artifacts_bbb-config
uses: actions/download-artifact@v4 uses: actions/download-artifact@v3
with: with:
name: artifacts_bbb-config.tar name: artifacts_bbb-config.tar
- run: tar xf artifacts.tar - run: tar xf artifacts.tar
- name: Download artifacts_bbb-export-annotations - name: Download artifacts_bbb-export-annotations
uses: actions/download-artifact@v4 uses: actions/download-artifact@v3
with: with:
name: artifacts_bbb-export-annotations.tar name: artifacts_bbb-export-annotations.tar
- run: tar xf artifacts.tar - run: tar xf artifacts.tar
- name: Download artifacts_bbb-learning-dashboard - name: Download artifacts_bbb-learning-dashboard
uses: actions/download-artifact@v4 uses: actions/download-artifact@v3
with: with:
name: artifacts_bbb-learning-dashboard.tar name: artifacts_bbb-learning-dashboard.tar
- run: tar xf artifacts.tar - run: tar xf artifacts.tar
- name: Download artifacts_bbb-playback-record - name: Download artifacts_bbb-playback-record
uses: actions/download-artifact@v4 uses: actions/download-artifact@v3
with: with:
name: artifacts_bbb-playback-record.tar name: artifacts_bbb-playback-record.tar
- run: tar xf artifacts.tar - run: tar xf artifacts.tar
- name: Download artifacts_bbb-graphql-server
uses: actions/download-artifact@v4
with:
name: artifacts_bbb-graphql-server.tar
- run: tar xf artifacts.tar
- name: Download artifacts_bbb-etherpad - name: Download artifacts_bbb-etherpad
uses: actions/download-artifact@v4 uses: actions/download-artifact@v3
with: with:
name: artifacts_bbb-etherpad.tar name: artifacts_bbb-etherpad.tar
- run: tar xf artifacts.tar - run: tar xf artifacts.tar
- name: Download artifacts_bbb-freeswitch - name: Download artifacts_bbb-freeswitch
uses: actions/download-artifact@v4 uses: actions/download-artifact@v3
with: with:
name: artifacts_bbb-freeswitch.tar name: artifacts_bbb-freeswitch.tar
- run: tar xf artifacts.tar - run: tar xf artifacts.tar
- name: Download artifacts_bbb-webrtc - name: Download artifacts_bbb-webrtc
uses: actions/download-artifact@v4 uses: actions/download-artifact@v3
with: with:
name: artifacts_bbb-webrtc.tar name: artifacts_bbb-webrtc.tar
- run: tar xf artifacts.tar - run: tar xf artifacts.tar
- name: Download artifacts_bbb-web - name: Download artifacts_bbb-web
uses: actions/download-artifact@v4 uses: actions/download-artifact@v3
with: with:
name: artifacts_bbb-web.tar name: artifacts_bbb-web.tar
- run: tar xf artifacts.tar - run: tar xf artifacts.tar
- name: Download artifacts_bbb-fsesl-akka - name: Download artifacts_bbb-fsesl-akka
uses: actions/download-artifact@v4 uses: actions/download-artifact@v3
with: with:
name: artifacts_bbb-fsesl-akka.tar name: artifacts_bbb-fsesl-akka.tar
- run: tar xf artifacts.tar - run: tar xf artifacts.tar
- name: Download artifacts_bbb-html5 - name: Download artifacts_bbb-html5
uses: actions/download-artifact@v4 uses: actions/download-artifact@v3
with: with:
name: artifacts_bbb-html5.tar name: artifacts_bbb-html5.tar
- run: tar xf artifacts.tar - run: tar xf artifacts.tar
- name: Download artifacts - name: Download artifacts
uses: actions/download-artifact@v4 uses: actions/download-artifact@v3
with: with:
name: artifacts_others.tar name: artifacts_others.tar
- run: tar xf artifacts.tar - run: tar xf artifacts.tar
@ -257,78 +244,15 @@ jobs:
apt --purge -y remove apache2-bin apt --purge -y remove apache2-bin
' '
- name: Install BBB - name: Install BBB
env:
NODE_EXTRA_CA_CERTS: /usr/local/share/ca-certificates/bbb-dev/bbb-dev-ca.crt
ACTIONS_RUNNER_DEBUG: true
run: |
sudo -i <<'EOF'
set -e
cd /root/
wget -nv https://raw.githubusercontent.com/bigbluebutton/bbb-install/v3.0.x-release--no-mongo/bbb-install.sh -O bbb-install.sh
sed -i "s|> /etc/apt/sources.list.d/bigbluebutton.list||g" bbb-install.sh
chmod +x bbb-install.sh
COMMAND="./bbb-install.sh -v jammy-30-dev -s bbb-ci.test -j -d /certs/"
TIMEOUT=1500 # 25 minutes
MAX_RETRIES=3
RETRY_INTERVAL=60
RETRY_COUNT=0
SUCCESS=0
while [[ $RETRY_COUNT -lt $MAX_RETRIES ]]; do
echo "Attempt $((RETRY_COUNT + 1)) of $MAX_RETRIES to install BBB..."
# Run the command with timeout and handle its exit code
# Capture both stdout and stderr
COMMAND_EXIT_CODE=0
timeout $TIMEOUT $COMMAND || COMMAND_EXIT_CODE=$?
if [[ $COMMAND_EXIT_CODE -eq 0 ]]; then
SUCCESS=1
break
elif [[ $COMMAND_EXIT_CODE -eq 124 ]]; then
echo "Installation timed out after ${TIMEOUT} seconds. Retrying..."
else
echo "Installation failed with exit code $COMMAND_EXIT_CODE"
echo "Retrying installation within $RETRY_INTERVAL seconds..."
sleep $RETRY_INTERVAL
fi
echo "Stop any ongoing processes related to apt-get or dpkg that might be stuck"
# Use -q to suppress "no process found" messages
killall -q apt-get || true
killall -q dpkg || true
echo "Remove the lock files that may have been left behind"
# Group lock file removal for better readability
rm -f /var/lib/dpkg/lock-frontend
rm -f /var/lib/dpkg/lock
rm -f /var/cache/apt/archives/lock
echo "Reconfigure the package manager"
dpkg --configure -a
echo "Clean up any partially installed packages"
apt-get clean
apt-get autoremove
RETRY_COUNT=$((RETRY_COUNT + 1))
done
if [[ $SUCCESS -eq 0 ]]; then
echo "All attempts to install BBB failed."
exit 1
fi
bbb-conf --salt bbbci
sed -i "s/\"minify\": true,/\"minify\": false,/" /usr/share/etherpad-lite/settings.json
sudo yq e -i '.log_level = "TRACE"' /usr/share/bbb-graphql-middleware/config.yml
bbb-conf --restart
EOF
- name: List systemctl services
timeout-minutes: 1
run: | run: |
sudo -i <<EOF sudo -i <<EOF
systemctl --type=service --state=running,exited,failed --all --no-pager --no-legend set -e
cd /root/ && wget -nv https://raw.githubusercontent.com/bigbluebutton/bbb-install/v2.7.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 focal-27-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 EOF
- name: Install test dependencies - name: Install test dependencies
working-directory: ./bigbluebutton-tests/playwright working-directory: ./bigbluebutton-tests/playwright
@ -339,18 +263,13 @@ jobs:
npx playwright install npx playwright install
' '
- name: Run tests - name: Run tests
uses: nick-fields/retry@v3 working-directory: ./bigbluebutton-tests/playwright
with:
timeout_minutes: 25
max_attempts: 2
command: |
cd ./bigbluebutton-tests/playwright
npm run test-chromium-ci -- --shard ${{ env.shard }}
env: env:
NODE_EXTRA_CA_CERTS: /usr/local/share/ca-certificates/bbb-dev/bbb-dev-ca.crt NODE_EXTRA_CA_CERTS: /usr/local/share/ca-certificates/bbb-dev/bbb-dev-ca.crt
ACTIONS_RUNNER_DEBUG: true ACTIONS_RUNNER_DEBUG: true
BBB_URL: https://bbb-ci.test/bigbluebutton/api BBB_URL: https://bbb-ci.test/bigbluebutton/api
BBB_SECRET: bbbci BBB_SECRET: bbbci
run: npm run test-chromium-ci -- --shard ${{ matrix.shard }}
- name: Run Firefox tests - name: Run Firefox tests
working-directory: ./bigbluebutton-tests/playwright working-directory: ./bigbluebutton-tests/playwright
if: | if: |
@ -365,13 +284,13 @@ jobs:
run: | run: |
sh -c ' sh -c '
find $HOME/.cache/ms-playwright -name libnssckbi.so -exec rm {} \; -exec ln -s /usr/lib/x86_64-linux-gnu/pkcs11/p11-kit-trust.so {} \; find $HOME/.cache/ms-playwright -name libnssckbi.so -exec rm {} \; -exec ln -s /usr/lib/x86_64-linux-gnu/pkcs11/p11-kit-trust.so {} \;
npm run test-firefox-ci -- --shard ${{ env.shard }} npm run test-firefox-ci -- --shard ${{ matrix.shard }}
' '
- if: always() - if: always() && github.event_name == 'pull_request'
name: Upload blob report to GitHub Actions Artifacts name: Upload blob report to GitHub Actions Artifacts
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v3
with: with:
name: blob-report-${{ matrix.shard }} name: all-blob-reports
path: bigbluebutton-tests/playwright/blob-report path: bigbluebutton-tests/playwright/blob-report
- if: failure() - if: failure()
name: Prepare artifacts (configs and logs) name: Prepare artifacts (configs and logs)
@ -399,31 +318,42 @@ jobs:
ls -t /root/*.tar.gz | head -1 | xargs -I '{}' cp '{}' /home/runner/work/bigbluebutton/bigbluebutton/bbb-logs.tar.gz ls -t /root/*.tar.gz | head -1 | xargs -I '{}' cp '{}' /home/runner/work/bigbluebutton/bigbluebutton/bbb-logs.tar.gz
EOF EOF
- if: failure() - if: failure()
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v3
with: with:
name: bbb-configs-${{ env.MATRIX_SHARD_UNDERSCORED }} name: bbb-configs
path: configs path: configs
- if: failure() - if: failure()
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v3
with: with:
name: bbb-logs-${{ env.MATRIX_SHARD_UNDERSCORED }} name: bbb-logs
path: ./bbb-logs.tar.gz path: ./bbb-logs.tar.gz
upload-report: upload-report:
if: always() && !contains(github.event.head_commit.message, 'Merge pull request') if: always()
needs: install-and-run-tests needs: install-and-run-tests
runs-on: ubuntu-latest runs-on: ubuntu-latest
env:
hasReportData: ${{ needs.install-and-run-tests.result == 'success' || needs.install-and-run-tests.result == 'failure' }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- name: Upload blob report - uses: actions/setup-node@v3
if: ${{ env.hasReportData }} with:
uses: ./.github/actions/upload-blob-report node-version: 18
- name: Remove unnecessary artifact - name: Install dependencies
uses: geekyeggo/delete-artifact@v5 working-directory: ./bigbluebutton-tests/playwright
run: npm ci
- name: Download all blob reports from GitHub Actions Artifacts
uses: actions/download-artifact@v3
with: with:
name: all-blob-reports name: all-blob-reports
failOnError: false path: bigbluebutton-tests/playwright/all-blob-reports
- name: Merge into HTML Report
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
with:
name: tests-report
path: |
bigbluebutton-tests/playwright/playwright-report
bigbluebutton-tests/playwright/test-results
- name: Write PR data for auto-comment - name: Write PR data for auto-comment
if: github.event_name == 'pull_request' if: github.event_name == 'pull_request'
working-directory: ./ working-directory: ./
@ -433,7 +363,7 @@ jobs:
echo ${{ github.run_id }} > ./pr-comment-data/workflow_id echo ${{ github.run_id }} > ./pr-comment-data/workflow_id
- name: Upload PR data for auto-comment - name: Upload PR data for auto-comment
if: github.event_name == 'pull_request' if: github.event_name == 'pull_request'
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v3
with: with:
name: pr-comment-data name: pr-comment-data
path: pr-comment-data path: pr-comment-data

View File

@ -12,18 +12,15 @@ permissions:
jobs: jobs:
main: main:
permissions: permissions:
pull-requests: write # for eps1lon/actions-label-merge-conflict to label PRs pull-requests: write # for eps1lon/actions-label-merge-conflict to label PRs
runs-on: ubuntu-latest runs-on: ubuntu-latest
concurrency:
group: github-api-request
cancel-in-progress: false
steps: steps:
- name: Check for dirty pull requests - name: Check for dirty pull requests
uses: eps1lon/actions-label-merge-conflict@v3 uses: eps1lon/actions-label-merge-conflict@releases/2.x
with: with:
dirtyLabel: "status: conflict" dirtyLabel: "status: conflict"
repoToken: "${{ secrets.GITHUB_TOKEN }}" repoToken: "${{ secrets.GITHUB_TOKEN }}"
commentOnDirty: | commentOnDirty: |
This pull request has conflicts ☹ This pull request has conflicts ☹
Please resolve those so we can review the pull request. Please resolve those so we can review the pull request.
Thanks. Thanks.

View File

@ -7,6 +7,7 @@ on:
- 'develop' - 'develop'
paths: paths:
- 'docs/**' - 'docs/**'
- '.github/**'
# Do not build the docs concurrently # Do not build the docs concurrently
concurrency: concurrency:
@ -22,20 +23,20 @@ jobs:
working-directory: ./docs working-directory: ./docs
steps: steps:
# Setup # Setup
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- uses: actions/setup-node@v4 - uses: actions/setup-node@v3
with: with:
node-version: 20 node-version: 18
cache: npm cache: yarn
cache-dependency-path: ./docs/package-lock.json cache-dependency-path: ./docs/yarn.lock
- name: Install dependencies - name: Install dependencies
run: npm ci run: yarn install --frozen-lockfile
# Build static docs # Build static docs
- name: Build all versions - name: Build all versions
run: ./build.sh run: ./build.sh
- name: Build website - name: Build website
run: npm run docusaurus build run: yarn build
- name: upload build artifact - name: upload build artifact
uses: actions/upload-pages-artifact@v1 uses: actions/upload-pages-artifact@v1
with: with:

View File

@ -1,36 +0,0 @@
name: Typescript - compile code
on:
push:
branches:
- "develop"
- "v2.[5-9].x-release"
- "v[3-9].*.x-release"
paths:
- "bigbluebutton-html5/**.ts"
- "bigbluebutton-html5/**.tsx"
- "bigbluebutton-html5/package.json"
- "bigbluebutton-html5/package-lock.json"
pull_request:
types: [opened, synchronize, reopened]
paths:
- "bigbluebutton-html5/**.ts"
- "bigbluebutton-html5/**.tsx"
- "bigbluebutton-html5/package.json"
- "bigbluebutton-html5/package-lock.json"
permissions:
contents: read
jobs:
ts-code-compilation:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Merge branches
uses: ./.github/actions/merge-branches
- name: run npm ci
working-directory: bigbluebutton-html5
run: npm ci
- name: typescript code compilation
working-directory: bigbluebutton-html5
run: npx tsc

View File

@ -1,36 +0,0 @@
name: Typescript - validate code (eslint)
on:
push:
branches:
- "develop"
- "v2.[5-9].x-release"
- "v[3-9].*.x-release"
paths:
- "bigbluebutton-html5/**.ts"
- "bigbluebutton-html5/**.tsx"
- "bigbluebutton-html5/package.json"
- "bigbluebutton-html5/package-lock.json"
pull_request:
types: [opened, synchronize, reopened]
paths:
- "bigbluebutton-html5/**.ts"
- "bigbluebutton-html5/**.tsx"
- "bigbluebutton-html5/package.json"
- "bigbluebutton-html5/package-lock.json"
permissions:
contents: read
jobs:
ts-code-validation:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Merge branches
uses: ./.github/actions/merge-branches
- name: install npm dependencies
working-directory: bigbluebutton-html5
run: npm ci
- name: typescript code validation with eslint
working-directory: bigbluebutton-html5
run: npx eslint . --ext .ts,.tsx

3
.gitignore vendored
View File

@ -23,6 +23,3 @@ cache/*
artifacts/* artifacts/*
bbb-presentation-video.zip bbb-presentation-video.zip
bbb-presentation-video bbb-presentation-video
bbb-graphql-actions-adapter-server/
bigbluebutton-html5/public/locales/index.json
node_modules

View File

@ -12,7 +12,7 @@ stages:
# define which docker image to use for builds # define which docker image to use for builds
default: default:
image: bigbluebutton/bbb-build:v3.0.x-release--2024-08-30-014114 image: bigbluebutton/bbb-build:bbb27-2023-06-13-java17
# This stage uses git to find out since when each package has been unmodified. # This stage uses git to find out since when each package has been unmodified.
# it then checks an API endpoint on the package server to find out for which of # it then checks an API endpoint on the package server to find out for which of
@ -102,16 +102,6 @@ bbb-html5-build:
script: script:
- build/setup-inside-docker.sh bbb-html5 - build/setup-inside-docker.sh bbb-html5
bbb-graphql-middleware-build:
extends: .build_job
script:
- build/setup-inside-docker.sh bbb-graphql-middleware
bbb-graphql-server-build:
extends: .build_job
script:
- build/setup-inside-docker.sh bbb-graphql-server
bbb-learning-dashboard-build: bbb-learning-dashboard-build:
extends: .build_job extends: .build_job
script: script:
@ -122,6 +112,11 @@ bbb-libreoffice-docker-build:
script: script:
- build/setup-inside-docker.sh bbb-libreoffice-docker - build/setup-inside-docker.sh bbb-libreoffice-docker
bbb-lti-build:
extends: .build_job
script:
- build/setup-inside-docker.sh bbb-lti
bbb-mkclean-build: bbb-mkclean-build:
extends: .build_job extends: .build_job
script: script:
@ -182,11 +177,6 @@ bbb-webrtc-recorder-build:
script: script:
- build/setup-inside-docker.sh bbb-webrtc-recorder - build/setup-inside-docker.sh bbb-webrtc-recorder
bbb-livekit:
extends: .build_job
script:
- build/setup-inside-docker.sh bbb-livekit
bbb-transcription-controller-build: bbb-transcription-controller-build:
extends: .build_job extends: .build_job
script: script:

View File

@ -1,20 +1,20 @@
BigBlueButton BigBlueButton
============= =============
BigBlueButton is an open-source virtual classroom designed to help teachers teach and learners learn. BigBlueButton is an open source web conferencing system.
BigBlueButton supports real-time sharing of audio, video, slides (with whiteboard annotations), chat, and the screen. Instructors can engage remote students with polling, emojis, multi-user whiteboards, shared notes, and breakout rooms. During the session, BigBlueButton generates analytics that are visible to moderators in the Learning Analytics Dashboard. BigBlueButton supports real-time sharing of audio, video, slides (with whiteboard controls), chat, and the screen. Instructors can engage remote students with polling, emojis, multi-user whiteboard, and breakout rooms.
Presenters can record and playback content for later sharing with others. Presenters can record and playback content for later sharing with others.
We designed BigBlueButton for online learning, it can be used for many other applications as well. The educational use cases for BigBlueButton are We designed BigBlueButton for online learning, (though it can be used for many [other applications](https://www.c4isrnet.com/it-networks/2015/02/11/disa-to-replace-dco-with-new-collaboration-services-tool/) as well). The educational use cases for BigBlueButton are
* Online tutoring (one-to-one) * Online tutoring (one-to-one)
* Flipped classrooms (recording content ahead of your session) * Flipped classrooms (recording content ahead of your session)
* Group collaboration (many-to-many) * Group collaboration (many-to-many)
* Online classes (one-to-many) * Online classes (one-to-many)
The latest version is BigBlueButton 2.7. You can install BigBlueButton 2.7 on Ubuntu 20.04 using [bbb-install.sh](https://github.com/bigbluebutton/bbb-install) within 30 minutes (or your money back 😉). You can install on a Ubuntu 20.04 64-bit server. We provide [bbb-install.sh](https://github.com/bigbluebutton/bbb-install) to let you have a server up and running within 30 minutes (or your money back 😉).
For full technical documentation of BigBlueButton -- including architecture, features, API, and GreenLight (the default front-end) -- see [https://docs.bigbluebutton.org/](https://docs.bigbluebutton.org/). For full technical documentation BigBlueButton -- including architecture, features, API, and GreenLight (the default front-end) -- see [https://docs.bigbluebutton.org/](https://docs.bigbluebutton.org/).
BigBlueButton and the BigBlueButton Logo are trademarks of [BigBlueButton Inc](https://bigbluebutton.org). BigBlueButton and the BigBlueButton Logo are trademarks of [BigBlueButton Inc](https://bigbluebutton.org) .

View File

@ -9,7 +9,7 @@ We actively support BigBlueButton through the community forums and through secur
| 2.5.x (or earlier) | :x: | | 2.5.x (or earlier) | :x: |
| 2.6.x   | :white_check_mark: | | 2.6.x   | :white_check_mark: |
| 2.7.x   | :white_check_mark: | | 2.7.x   | :white_check_mark: |
| 3.0.x   | :x: | | 2.8.x   | :x: |
We have released 2.7 to the community and are going to support both 2.6 and 2.7 together for the coming months (while we're actively developing the next release). Also, BigBlueButton 2.5 is now end of life. We have released 2.7 to the community and are going to support both 2.6 and 2.7 together for the coming months (while we're actively developing the next release). Also, BigBlueButton 2.5 is now end of life.
@ -17,7 +17,7 @@ As such, we recommend that all administrators deploy 2.7 going forward. You'll
## Reporting a Vulnerability ## Reporting a Vulnerability
If you believe you have found a security vulnerability in BigBlueButton please let us know directly by If you believe you have found a security vunerability in BigBlueButton please let us know directly by
- using GitHub's "Report a vulnerability" functionality on https://github.com/bigbluebutton/bigbluebutton/security/advisories - using GitHub's "Report a vulnerability" functionality on https://github.com/bigbluebutton/bigbluebutton/security/advisories
- or e-mailing security@bigbluebutton.org with as much detail as possible. - or e-mailing security@bigbluebutton.org with as much detail as possible.

View File

@ -1,6 +1,7 @@
package org.bigbluebutton.build package org.bigbluebutton.build
import sbt._ import sbt._
import Keys._
object Dependencies { object Dependencies {
@ -12,8 +13,8 @@ object Dependencies {
val scalactic = "3.0.8" val scalactic = "3.0.8"
// Libraries // Libraries
val pekkoVersion = "1.0.1" val akkaVersion = "2.6.17"
val pekkoHttpVersion = "1.0.0" val akkaHttpVersion = "10.2.7"
val gson = "2.8.9" val gson = "2.8.9"
val jackson = "2.13.5" val jackson = "2.13.5"
val logback = "1.2.13" val logback = "1.2.13"
@ -27,24 +28,18 @@ object Dependencies {
// BigBlueButton // BigBlueButton
val bbbCommons = "0.0.22-SNAPSHOT" val bbbCommons = "0.0.22-SNAPSHOT"
// Database
val slick = "3.4.1"
val postgresql = "42.5.0"
val slickPg = "0.21.1"
// Test // Test
val scalaTest = "3.2.11" val scalaTest = "3.2.11"
val mockito = "2.23.0" val mockito = "2.23.0"
val akkaTestKit = "2.6.0" val akkaTestKit = "2.6.0"
val jacksonDataFormat = "2.13.5"
} }
object Compile { object Compile {
val scalaLibrary = "org.scala-lang" % "scala-library" % Versions.scala val scalaLibrary = "org.scala-lang" % "scala-library" % Versions.scala
val scalaCompiler = "org.scala-lang" % "scala-compiler" % Versions.scala val scalaCompiler = "org.scala-lang" % "scala-compiler" % Versions.scala
val pekkoActor = "org.apache.pekko" %% "pekko-actor" % Versions.pekkoVersion val akkaActor = "com.typesafe.akka" % "akka-actor_2.13" % Versions.akkaVersion
val pekkoSlf4j = "org.apache.pekko" %% "pekko-slf4j" % Versions.pekkoVersion val akkaSl4fj = "com.typesafe.akka" % "akka-slf4j_2.13" % Versions.akkaVersion
val googleGson = "com.google.code.gson" % "gson" % Versions.gson val googleGson = "com.google.code.gson" % "gson" % Versions.gson
val jacksonModule = "com.fasterxml.jackson.module" %% "jackson-module-scala" % Versions.jackson val jacksonModule = "com.fasterxml.jackson.module" %% "jackson-module-scala" % Versions.jackson
@ -53,21 +48,13 @@ object Dependencies {
val commonsCodec = "commons-codec" % "commons-codec" % Versions.codec val commonsCodec = "commons-codec" % "commons-codec" % Versions.codec
val sprayJson = "io.spray" % "spray-json_2.13" % Versions.spray val sprayJson = "io.spray" % "spray-json_2.13" % Versions.spray
val pekkoStream = "org.apache.pekko" %% "pekko-stream" % Versions.pekkoVersion val akkaStream = "com.typesafe.akka" %% "akka-stream" % Versions.akkaVersion
val pekkoHttp = "org.apache.pekko" %% "pekko-http" % Versions.pekkoHttpVersion val akkaHttp = "com.typesafe.akka" %% "akka-http" % Versions.akkaHttpVersion
val pekkoHttpSprayJson = "org.apache.pekko" %% "pekko-http-spray-json" % Versions.pekkoHttpVersion val akkaHttpSprayJson = "com.typesafe.akka" %% "akka-http-spray-json" % Versions.akkaHttpVersion
val apacheLang = "org.apache.commons" % "commons-lang3" % Versions.lang val apacheLang = "org.apache.commons" % "commons-lang3" % Versions.lang
val bbbCommons = "org.bigbluebutton" % "bbb-common-message_2.13" % Versions.bbbCommons val bbbCommons = "org.bigbluebutton" % "bbb-common-message_2.13" % Versions.bbbCommons
val slick = "com.typesafe.slick" %% "slick" % Versions.slick
val slickHikaricp = "com.typesafe.slick" %% "slick-hikaricp" % Versions.slick
val slickPg = "com.github.tminglei" %% "slick-pg" % Versions.slickPg
val slickPgSprayJson = "com.github.tminglei" %% "slick-pg_spray-json" % Versions.slickPg
val postgresql = "org.postgresql" % "postgresql" % Versions.postgresql
val jacksonDataFormat = "com.fasterxml.jackson.dataformat" % "jackson-dataformat-yaml" % Versions.jacksonDataFormat
} }
object Test { object Test {
@ -88,9 +75,9 @@ object Dependencies {
val runtime = Seq( val runtime = Seq(
Compile.scalaLibrary, Compile.scalaLibrary,
Compile.scalaCompiler, Compile.scalaCompiler,
Compile.pekkoActor, Compile.akkaActor,
Compile.pekkoSlf4j, Compile.akkaSl4fj,
Compile.pekkoStream, Compile.akkaStream,
Compile.googleGson, Compile.googleGson,
Compile.jacksonModule, Compile.jacksonModule,
Compile.quicklens, Compile.quicklens,
@ -98,13 +85,7 @@ object Dependencies {
Compile.commonsCodec, Compile.commonsCodec,
Compile.sprayJson, Compile.sprayJson,
Compile.apacheLang, Compile.apacheLang,
Compile.pekkoHttp, Compile.akkaHttp,
Compile.pekkoHttpSprayJson, Compile.akkaHttpSprayJson,
Compile.bbbCommons, Compile.bbbCommons) ++ testing
Compile.slick,
Compile.slickHikaricp,
Compile.slickPg,
Compile.slickPgSprayJson,
Compile.postgresql,
Compile.jacksonDataFormat) ++ testing
} }

View File

@ -1,13 +1,11 @@
package org.bigbluebutton package org.bigbluebutton
import org.apache.pekko.http.scaladsl.model._ import akka.http.scaladsl.model._
import org.apache.pekko.http.scaladsl.marshallers.sprayjson.SprayJsonSupport import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport
import org.apache.pekko.http.scaladsl.server.Directives._ import akka.http.scaladsl.server.Directives._
import org.bigbluebutton.common2.msgs._ import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.api.{ ApiResponseFailure, ApiResponseSuccess, UserInfosApiMsg } import org.bigbluebutton.service.{ HealthzService, MeetingInfoService, PubSubReceiveStatus, PubSubSendStatus, RecordingDBSendStatus }
import org.bigbluebutton.service.{ HealthzService, MeetingInfoService, PubSubReceiveStatus, PubSubSendStatus, RecordingDBSendStatus, UserInfoService }
import spray.json._ import spray.json._
import scala.concurrent._ import scala.concurrent._
import ExecutionContext.Implicits.global import ExecutionContext.Implicits.global
@ -65,7 +63,7 @@ trait JsonSupportProtocolMeetingInfoResponse extends SprayJsonSupport with Defau
implicit val meetingInfoResponseJsonFormat = jsonFormat1(MeetingInfoResponse) implicit val meetingInfoResponseJsonFormat = jsonFormat1(MeetingInfoResponse)
} }
class ApiService(healthz: HealthzService, meetingInfoz: MeetingInfoService, userInfoService: UserInfoService) class ApiService(healthz: HealthzService, meetingInfoz: MeetingInfoService)
extends JsonSupportProtocolHealthResponse extends JsonSupportProtocolHealthResponse
with JsonSupportProtocolMeetingInfoResponse { with JsonSupportProtocolMeetingInfoResponse {
@ -126,28 +124,5 @@ class ApiService(healthz: HealthzService, meetingInfoz: MeetingInfoService, user
} }
complete(entityFuture) complete(entityFuture)
} }
} ~
path("userInfo") {
(headerValueByName("x-session-token") & headerValueByName("user-agent")) { (sessionToken, userAgent) =>
get {
val entityFuture = userInfoService.getUserInfo(sessionToken).map {
case ApiResponseSuccess(msg, userInfos: UserInfosApiMsg) =>
val responseMap = userInfoService.generateResponseMap(userInfos)
userInfoService.createHttpResponse(StatusCodes.OK, responseMap)
case ApiResponseFailure(msg, msgId, arg) =>
userInfoService.createHttpResponse(
StatusCodes.OK,
Map(
"response" -> "unauthorized",
"message" -> msg,
"message_id" -> msgId,
)
)
}
complete(entityFuture)
}
}
} }
} }

View File

@ -1,18 +1,20 @@
package org.bigbluebutton package org.bigbluebutton
import org.apache.pekko.actor.ActorSystem import akka.actor.ActorSystem
import org.apache.pekko.event.Logging import akka.event.Logging
import org.apache.pekko.http.scaladsl.Http import akka.http.scaladsl.Http
import org.apache.pekko.stream.ActorMaterializer import akka.stream.ActorMaterializer
import org.bigbluebutton.common2.redis.{MessageSender, RedisConfig, RedisPublisher} import org.bigbluebutton.common2.redis.{ MessageSender, RedisConfig, RedisPublisher }
import org.bigbluebutton.core._ import org.bigbluebutton.core._
import org.bigbluebutton.core.bus._ import org.bigbluebutton.core.bus._
import org.bigbluebutton.core.pubsub.senders.ReceivedJsonMsgHandlerActor import org.bigbluebutton.core.pubsub.senders.ReceivedJsonMsgHandlerActor
import org.bigbluebutton.core2.AnalyticsActor import org.bigbluebutton.core2.AnalyticsActor
import org.bigbluebutton.core2.FromAkkaAppsMsgSenderActor import org.bigbluebutton.core2.FromAkkaAppsMsgSenderActor
import org.bigbluebutton.endpoint.redis.{AppsRedisSubscriberActor, ExportAnnotationsActor, GraphqlConnectionsActor, LearningDashboardActor, RedisRecorderActor} import org.bigbluebutton.endpoint.redis.AppsRedisSubscriberActor
import org.bigbluebutton.endpoint.redis.{ RedisRecorderActor, ExportAnnotationsActor }
import org.bigbluebutton.endpoint.redis.LearningDashboardActor
import org.bigbluebutton.common2.bus.IncomingJsonMessageBus import org.bigbluebutton.common2.bus.IncomingJsonMessageBus
import org.bigbluebutton.service.{HealthzService, MeetingInfoActor, MeetingInfoService, UserInfoService} import org.bigbluebutton.service.{ HealthzService, MeetingInfoActor, MeetingInfoService }
object Boot extends App with SystemConfiguration { object Boot extends App with SystemConfiguration {
@ -50,6 +52,8 @@ object Boot extends App with SystemConfiguration {
val meetingInfoService = MeetingInfoService(system, meetingInfoActorRef) val meetingInfoService = MeetingInfoService(system, meetingInfoActorRef)
val apiService = new ApiService(healthzService, meetingInfoService)
val redisRecorderActor = system.actorOf( val redisRecorderActor = system.actorOf(
RedisRecorderActor.props(system, redisConfig, healthzService), RedisRecorderActor.props(system, redisConfig, healthzService),
"redisRecorderActor" "redisRecorderActor"
@ -65,12 +69,6 @@ object Boot extends App with SystemConfiguration {
"LearningDashboardActor" "LearningDashboardActor"
) )
val graphqlConnectionsActor = system.actorOf(
GraphqlConnectionsActor.props(system, eventBus, outGW),
"GraphqlConnectionsActor"
)
ClientSettings.loadClientSettingsFromFile()
recordingEventBus.subscribe(redisRecorderActor, outMessageChannel) recordingEventBus.subscribe(redisRecorderActor, outMessageChannel)
val incomingJsonMessageBus = new IncomingJsonMessageBus val incomingJsonMessageBus = new IncomingJsonMessageBus
@ -87,15 +85,9 @@ object Boot extends App with SystemConfiguration {
outBus2.subscribe(learningDashboardActor, outBbbMsgMsgChannel) outBus2.subscribe(learningDashboardActor, outBbbMsgMsgChannel)
bbbMsgBus.subscribe(learningDashboardActor, analyticsChannel) bbbMsgBus.subscribe(learningDashboardActor, analyticsChannel)
eventBus.subscribe(graphqlConnectionsActor, meetingManagerChannel)
bbbMsgBus.subscribe(graphqlConnectionsActor, analyticsChannel)
val bbbActor = system.actorOf(BigBlueButtonActor.props(system, eventBus, bbbMsgBus, outGW, healthzService), "bigbluebutton-actor") val bbbActor = system.actorOf(BigBlueButtonActor.props(system, eventBus, bbbMsgBus, outGW, healthzService), "bigbluebutton-actor")
eventBus.subscribe(bbbActor, meetingManagerChannel) eventBus.subscribe(bbbActor, meetingManagerChannel)
val userInfoService = UserInfoService(system, bbbActor)
val apiService = new ApiService(healthzService, meetingInfoService, userInfoService)
val redisMessageHandlerActor = system.actorOf(ReceivedJsonMsgHandlerActor.props(bbbMsgBus, incomingJsonMessageBus)) val redisMessageHandlerActor = system.actorOf(ReceivedJsonMsgHandlerActor.props(bbbMsgBus, incomingJsonMessageBus))
incomingJsonMessageBus.subscribe(redisMessageHandlerActor, toAkkaAppsJsonChannel) incomingJsonMessageBus.subscribe(redisMessageHandlerActor, toAkkaAppsJsonChannel)

View File

@ -1,190 +0,0 @@
package org.bigbluebutton
import org.bigbluebutton.common2.util.YamlUtil
import org.slf4j.LoggerFactory
import java.io.{ ByteArrayInputStream, File }
import scala.io.BufferedSource
import scala.util.{ Failure, Success }
object ClientSettings extends SystemConfiguration {
var clientSettingsFromFile: Map[String, Object] = Map("" -> "")
val logger = LoggerFactory.getLogger(this.getClass)
def loadClientSettingsFromFile() = {
val clientSettingsFile = scala.io.Source.fromFile(clientSettingsPath, "UTF-8")
val clientSettingsFileOverrideToCheck = new File(clientSettingsPathOverride)
val clientSettingsFileOverride = if (clientSettingsFileOverrideToCheck.exists())
scala.io.Source.fromFile(
clientSettingsPathOverride,
"UTF-8"
)
else new BufferedSource(new ByteArrayInputStream(Array[Byte]()))
clientSettingsFromFile =
common2.util.YamlUtil.mergeImmutableMaps(
common2.util.YamlUtil.toMap[Object](clientSettingsFile.mkString) match {
case Success(value) => value
case Failure(exception) =>
println("Error while fetching client Settings: ", exception)
Map[String, Object]()
},
common2.util.YamlUtil.toMap[Object](clientSettingsFileOverride.mkString) match {
case Success(value) => value
case Failure(exception) =>
println("Error while fetching client override Settings: ", exception)
Map[String, Object]()
}
)
//Remove `:private` once it's used only by HTML5 client's internal configs
clientSettingsFromFile -= "private"
}
def getClientSettingsWithOverride(clientSettingsOverrideJson: String): Map[String, Object] = {
if (clientSettingsOverrideJson.nonEmpty) {
val scalaMapClientOverride = common2.util.JsonUtil.toMap[Object](clientSettingsOverrideJson)
scalaMapClientOverride match {
case Success(clientSettingsOverrideAsMap) => YamlUtil.mergeImmutableMaps(clientSettingsFromFile, clientSettingsOverrideAsMap)
case Failure(msg) =>
logger.debug("No valid JSON override of client configuration in create call: {}", msg)
clientSettingsFromFile
}
} else clientSettingsFromFile
}
def getConfigPropertyValueByPathAsIntOrElse(map: Map[String, Any], path: String, alternativeValue: Int): Int = {
getConfigPropertyValueByPath(map, path) match {
case Some(configValue: Int) => configValue
case _ =>
logger.debug(s"Config `$path` with type Integer not found in clientSettings.")
alternativeValue
}
}
def getConfigPropertyValueByPathAsStringOrElse(map: Map[String, Any], path: String, alternativeValue: String): String = {
getConfigPropertyValueByPath(map, path) match {
case Some(configValue: String) => configValue
case _ =>
logger.debug(s"Config `$path` with type String not found in clientSettings.")
alternativeValue
}
}
def getConfigPropertyValueByPathAsBooleanOrElse(map: Map[String, Any], path: String, alternativeValue: Boolean): Boolean = {
getConfigPropertyValueByPath(map, path) match {
case Some(configValue: Boolean) => configValue
case _ =>
logger.debug(s"Config `$path` with type Boolean found in clientSettings.")
alternativeValue
}
}
def getConfigPropertyValueByPathAsListOfStringOrElse(map: Map[String, Any], path: String, alternativeValue: List[String]): List[String] = {
getConfigPropertyValueByPath(map, path) match {
case Some(configValue: List[String]) => configValue
case _ =>
logger.debug(s"Config `$path` with type List[String] not found in clientSettings.")
alternativeValue
}
}
def getConfigPropertyValueByPathAsListOfIntOrElse(map: Map[String, Any], path: String, alternativeValue: List[Int]): List[Int] = {
getConfigPropertyValueByPath(map, path) match {
case Some(configValue: List[Int]) => configValue
case _ =>
logger.debug(s"Config `$path` with type List[Int] not found in clientSettings.")
alternativeValue
}
}
def getConfigPropertyValueByPath(map: Map[String, Any], path: String): Option[Any] = {
val keys = path.split("\\.")
def getRecursive(map: Map[String, Any], keys: Seq[String]): Option[Any] = {
keys match {
case Seq(head, tail @ _*) =>
map.get(head) match {
case Some(innerMap: Map[String, Any]) => getRecursive(innerMap, tail)
case otherValue if tail.isEmpty => otherValue
case _ => None
}
case _ => None
}
}
getRecursive(map, keys)
}
def getPluginsFromConfig(config: Map[String, Any]): Map[String, Plugin] = {
var pluginsFromConfig: Map[String, Plugin] = Map()
val pluginsConfig = getConfigPropertyValueByPath(config, "public.plugins")
pluginsConfig match {
case Some(plugins: List[Map[String, Any]]) =>
for {
plugin <- plugins
} yield {
if (plugin.contains("name") && plugin.contains("url")) {
val pluginName = plugin("name").toString
val pluginUrl = plugin("url").toString
var pluginDataChannels: Map[String, DataChannel] = Map()
if (plugin.contains("dataChannels")) {
plugin("dataChannels") match {
case dataChannels: List[Map[String, Any]] =>
for {
dataChannel <- dataChannels
} yield {
if (dataChannel.contains("name")) {
val channelName = dataChannel("name").toString
val pushPermission = {
if (dataChannel.contains("pushPermission")) {
dataChannel("pushPermission") match {
case wPerm: List[String] => wPerm
case _ => {
logger.warn(s"Invalid pushPermission for channel $channelName in plugin $pluginName")
List()
}
}
} else {
logger.warn(s"Missing config pushPermission for channel $channelName in plugin $pluginName")
List()
}
}
val replaceOrDeletePermission = {
if (dataChannel.contains("replaceOrDeletePermission")) {
dataChannel("replaceOrDeletePermission") match {
case dPerm: List[String] => dPerm
case _ => {
logger.warn(s"Invalid replaceOrDeletePermission for channel $channelName in plugin $pluginName")
List()
}
}
} else {
List()
}
}
pluginDataChannels += (channelName -> DataChannel(channelName, pushPermission, replaceOrDeletePermission))
}
}
case _ => logger.warn(s"Plugin $pluginName has an invalid dataChannels format")
}
}
pluginsFromConfig += (pluginName -> Plugin(pluginName, pluginUrl, pluginDataChannels))
}
}
case _ => logger.warn(s"Invalid plugins config found.")
}
pluginsFromConfig
}
case class DataChannel(name: String, pushPermission: List[String], replaceOrDeletePermission: List[String])
case class Plugin(name: String, url: String, dataChannels: Map[String, DataChannel])
}

View File

@ -1,7 +1,5 @@
package org.bigbluebutton package org.bigbluebutton
import org.apache.pekko.actor.ActorContext
import org.bigbluebutton.common2.msgs.{ BbbCommonEnvCoreMsg, BbbCoreEnvelope, BbbCoreHeaderWithMeetingId, MessageTypes, Routing } import org.bigbluebutton.common2.msgs.{ BbbCommonEnvCoreMsg, BbbCoreEnvelope, BbbCoreHeaderWithMeetingId, MessageTypes, Routing }
import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter } import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter }
import org.bigbluebutton.core2.{ MeetingStatus2x } import org.bigbluebutton.core2.{ MeetingStatus2x }
@ -23,7 +21,7 @@ object LockSettingsUtil {
liveMeeting: LiveMeeting, liveMeeting: LiveMeeting,
outGW: OutMsgRouter, outGW: OutMsgRouter,
vu: VoiceUserState, mute: Boolean vu: VoiceUserState, mute: Boolean
)(implicit context: ActorContext): Unit = { )(implicit context: akka.actor.ActorContext): Unit = {
VoiceApp.muteUserInVoiceConf(liveMeeting, outGW, vu.intId, mute) VoiceApp.muteUserInVoiceConf(liveMeeting, outGW, vu.intId, mute)
} }
@ -31,7 +29,7 @@ object LockSettingsUtil {
disableMic: Boolean, disableMic: Boolean,
liveMeeting: LiveMeeting, liveMeeting: LiveMeeting,
outGW: OutMsgRouter outGW: OutMsgRouter
)(implicit context: ActorContext): Unit = { )(implicit context: akka.actor.ActorContext): Unit = {
VoiceUsers.findAll(liveMeeting.voiceUsers) foreach { vu => VoiceUsers.findAll(liveMeeting.voiceUsers) foreach { vu =>
Users2x.findWithIntId(liveMeeting.users2x, vu.intId).foreach { user => Users2x.findWithIntId(liveMeeting.users2x, vu.intId).foreach { user =>
if (user.role == Roles.VIEWER_ROLE && !vu.listenOnly && user.locked) { if (user.role == Roles.VIEWER_ROLE && !vu.listenOnly && user.locked) {
@ -50,7 +48,7 @@ object LockSettingsUtil {
def enforceLockSettingsForAllVoiceUsers( def enforceLockSettingsForAllVoiceUsers(
liveMeeting: LiveMeeting, liveMeeting: LiveMeeting,
outGW: OutMsgRouter outGW: OutMsgRouter
)(implicit context: ActorContext): Unit = { )(implicit context: akka.actor.ActorContext): Unit = {
val permissions = MeetingStatus2x.getPermissions(liveMeeting.status) val permissions = MeetingStatus2x.getPermissions(liveMeeting.status)
applyMutingOfUsers(permissions.disableMic, liveMeeting, outGW) applyMutingOfUsers(permissions.disableMic, liveMeeting, outGW)
} }
@ -59,7 +57,7 @@ object LockSettingsUtil {
voiceUser: VoiceUserState, voiceUser: VoiceUserState,
liveMeeting: LiveMeeting, liveMeeting: LiveMeeting,
outGW: OutMsgRouter outGW: OutMsgRouter
)(implicit context: ActorContext): Unit = { )(implicit context: akka.actor.ActorContext): Unit = {
val permissions = MeetingStatus2x.getPermissions(liveMeeting.status) val permissions = MeetingStatus2x.getPermissions(liveMeeting.status)
if (permissions.disableMic) { if (permissions.disableMic) {
@ -80,7 +78,7 @@ object LockSettingsUtil {
intUserId: String, intUserId: String,
liveMeeting: LiveMeeting, liveMeeting: LiveMeeting,
outGW: OutMsgRouter outGW: OutMsgRouter
)(implicit context: ActorContext): Unit = { )(implicit context: akka.actor.ActorContext): Unit = {
val voiceUser = VoiceUsers.findWithIntId(liveMeeting.voiceUsers, intUserId) val voiceUser = VoiceUsers.findWithIntId(liveMeeting.voiceUsers, intUserId)
voiceUser.foreach { vu => voiceUser.foreach { vu =>
// Make sure that listen only user is muted. (ralam dec 6, 2019 // Make sure that listen only user is muted. (ralam dec 6, 2019

View File

@ -1,9 +1,6 @@
package org.bigbluebutton package org.bigbluebutton
import com.fasterxml.jackson.databind.ObjectMapper import scala.util.Try
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
import scala.util.{ Failure, Success, Try }
import com.typesafe.config.ConfigFactory import com.typesafe.config.ConfigFactory
trait SystemConfiguration { trait SystemConfiguration {
@ -41,16 +38,12 @@ trait SystemConfiguration {
lazy val voiceConfRecordPath = Try(config.getString("voiceConf.recordPath")).getOrElse("/var/freeswitch/meetings") lazy val voiceConfRecordPath = Try(config.getString("voiceConf.recordPath")).getOrElse("/var/freeswitch/meetings")
lazy val voiceConfRecordCodec = Try(config.getString("voiceConf.recordCodec")).getOrElse("wav") lazy val voiceConfRecordCodec = Try(config.getString("voiceConf.recordCodec")).getOrElse("wav")
lazy val voiceConfRecordEnableFileSplitter = Try(config.getBoolean("voiceConf.recordEnableFileSplitter")).getOrElse(false)
lazy val voiceConfRecordFileSplitterIntervalInMinutes = Try(config.getInt("voiceConf.recordFileSplitterIntervalInMinutes")).getOrElse(15)
lazy val checkVoiceRecordingInterval = Try(config.getInt("voiceConf.checkRecordingInterval")).getOrElse(19) lazy val checkVoiceRecordingInterval = Try(config.getInt("voiceConf.checkRecordingInterval")).getOrElse(19)
lazy val syncVoiceUsersStatusInterval = Try(config.getInt("voiceConf.syncUserStatusInterval")).getOrElse(43) lazy val syncVoiceUsersStatusInterval = Try(config.getInt("voiceConf.syncUserStatusInterval")).getOrElse(43)
lazy val ejectRogueVoiceUsers = Try(config.getBoolean("voiceConf.ejectRogueVoiceUsers")).getOrElse(true) lazy val ejectRogueVoiceUsers = Try(config.getBoolean("voiceConf.ejectRogueVoiceUsers")).getOrElse(true)
lazy val dialInApprovalAudioPath = Try(config.getString("voiceConf.dialInApprovalAudioPath")).getOrElse("ivr/ivr-please_hold_while_party_contacted.wav") lazy val dialInApprovalAudioPath = Try(config.getString("voiceConf.dialInApprovalAudioPath")).getOrElse("ivr/ivr-please_hold_while_party_contacted.wav")
lazy val toggleListenOnlyAfterMuteTimer = Try(config.getInt("voiceConf.toggleListenOnlyAfterMuteTimer")).getOrElse(4) lazy val toggleListenOnlyAfterMuteTimer = Try(config.getInt("voiceConf.toggleListenOnlyAfterMuteTimer")).getOrElse(4)
lazy val transparentListenOnlyThreshold = Try(config.getInt("voiceConf.transparentListenOnlyThreshold")).getOrElse(0) lazy val transparentListenOnlyThreshold = Try(config.getInt("voiceConf.transparentListenOnlyThreshold")).getOrElse(0)
lazy val muteOnStartThreshold = Try(config.getInt("voiceConf.muteOnStartThreshold")).getOrElse(0)
lazy val dialInEnforceGuestPolicy = Try(config.getBoolean("voiceConf.dialInEnforceGuestPolicy")).getOrElse(true)
lazy val recordingChapterBreakLengthInMinutes = Try(config.getInt("recording.chapterBreakLengthInMinutes")).getOrElse(0) lazy val recordingChapterBreakLengthInMinutes = Try(config.getInt("recording.chapterBreakLengthInMinutes")).getOrElse(0)
@ -86,13 +79,6 @@ trait SystemConfiguration {
lazy val analyticsIncludeChat = Try(config.getBoolean("analytics.includeChat")).getOrElse(true) lazy val analyticsIncludeChat = Try(config.getBoolean("analytics.includeChat")).getOrElse(true)
lazy val clientSettingsPath = Try(config.getString("client.clientSettingsFilePath")).getOrElse(
"/usr/share/bigbluebutton/html5-client/private/config/settings.yml"
)
lazy val clientSettingsPathOverride = Try(config.getString("client.clientSettingsOverrideFilePath")).getOrElse(
"/etc/bigbluebutton/bbb-html5.yml"
)
// Grab the "interface" parameter from the http config // Grab the "interface" parameter from the http config
val httpHost = config.getString("http.interface") val httpHost = config.getString("http.interface")
// Grab the "port" parameter from the http config // Grab the "port" parameter from the http config

View File

@ -1,10 +1,10 @@
package org.bigbluebutton.core package org.bigbluebutton.core
import java.io.{ PrintWriter, StringWriter } import java.io.{ PrintWriter, StringWriter }
import org.apache.pekko.actor._ import akka.actor._
import org.apache.pekko.actor.ActorLogging import akka.actor.ActorLogging
import org.apache.pekko.actor.SupervisorStrategy.Resume import akka.actor.SupervisorStrategy.Resume
import org.apache.pekko.util.Timeout import akka.util.Timeout
import scala.concurrent.duration._ import scala.concurrent.duration._
import org.bigbluebutton.core.bus._ import org.bigbluebutton.core.bus._
@ -13,9 +13,6 @@ import org.bigbluebutton.SystemConfiguration
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import org.bigbluebutton.common2.msgs._ import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.db.{ DatabaseConnection, MeetingDAO }
import org.bigbluebutton.core.domain.MeetingEndReason
import org.bigbluebutton.core.models.Roles
import org.bigbluebutton.core.running.RunningMeeting import org.bigbluebutton.core.running.RunningMeeting
import org.bigbluebutton.core.util.ColorPicker import org.bigbluebutton.core.util.ColorPicker
import org.bigbluebutton.core2.RunningMeetings import org.bigbluebutton.core2.RunningMeetings
@ -46,13 +43,6 @@ class BigBlueButtonActor(
private val meetings = new RunningMeetings private val meetings = new RunningMeetings
private case class SessionTokenInfo(
meetingId: String,
userId: String,
replaced: Boolean = false
)
private var sessionTokens = new collection.immutable.HashMap[String, SessionTokenInfo] //sessionToken -> SessionTokenInfo
override val supervisorStrategy = OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) { override val supervisorStrategy = OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) {
case e: Exception => { case e: Exception => {
val sw: StringWriter = new StringWriter() val sw: StringWriter = new StringWriter()
@ -63,20 +53,8 @@ class BigBlueButtonActor(
} }
} }
object BBBTasksExecutor
context.system.scheduler.schedule(
1 minute,
1 minute,
self,
BBBTasksExecutor
)
override def preStart() { override def preStart() {
bbbMsgBus.subscribe(self, meetingManagerChannel) 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() { override def postStop() {
@ -85,76 +63,35 @@ class BigBlueButtonActor(
def receive = { def receive = {
// Internal messages // Internal messages
case BBBTasksExecutor => handleMeetingTasksExecutor()
case msg: DestroyMeetingInternalMsg => handleDestroyMeeting(msg) case msg: DestroyMeetingInternalMsg => handleDestroyMeeting(msg)
//Api messages
case msg: GetUserApiMsg => handleGetUserApiMsg(msg, sender)
// 2x messages // 2x messages
case msg: BbbCommonEnvCoreMsg => handleBbbCommonEnvCoreMsg(msg) case msg: BbbCommonEnvCoreMsg => handleBbbCommonEnvCoreMsg(msg)
case _ => // do nothing case _ => // do nothing
} }
private def handleGetUserApiMsg(msg: GetUserApiMsg, actorRef: ActorRef): Unit = {
log.debug("RECEIVED GetUserApiMsg msg {}", msg)
sessionTokens.get(msg.sessionToken) match {
case Some(sessionTokenInfo) =>
if (sessionTokenInfo.replaced) {
log.debug("handleGetUserApiMsg ({}): Session token replaced.", msg.sessionToken)
actorRef ! ApiResponseFailure("Session token replaced.", "session_token_replaced")
} else {
RunningMeetings.findWithId(meetings, sessionTokenInfo.meetingId) match {
case Some(m) =>
log.debug("handleGetUserApiMsg ({}): {}.", msg.sessionToken, m)
m.actorRef forward (msg)
case None =>
//The meeting is ended, it will return some data just to confirm the session was valid
//The client can request data after the meeting is ended
val userInfos = Map(
"returncode" -> "SUCCESS",
"sessionToken" -> msg.sessionToken,
"meetingID" -> sessionTokenInfo.meetingId,
"internalUserID" -> sessionTokenInfo.userId,
"externMeetingID" -> "",
"externUserID" -> "",
"currentlyInMeeting" -> false,
"authToken" -> "",
"role" -> Roles.VIEWER_ROLE,
"guest" -> "false",
"guestStatus" -> "ALLOWED",
"moderator" -> false,
"presenter" -> false,
"hideViewersCursor" -> false,
"hideViewersAnnotation" -> false,
"hideUserList" -> false,
"webcamsOnlyForModerator" -> false
)
log.debug("handleGetUserApiMsg ({}): Meeting is ended.", msg.sessionToken)
actorRef ! ApiResponseSuccess("Meeting is ended.", UserInfosApiMsg(userInfos))
}
}
case None =>
log.debug("handleGetUserApiMsg ({}): Meeting not found.", msg.sessionToken)
actorRef ! ApiResponseFailure("Meeting not found.", "meeting_not_found")
}
}
private def handleBbbCommonEnvCoreMsg(msg: BbbCommonEnvCoreMsg): Unit = { private def handleBbbCommonEnvCoreMsg(msg: BbbCommonEnvCoreMsg): Unit = {
msg.core match { msg.core match {
case m: CreateMeetingReqMsg => handleCreateMeetingReqMsg(m) case m: CreateMeetingReqMsg => handleCreateMeetingReqMsg(m)
case m: RegisterUserReqMsg => handleRegisterUserReqMsg(m) case m: RegisterUserReqMsg => handleRegisterUserReqMsg(m)
case m: RegisterUserSessionTokenReqMsg => handleRegisterUserSessionTokenReqMsg(m) case m: GetAllMeetingsReqMsg => handleGetAllMeetingsReqMsg(m)
case m: CheckAlivePingSysMsg => handleCheckAlivePingSysMsg(m) case m: GetRunningMeetingsReqMsg => handleGetRunningMeetingsReqMsg(m)
case _: UserGraphqlConnectionEstablishedSysMsg => //Ignore case m: CheckAlivePingSysMsg => handleCheckAlivePingSysMsg(m)
case _: UserGraphqlConnectionClosedSysMsg => //Ignore case m: ValidateConnAuthTokenSysMsg => handleValidateConnAuthTokenSysMsg(m)
case _: CheckGraphqlMiddlewareAlivePongSysMsg => //Ignore case _ => log.warning("Cannot handle " + msg.envelope.name)
case _ => log.warning("Cannot handle " + msg.envelope.name) }
}
def handleValidateConnAuthTokenSysMsg(msg: ValidateConnAuthTokenSysMsg): Unit = {
RunningMeetings.findWithId(meetings, msg.body.meetingId) match {
case Some(meeting) =>
meeting.actorRef forward msg
case None =>
val event = MsgBuilder.buildValidateConnAuthTokenSysRespMsg(msg.body.meetingId, msg.body.userId,
false, msg.body.connId, msg.body.app)
outGW.send(event)
} }
} }
@ -164,32 +101,6 @@ class BigBlueButtonActor(
m <- RunningMeetings.findWithId(meetings, msg.header.meetingId) m <- RunningMeetings.findWithId(meetings, msg.header.meetingId)
} yield { } yield {
log.debug("FORWARDING Register user message") log.debug("FORWARDING Register user message")
//Store sessionTokens and associate them with their respective meetingId + userId owners
sessionTokens += (msg.body.sessionToken -> SessionTokenInfo(msg.body.meetingId, msg.body.intUserId))
m.actorRef forward (msg)
}
}
def handleRegisterUserSessionTokenReqMsg(msg: RegisterUserSessionTokenReqMsg): Unit = {
log.debug("RECEIVED RegisterUserSessionTokenReqMsg msg {}", msg)
for {
m <- RunningMeetings.findWithId(meetings, msg.header.meetingId)
} yield {
log.debug("FORWARDING Register user session token message")
//Store sessionTokens and associate them with their respective meetingId + userId owners
sessionTokens += (msg.body.sessionToken -> SessionTokenInfo(msg.body.meetingId, msg.body.userId))
if (msg.body.replaceSessionToken.nonEmpty) {
for {
sessionTokenInfo <- sessionTokens.get(msg.body.replaceSessionToken)
} yield {
sessionTokens += (msg.body.replaceSessionToken -> sessionTokenInfo.copy(replaced = true))
}
}
m.actorRef forward (msg) m.actorRef forward (msg)
} }
} }
@ -219,18 +130,32 @@ class BigBlueButtonActor(
} }
} }
private def handleGetRunningMeetingsReqMsg(msg: GetRunningMeetingsReqMsg): Unit = {
val liveMeetings = RunningMeetings.meetings(meetings)
val meetingIds = liveMeetings.map(m => m.props.meetingProp.intId)
val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka")
val envelope = BbbCoreEnvelope(GetRunningMeetingsRespMsg.NAME, routing)
val header = BbbCoreBaseHeader(GetRunningMeetingsRespMsg.NAME)
val body = GetRunningMeetingsRespMsgBody(meetingIds)
val event = GetRunningMeetingsRespMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
outGW.send(msgEvent)
}
private def handleGetAllMeetingsReqMsg(msg: GetAllMeetingsReqMsg): Unit = {
RunningMeetings.meetings(meetings).filter(_.props.systemProps.html5InstanceId == msg.body.html5InstanceId).foreach(m => {
m.actorRef ! msg
})
}
private def handleCheckAlivePingSysMsg(msg: CheckAlivePingSysMsg): Unit = { private def handleCheckAlivePingSysMsg(msg: CheckAlivePingSysMsg): Unit = {
val event = MsgBuilder.buildCheckAlivePingSysMsg(msg.body.system, msg.body.bbbWebTimestamp, System.currentTimeMillis()) val event = MsgBuilder.buildCheckAlivePingSysMsg(msg.body.system, msg.body.bbbWebTimestamp, System.currentTimeMillis())
healthzService.sendPubSubStatusMessage(msg.body.akkaAppsTimestamp, System.currentTimeMillis()) healthzService.sendPubSubStatusMessage(msg.body.akkaAppsTimestamp, System.currentTimeMillis())
outGW.send(event) outGW.send(event)
} }
private def handleMeetingTasksExecutor(): Unit = {
// Delays meeting data for 1 hour post-meeting in case users request info after it ends.
// This routine ensures proper purging if akka-apps restart and the handleDestroyMeeting scheduler does not run.
MeetingDAO.deleteOldMeetings()
}
private def handleDestroyMeeting(msg: DestroyMeetingInternalMsg): Unit = { private def handleDestroyMeeting(msg: DestroyMeetingInternalMsg): Unit = {
for { for {
@ -260,16 +185,6 @@ class BigBlueButtonActor(
context.stop(m.actorRef) context.stop(m.actorRef)
} }
//Delay removal of session tokens and Graphql data once users might request some info after the meeting is ended
context.system.scheduler.scheduleOnce(Duration.create(60, TimeUnit.MINUTES)) {
log.debug("Removing Graphql data and session tokens. meetingID={}", msg.meetingId)
sessionTokens = sessionTokens.filter(sessionTokenInfo => sessionTokenInfo._2.meetingId != msg.meetingId)
//In Db, Removing the meeting is enough, all other tables has "ON DELETE CASCADE"
MeetingDAO.delete(msg.meetingId)
}
//Remove ColorPicker idx of the meeting //Remove ColorPicker idx of the meeting
ColorPicker.reset(m.props.meetingProp.intId) ColorPicker.reset(m.props.meetingProp.intId)
} }

View File

@ -1,6 +1,5 @@
package org.bigbluebutton.core.api package org.bigbluebutton.core.api
import org.bigbluebutton.core.apps.users.UserEstablishedGraphqlConnectionInternalMsgHdlr
import org.bigbluebutton.core.domain.{ BreakoutUser, BreakoutVoiceUser } import org.bigbluebutton.core.domain.{ BreakoutUser, BreakoutVoiceUser }
import spray.json.JsObject import spray.json.JsObject
case class InMessageHeader(name: String) case class InMessageHeader(name: String)
@ -25,7 +24,16 @@ case class MonitorNumberOfUsersInternalMsg(meetingID: String) extends InMessage
* Audit message sent to meeting to trigger updating clients of meeting time remaining. * Audit message sent to meeting to trigger updating clients of meeting time remaining.
* @param meetingId * @param meetingId
*/ */
case class MonitorGuestWaitPresenceInternalMsg(meetingId: String) extends InMessage case class SendTimeRemainingAuditInternalMsg(meetingId: String, timeUpdatedInMinutes: Int) extends InMessage
/**
* Parent message sent to breakout rooms to trigger updating clients of meeting time remaining.
* @param meetingId
* @param timeLeftInSec
*/
case class SendBreakoutTimeRemainingInternalMsg(meetingId: String, timeLeftInSec: Long, timeUpdatedInMinutes: Int) extends InMessage
case class SendRecordingTimerInternalMsg(meetingId: String) extends InMessage
case class ExtendMeetingDuration(meetingId: String, userId: String) extends InMessage case class ExtendMeetingDuration(meetingId: String, userId: String) extends InMessage
case class DestroyMeetingInternalMsg(meetingId: String) extends InMessage case class DestroyMeetingInternalMsg(meetingId: String) extends InMessage
@ -106,29 +114,15 @@ case class EjectUserFromBreakoutInternalMsg(parentId: String, breakoutId: String
case class CapturePresentationReqInternalMsg(userId: String, parentMeetingId: String, filename: String, allPages: Boolean = true) extends InMessage case class CapturePresentationReqInternalMsg(userId: String, parentMeetingId: String, filename: String, allPages: Boolean = true) extends InMessage
/** /**
* Sent to the same meeting to force a new presenter to the Pod * Sent by breakout room to parent meeting to obtain padId
* @param presenterId * @param breakoutId
* @param filename
*/ */
case class SetPresenterInDefaultPodInternalMsg(presenterId: String) extends InMessage case class CaptureSharedNotesReqInternalMsg(breakoutId: String, filename: String) extends InMessage
/** // DeskShare
* Sent by GraphqlActionsActor to inform MeetingActor that user disconnected case class DeskShareStartedRequest(conferenceName: String, callerId: String, callerIdName: String) extends InMessage
* @param userId 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 UserClosedAllGraphqlConnectionsInternalMsg(userId: String) extends InMessage case class DeskShareRTMPBroadcastStoppedRequest(conferenceName: String, streamname: String, videoWidth: Int, videoHeight: Int, timestamp: String) extends InMessage
case class DeskShareGetDeskShareInfoRequest(conferenceName: String, requesterID: String, replyTo: String) extends InMessage
/**
* Sent by GraphqlActionsActor to inform MeetingActor that user came back from disconnection
* @param userId
*/
case class UserEstablishedGraphqlConnectionInternalMsg(userId: String, clientType: String, isMobile: Boolean) extends InMessage
/**
* API endpoint /userInfo to provide User Session Variables messages
*/
case class GetUserApiMsg(sessionToken: String)
case class UserInfosApiMsg(infos: Map[String, Any])
trait ApiResponse
case class ApiResponseSuccess(msg: String, any: Any = null) extends ApiResponse
case class ApiResponseFailure(msg: String, msgId: String, any: Any = null) extends ApiResponse

View File

@ -20,9 +20,10 @@ object BreakoutModel {
captureSlidesFilename: String, captureSlidesFilename: String,
allPages: Boolean, allPages: Boolean,
presId: String, presId: String,
sourcePresentationFilename: String,
): BreakoutRoom2x = { ): BreakoutRoom2x = {
new BreakoutRoom2x(id, externalId, name, parentId, sequence, shortName, isDefaultName, freeJoin, voiceConf, assignedUsers, Vector(), Vector(), None, false, new BreakoutRoom2x(id, externalId, name, parentId, sequence, shortName, isDefaultName, freeJoin, voiceConf, assignedUsers, Vector(), Vector(), None, false,
captureNotes, captureSlides, captureNotesFilename, captureSlidesFilename, allPages, presId) captureNotes, captureSlides, captureNotesFilename, captureSlidesFilename, allPages, presId, sourcePresentationFilename)
} }
} }

View File

@ -20,6 +20,32 @@ class CaptionModel {
return None return None
} }
def updateTranscriptOwner(name: String, locale: String, ownerId: String): Map[String, TranscriptVO] = {
var updatedTranscripts = new HashMap[String, TranscriptVO]
// clear owner from previous locale
if (ownerId.length > 0) {
findTranscriptByOwnerId(ownerId).foreach(t => {
val oldTranscript = t._2.copy(ownerId = "")
transcripts += t._1 -> oldTranscript
updatedTranscripts += t._1 -> oldTranscript
})
}
// change the owner if it does exist
if (transcripts contains name) {
val newTranscript = transcripts(name).copy(ownerId = ownerId)
transcripts += name -> newTranscript
updatedTranscripts += name -> newTranscript
} else { // create the locale if it doesn't exist
val addedTranscript = createTranscript(name, locale, ownerId)
updatedTranscripts += name -> addedTranscript
}
updatedTranscripts
}
def getHistory(): Map[String, TranscriptVO] = { def getHistory(): Map[String, TranscriptVO] = {
transcripts transcripts
} }
@ -71,6 +97,20 @@ class CaptionModel {
locale locale
} }
def checkCaptionOwnerLogOut(userId: String): Option[(String, TranscriptVO)] = {
var rtnTranscript: Option[(String, TranscriptVO)] = None
if (userId.length > 0) {
findTranscriptByOwnerId(userId).foreach(t => {
val oldTranscript = t._2.copy(ownerId = "")
transcripts += t._1 -> oldTranscript
rtnTranscript = Some((t._1, oldTranscript))
})
}
rtnTranscript
}
def isUserCaptionOwner(userId: String, name: String): Boolean = { def isUserCaptionOwner(userId: String, name: String): Boolean = {
var isOwner: Boolean = false; var isOwner: Boolean = false;

View File

@ -5,6 +5,7 @@ import org.bigbluebutton.core2.message.handlers.guests._
trait GuestsApp extends GetGuestsWaitingApprovalReqMsgHdlr trait GuestsApp extends GetGuestsWaitingApprovalReqMsgHdlr
with GuestsWaitingApprovedMsgHdlr with GuestsWaitingApprovedMsgHdlr
with GuestWaitingLeftMsgHdlr
with UpdatePositionInWaitingQueueReqMsgHdlr with UpdatePositionInWaitingQueueReqMsgHdlr
with SetGuestPolicyMsgHdlr with SetGuestPolicyMsgHdlr
with SetGuestLobbyMessageMsgHdlr with SetGuestLobbyMessageMsgHdlr

View File

@ -88,12 +88,8 @@ object PermissionCheck extends SystemConfiguration {
UsersApp.ejectUserFromMeeting(outGW, liveMeeting, userId, ejectedBy, reason, EjectReasonCode.PERMISSION_FAILED, ban = false) UsersApp.ejectUserFromMeeting(outGW, liveMeeting, userId, ejectedBy, reason, EjectReasonCode.PERMISSION_FAILED, ban = false)
// Force reconnection with graphql to refresh permissions // send a system message to force disconnection
for { Sender.sendDisconnectClientSysMsg(meetingId, userId, ejectedBy, reason, outGW)
regUser <- RegisteredUsers.findWithUserId(userId, liveMeeting.registeredUsers)
} yield {
Sender.sendForceUserGraphqlReconnectionSysMsg(liveMeeting.props.meetingProp.intId, regUser.id, regUser.sessionToken, reason, outGW)
}
} else { } else {
// TODO: get this object a context so it can use the akka logging system // TODO: get this object a context so it can use the akka logging system
println(s"Skipping violation ejection of ${userId} trying to ${reason} in ${meetingId}") println(s"Skipping violation ejection of ${userId} trying to ${reason} in ${meetingId}")

View File

@ -18,7 +18,7 @@ class PresentationModel {
presentations.values.toVector presentations.values.toVector
} }
def getCurrentPresentation(): Option[Presentation] = { def getCurrentPresentation(): Option[Presentation] = { // todo remove
presentations.values find (p => p.current) presentations.values find (p => p.current)
} }

View File

@ -6,7 +6,7 @@ object TimerModel {
stopwatch: Boolean = true, stopwatch: Boolean = true,
time: Int = 0, time: Int = 0,
accumulated: Int = 0, accumulated: Int = 0,
track: String = "noTrack", track: String = "",
): Unit = { ): Unit = {
model.stopwatch = stopwatch model.stopwatch = stopwatch
model.time = time model.time = time
@ -14,16 +14,20 @@ object TimerModel {
model.track = track model.track = track
} }
def reset(model: TimerModel) : Unit = { def reset(model: TimerModel, stopwatch: Boolean, time: Int, accumulated: Int, startedAt: Long, track: String) : Unit = {
model.accumulated = 0 model.stopwatch = stopwatch
model.startedAt = if (model.running) System.currentTimeMillis() else 0 model.time = time
model.accumulated = accumulated
model.startedAt = startedAt
model.track = track
model.endedAt = 0
} }
def setIsActive(model: TimerModel, active: Boolean): Unit = { def setIsActive(model: TimerModel, active: Boolean): Unit = {
model.isActive = active model.isActive = active
} }
def getIsActive(model: TimerModel): Boolean = { def getIsACtive(model: TimerModel): Boolean = {
model.isActive model.isActive
} }
@ -44,39 +48,10 @@ object TimerModel {
} }
def setRunning(model: TimerModel, running: Boolean): Unit = { def setRunning(model: TimerModel, running: Boolean): Unit = {
resetTimerIfFinished(model)
val now = System.currentTimeMillis()
// If the timer is running and will stop, update accumulated time
if (isRunning(model) && !running) {
val accumulated = getAccumulated(model) + Math.abs(now - getStartedAt(model)).toInt
setAccumulated(model, accumulated)
}
// If the timer is not running and will start, set the start time
if (!isRunning(model) && running) {
setStartedAt(model, now)
}
// Update the running status of the model
model.running = running model.running = running
} }
def resetTimerIfFinished(model: TimerModel) = { def getRunning(model: TimerModel): Boolean = {
// If the timer is finished, reset the accumulated time and start time if running
if (isRunning(model)
&& !isStopwatch(model)
&& (model.startedAt + (model.time - model.accumulated)) < System.currentTimeMillis()) {
model.running = false
reset(model)
true
} else {
false
}
}
def isRunning(model: TimerModel): Boolean = {
model.running model.running
} }
@ -84,7 +59,7 @@ object TimerModel {
model.stopwatch = stopwatch model.stopwatch = stopwatch
} }
def isStopwatch(model: TimerModel): Boolean = { def getStopwatch(model: TimerModel): Boolean = {
model.stopwatch model.stopwatch
} }
@ -103,14 +78,23 @@ object TimerModel {
def getTime(model: TimerModel): Int = { def getTime(model: TimerModel): Int = {
model.time model.time
} }
def setEndedAt(model: TimerModel, timestamp: Long): Unit = {
model.endedAt = timestamp
}
def getEndedAt(model: TimerModel): Long = {
model.endedAt
}
} }
class TimerModel { class TimerModel {
private var startedAt: Long = 0 private var startedAt: Long = 0
private var endedAt: Long = 0
private var accumulated: Int = 0 private var accumulated: Int = 0
private var running: Boolean = false private var running: Boolean = false
private var time: Int = 0 private var time: Int = 0
private var stopwatch: Boolean = true private var stopwatch: Boolean = true
private var track: String = "noTrack" private var track: String = ""
private var isActive: Boolean = false private var isActive: Boolean = false
} }

View File

@ -4,7 +4,6 @@ import scala.collection.immutable.HashMap
import org.bigbluebutton.common2.msgs.AnnotationVO import org.bigbluebutton.common2.msgs.AnnotationVO
import org.bigbluebutton.core.apps.whiteboard.Whiteboard import org.bigbluebutton.core.apps.whiteboard.Whiteboard
import org.bigbluebutton.SystemConfiguration import org.bigbluebutton.SystemConfiguration
import org.bigbluebutton.core.db.{ PresAnnotationDAO, PresPageWritersDAO }
class WhiteboardModel extends SystemConfiguration { class WhiteboardModel extends SystemConfiguration {
private var _whiteboards = new HashMap[String, Whiteboard]() private var _whiteboards = new HashMap[String, Whiteboard]()
@ -46,80 +45,33 @@ class WhiteboardModel extends SystemConfiguration {
k -> newValue k -> newValue
}).toMap }).toMap
def addAnnotations(wbId: String, meetingId: String, userId: String, annotations: Array[AnnotationVO], isPresenter: Boolean, isModerator: Boolean): Array[AnnotationVO] = { def addAnnotations(wbId: String, userId: String, annotations: Array[AnnotationVO], isPresenter: Boolean, isModerator: Boolean): Array[AnnotationVO] = {
val wb = getWhiteboard(wbId)
var annotationsAdded = Array[AnnotationVO]() var annotationsAdded = Array[AnnotationVO]()
var annotationsDiffAdded = Array[AnnotationVO]() val wb = getWhiteboard(wbId)
var newAnnotationsMap = wb.annotationsMap var newAnnotationsMap = wb.annotationsMap
for (annotation <- annotations) { for (annotation <- annotations) {
val oldAnnotation = wb.annotationsMap.get(annotation.id) val oldAnnotation = wb.annotationsMap.get(annotation.id)
if (oldAnnotation.isDefined) { if (!oldAnnotation.isEmpty) {
val hasPermission = isPresenter || isModerator || oldAnnotation.get.userId == userId val hasPermission = isPresenter || isModerator || oldAnnotation.get.userId == userId
if (hasPermission) { if (hasPermission) {
val mergedAnnotationInfo = deepMerge(oldAnnotation.get.annotationInfo, annotation.annotationInfo) val newAnnotation = oldAnnotation.get.copy(annotationInfo = deepMerge(oldAnnotation.get.annotationInfo, annotation.annotationInfo))
// Apply cleaning if it's an arrow annotation
val finalAnnotationInfo = if (oldAnnotation.get.annotationInfo.get("type").contains("arrow")) {
cleanArrowAnnotationProps(mergedAnnotationInfo)
} else {
mergedAnnotationInfo
}
val newAnnotation = oldAnnotation.get.copy(annotationInfo = finalAnnotationInfo)
newAnnotationsMap += (annotation.id -> newAnnotation) newAnnotationsMap += (annotation.id -> newAnnotation)
annotationsAdded :+= newAnnotation annotationsAdded :+= annotation
annotationsDiffAdded :+= annotation println(s"Updated annotation onpage [${wb.id}]. After numAnnotations=[${newAnnotationsMap.size}].")
println(s"Updated annotation on page [${wb.id}]. After numAnnotations=[${newAnnotationsMap.size}].")
} else { } else {
println(s"User $userId doesn't have permission to edit annotation ${annotation.id}, ignoring...") println(s"User $userId doesn't have permission to edit annotation ${annotation.id}, ignoring...")
} }
} else if (annotation.annotationInfo.contains("type")) { } else if (annotation.annotationInfo.contains("type")) {
newAnnotationsMap += (annotation.id -> annotation) newAnnotationsMap += (annotation.id -> annotation)
annotationsAdded :+= annotation annotationsAdded :+= annotation
annotationsDiffAdded :+= annotation
println(s"Adding annotation to page [${wb.id}]. After numAnnotations=[${newAnnotationsMap.size}].") println(s"Adding annotation to page [${wb.id}]. After numAnnotations=[${newAnnotationsMap.size}].")
} else { } else {
println(s"New annotation [${annotation.id}] with no type, ignoring...") println(s"New annotation [${annotation.id}] with no type, ignoring (probably received a remove message before and now the shape is incomplete, ignoring...")
} }
} }
PresAnnotationDAO.insertOrUpdateMap(meetingId, annotationsAdded)
val newWb = wb.copy(annotationsMap = newAnnotationsMap) val newWb = wb.copy(annotationsMap = newAnnotationsMap)
saveWhiteboard(newWb) saveWhiteboard(newWb)
annotationsDiffAdded annotationsAdded
}
private def overwriteLineShapeHandles(oldProps: Map[String, Any], newProps: Map[String, Any]): Map[String, Any] = {
val newHandles = newProps.get("handles")
val updatedProps = oldProps ++ newProps.filter {
case ("handles", _) => false // Remove the old handles
case _ => true
}
updatedProps ++ newHandles.map("handles" -> _)
}
private def cleanArrowAnnotationProps(annotationInfo: Map[String, _]): Map[String, _] = {
annotationInfo.get("props") match {
case Some(props: Map[String, _]) =>
val cleanedProps = props.map {
case ("end", endProps: Map[String, _]) => "end" -> cleanEndOrStartProps(endProps)
case ("start", startProps: Map[String, _]) => "start" -> cleanEndOrStartProps(startProps)
case other => other
}
annotationInfo + ("props" -> cleanedProps)
case _ => annotationInfo
}
}
private def cleanEndOrStartProps(props: Map[String, _]): Map[String, _] = {
props.get("type") match {
case Some("binding") => props - ("x", "y") // Remove 'x' and 'y' for 'binding' type
case Some("point") => props - ("boundShapeId", "normalizedAnchor", "isExact", "isPrecise") // Remove unwanted properties for 'point' type
case _ => props
}
} }
def getHistory(wbId: String): Array[AnnotationVO] = { def getHistory(wbId: String): Array[AnnotationVO] = {
@ -127,42 +79,33 @@ class WhiteboardModel extends SystemConfiguration {
wb.annotationsMap.values.toArray wb.annotationsMap.values.toArray
} }
def deleteAnnotations(wbId: String, meetingId: String, userId: String, annotationsIds: Array[String], isPresenter: Boolean, isModerator: Boolean): Array[String] = { def deleteAnnotations(wbId: String, userId: String, annotationsIds: Array[String], isPresenter: Boolean, isModerator: Boolean): Array[String] = {
val wb = getWhiteboard(wbId)
var annotationsIdsRemoved = Array[String]() var annotationsIdsRemoved = Array[String]()
val wb = getWhiteboard(wbId)
var newAnnotationsMap = wb.annotationsMap var newAnnotationsMap = wb.annotationsMap
for (annotationId <- annotationsIds) { for (annotationId <- annotationsIds) {
val annotation = wb.annotationsMap.get(annotationId) val annotation = wb.annotationsMap.get(annotationId)
if (annotation.isDefined) { if (!annotation.isEmpty) {
val hasPermission = isPresenter || isModerator || annotation.get.userId == userId val hasPermission = isPresenter || isModerator || annotation.get.userId == userId
if (hasPermission) { if (hasPermission) {
newAnnotationsMap -= annotationId newAnnotationsMap -= annotationId
println(s"Removed annotation $annotationId on page [${wb.id}]. After numAnnotations=[${newAnnotationsMap.size}].") println("Removing annotation on page [" + wb.id + "]. After numAnnotations=[" + newAnnotationsMap.size + "].")
annotationsIdsRemoved :+= annotationId annotationsIdsRemoved :+= annotationId
} else { } else {
println(s"User $userId doesn't have permission to remove annotation $annotationId, ignoring...") println("User doesn't have permission to remove this annotation, ignoring...")
} }
} else {
println(s"Annotation $annotationId not found while trying to delete it.")
} }
} }
val newWb = wb.copy(annotationsMap = newAnnotationsMap)
// Update whiteboard and save saveWhiteboard(newWb)
val updatedWb = wb.copy(annotationsMap = newAnnotationsMap)
saveWhiteboard(updatedWb)
PresAnnotationDAO.delete(meetingId, userId, annotationsIdsRemoved)
annotationsIdsRemoved annotationsIdsRemoved
} }
def modifyWhiteboardAccess(meetingId: String, wbId: String, multiUser: Array[String]) { def modifyWhiteboardAccess(wbId: String, multiUser: Array[String]) {
val wb = getWhiteboard(wbId) val wb = getWhiteboard(wbId)
val newWb = wb.copy(multiUser = multiUser, oldMultiUser = wb.multiUser, changedModeOn = System.currentTimeMillis()) val newWb = wb.copy(multiUser = multiUser, oldMultiUser = wb.multiUser, changedModeOn = System.currentTimeMillis())
PresPageWritersDAO.updateMultiuser(meetingId, newWb)
saveWhiteboard(newWb) saveWhiteboard(newWb)
} }

View File

@ -1,6 +1,6 @@
package org.bigbluebutton.core.apps.audiocaptions package org.bigbluebutton.core.apps.audiocaptions
import org.apache.pekko.actor.ActorContext import akka.actor.ActorContext
class AudioCaptionsApp2x(implicit val context: ActorContext) class AudioCaptionsApp2x(implicit val context: ActorContext)
extends UpdateTranscriptPubMsgHdlr extends UpdateTranscriptPubMsgHdlr

View File

@ -2,7 +2,6 @@ package org.bigbluebutton.core.apps.audiocaptions
import org.bigbluebutton.common2.msgs._ import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.bus.MessageBus import org.bigbluebutton.core.bus.MessageBus
import org.bigbluebutton.core.db.UserTranscriptionErrorDAO
import org.bigbluebutton.core.models.AudioCaptions import org.bigbluebutton.core.models.AudioCaptions
import org.bigbluebutton.core.running.LiveMeeting import org.bigbluebutton.core.running.LiveMeeting
@ -24,8 +23,5 @@ trait TranscriptionProviderErrorMsgHdlr {
} }
broadcastEvent(msg.header.userId, msg.body.errorCode, msg.body.errorMessage) broadcastEvent(msg.header.userId, msg.body.errorCode, msg.body.errorMessage)
UserTranscriptionErrorDAO.insert(msg.header.userId, msg.header.meetingId, msg.body.errorCode, msg.body.errorMessage)
} }
} }

View File

@ -1,13 +1,9 @@
package org.bigbluebutton.core.apps.audiocaptions package org.bigbluebutton.core.apps.audiocaptions
import org.bigbluebutton.ClientSettings.getConfigPropertyValueByPathAsStringOrElse
import org.bigbluebutton.common2.msgs._ import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.bus.MessageBus import org.bigbluebutton.core.bus.MessageBus
import org.bigbluebutton.core.db.CaptionDAO import org.bigbluebutton.core.models.AudioCaptions
import org.bigbluebutton.core.models.{AudioCaptions, UserState, Pads, Users2x}
import org.bigbluebutton.core.running.LiveMeeting import org.bigbluebutton.core.running.LiveMeeting
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
trait UpdateTranscriptPubMsgHdlr { trait UpdateTranscriptPubMsgHdlr {
this: AudioCaptionsApp2x => this: AudioCaptionsApp2x =>
@ -26,17 +22,6 @@ trait UpdateTranscriptPubMsgHdlr {
bus.outGW.send(msgEvent) bus.outGW.send(msgEvent)
} }
def sendPadUpdateCmdMsg(groupId: String, defaultPad: String, text: String, transcript: Boolean): Unit = {
val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka")
val envelope = BbbCoreEnvelope(PadUpdateCmdMsg.NAME, routing)
val header = BbbCoreHeaderWithMeetingId(PadUpdateCmdMsg.NAME, liveMeeting.props.meetingProp.intId)
val body = PadUpdateCmdMsgBody(groupId, defaultPad, text)
val event = PadUpdateCmdMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
bus.outGW.send(msgEvent)
}
// Adapt to the current captions' recording process // Adapt to the current captions' recording process
def editTranscript( def editTranscript(
userId: String, userId: String,
@ -78,13 +63,6 @@ trait UpdateTranscriptPubMsgHdlr {
val transcript = AudioCaptions.parseTranscript(msg.body.transcript) val transcript = AudioCaptions.parseTranscript(msg.body.transcript)
for {
u <- Users2x.findWithIntId(liveMeeting.users2x, msg.header.userId)
} yield {
CaptionDAO.insertOrUpdateCaption(msg.body.transcriptId, meetingId, msg.header.userId, transcript, u.speechLocale)
}
broadcastEvent( broadcastEvent(
msg.header.userId, msg.header.userId,
msg.body.transcriptId, msg.body.transcriptId,
@ -92,31 +70,6 @@ trait UpdateTranscriptPubMsgHdlr {
msg.body.locale, msg.body.locale,
msg.body.result, msg.body.result,
) )
if(msg.body.result) {
val userName = Users2x.findWithIntId(liveMeeting.users2x, msg.header.userId).get match {
case u: UserState => u.name
case _ => "???"
}
val now = LocalDateTime.now()
val formatter = DateTimeFormatter.ofPattern("HH:mm:ss")
val formattedTime = now.format(formatter)
val userSpoke = s"\n $userName ($formattedTime): $transcript"
val defaultPad = getConfigPropertyValueByPathAsStringOrElse(
liveMeeting.clientSettings,
"public.captions.defaultPad",
alternativeValue = ""
)
Pads.getGroup(liveMeeting.pads, defaultPad) match {
case Some(group) => sendPadUpdateCmdMsg(group.groupId, defaultPad, userSpoke, transcript = true)
case _ =>
}
}
} }
} }
} }

View File

@ -16,7 +16,6 @@ trait BreakoutApp2x extends BreakoutRoomCreatedMsgHdlr
with SendMessageToAllBreakoutRoomsMsgHdlr with SendMessageToAllBreakoutRoomsMsgHdlr
with SendMessageToBreakoutRoomInternalMsgHdlr with SendMessageToBreakoutRoomInternalMsgHdlr
with RequestBreakoutJoinURLReqMsgHdlr with RequestBreakoutJoinURLReqMsgHdlr
with SetBreakoutRoomInviteDismissedReqMsgHdlr
with SendBreakoutUsersUpdateMsgHdlr with SendBreakoutUsersUpdateMsgHdlr
with TransferUserToMeetingRequestHdlr with TransferUserToMeetingRequestHdlr
with EndBreakoutRoomInternalMsgHdlr with EndBreakoutRoomInternalMsgHdlr
@ -63,23 +62,13 @@ object BreakoutRoomsUtil extends SystemConfiguration {
checksum(apiCall.concat(baseString).concat(sharedSecret)) checksum(apiCall.concat(baseString).concat(sharedSecret))
} }
def joinParams( def joinParams(username: String, userId: String, isBreakout: Boolean, breakoutMeetingId: String,
username: String, password: String): (collection.immutable.Map[String, String], collection.immutable.Map[String, String]) = {
userId: String,
isBreakout: Boolean,
breakoutMeetingId: String,
avatarURL: String,
role: String,
password: String
): (collection.immutable.Map[String, String], collection.immutable.Map[String, String]) = {
val moderator = role == "MODERATOR"
val params = collection.immutable.HashMap( val params = collection.immutable.HashMap(
"fullName" -> urlEncode(username), "fullName" -> urlEncode(username),
"userID" -> urlEncode(userId), "userID" -> urlEncode(userId),
"isBreakout" -> urlEncode(isBreakout.toString()), "isBreakout" -> urlEncode(isBreakout.toString()),
"meetingID" -> urlEncode(breakoutMeetingId), "meetingID" -> urlEncode(breakoutMeetingId),
"avatarURL" -> urlEncode(avatarURL),
"userdata-bbb_parent_room_moderator" -> urlEncode(moderator.toString()),
"password" -> urlEncode(password), "password" -> urlEncode(password),
"redirect" -> urlEncode("true") "redirect" -> urlEncode("true")
) )

View File

@ -41,15 +41,8 @@ object BreakoutHdlrHelpers extends SystemConfiguration {
for { for {
user <- Users2x.findWithIntId(liveMeeting.users2x, userId) user <- Users2x.findWithIntId(liveMeeting.users2x, userId)
apiCall = "join" apiCall = "join"
(redirectParams, redirectToHtml5Params) = BreakoutRoomsUtil.joinParams( (redirectParams, redirectToHtml5Params) = BreakoutRoomsUtil.joinParams(user.name, userId + "-" + roomSequence, true,
user.name, externalMeetingId, liveMeeting.props.password.moderatorPass)
userId + "-" + roomSequence,
true,
externalMeetingId,
user.avatar,
user.role,
liveMeeting.props.password.moderatorPass
)
// We generate a first url with redirect -> true // We generate a first url with redirect -> true
redirectBaseString = BreakoutRoomsUtil.createBaseString(redirectParams) redirectBaseString = BreakoutRoomsUtil.createBaseString(redirectParams)
redirectJoinURL = BreakoutRoomsUtil.createJoinURL(bbbWebAPI, apiCall, redirectBaseString, redirectJoinURL = BreakoutRoomsUtil.createJoinURL(bbbWebAPI, apiCall, redirectBaseString,
@ -125,7 +118,7 @@ object BreakoutHdlrHelpers extends SystemConfiguration {
eventBus.publish(BigBlueButtonEvent( eventBus.publish(BigBlueButtonEvent(
liveMeeting.props.breakoutProps.parentId, liveMeeting.props.breakoutProps.parentId,
BreakoutRoomUsersUpdateInternalMsg(liveMeeting.props.breakoutProps.parentId, liveMeeting.props.meetingProp.intId, new BreakoutRoomUsersUpdateInternalMsg(liveMeeting.props.breakoutProps.parentId, liveMeeting.props.meetingProp.intId,
breakoutUsers, breakoutVoiceUsers) breakoutUsers, breakoutVoiceUsers)
)) ))
} }

View File

@ -3,7 +3,6 @@ package org.bigbluebutton.core.apps.breakout
import org.bigbluebutton.common2.msgs._ import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.api.BreakoutRoomCreatedInternalMsg import org.bigbluebutton.core.api.BreakoutRoomCreatedInternalMsg
import org.bigbluebutton.core.apps.BreakoutModel import org.bigbluebutton.core.apps.BreakoutModel
import org.bigbluebutton.core.db.BreakoutRoomDAO
import org.bigbluebutton.core.domain.{ BreakoutRoom2x, MeetingState2x } import org.bigbluebutton.core.domain.{ BreakoutRoom2x, MeetingState2x }
import org.bigbluebutton.core.running.{ LiveMeeting, MeetingActor, OutMsgRouter } import org.bigbluebutton.core.running.{ LiveMeeting, MeetingActor, OutMsgRouter }
@ -22,12 +21,9 @@ trait BreakoutRoomCreatedMsgHdlr {
} yield { } yield {
val updatedRoom = sendBreakoutRoomStarted(startedRoom) val updatedRoom = sendBreakoutRoomStarted(startedRoom)
var updatedModel = breakoutModel.update(updatedRoom) var updatedModel = breakoutModel.update(updatedRoom)
// BreakoutRoomDAO.updateRoomStarted(room.id)
// We postpone sending invitation until all breakout rooms have been created // We postpone sending invitation until all breakout rooms have been created
if (updatedModel.hasAllStarted()) { if (updatedModel.hasAllStarted()) {
updatedModel = updatedModel.copy(startedOn = Some(System.currentTimeMillis())) updatedModel = updatedModel.copy(startedOn = Some(System.currentTimeMillis()))
BreakoutRoomDAO.updateRoomsStarted(room.parentId)
updatedModel = sendBreakoutRoomsList(updatedModel) updatedModel = sendBreakoutRoomsList(updatedModel)
} }
updatedModel updatedModel

View File

@ -1,7 +1,6 @@
package org.bigbluebutton.core.apps.breakout package org.bigbluebutton.core.apps.breakout
import org.bigbluebutton.core.api.BreakoutRoomEndedInternalMsg import org.bigbluebutton.core.api.BreakoutRoomEndedInternalMsg
import org.bigbluebutton.core.db.{ BreakoutRoomDAO, NotificationDAO }
import org.bigbluebutton.core.domain.MeetingState2x import org.bigbluebutton.core.domain.MeetingState2x
import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter } import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter }
import org.bigbluebutton.core2.message.senders.MsgBuilder import org.bigbluebutton.core2.message.senders.MsgBuilder
@ -37,9 +36,7 @@ trait BreakoutRoomEndedInternalMsgHdlr {
Vector() Vector()
) )
outGW.send(notifyEvent) outGW.send(notifyEvent)
NotificationDAO.insert(notifyEvent)
BreakoutRoomDAO.updateRoomsEnded(liveMeeting.props.meetingProp.intId)
state.update(None) state.update(None)
} else { } else {
state.update(Some(model)) state.update(Some(model))

View File

@ -1,8 +1,8 @@
package org.bigbluebutton.core.apps.breakout package org.bigbluebutton.core.apps.breakout
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.api.BreakoutRoomUsersUpdateInternalMsg import org.bigbluebutton.core.api.BreakoutRoomUsersUpdateInternalMsg
import org.bigbluebutton.core.db.{ BreakoutRoomUserDAO, UserBreakoutRoomDAO } import org.bigbluebutton.core.domain.{ BreakoutRoom2x, MeetingState2x }
import org.bigbluebutton.core.domain.MeetingState2x
import org.bigbluebutton.core.models.{ RegisteredUsers, Users2x } import org.bigbluebutton.core.models.{ RegisteredUsers, Users2x }
import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter } import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter }
@ -13,11 +13,24 @@ trait BreakoutRoomUsersUpdateMsgHdlr {
def handleBreakoutRoomUsersUpdateInternalMsg(msg: BreakoutRoomUsersUpdateInternalMsg, state: MeetingState2x): MeetingState2x = { def handleBreakoutRoomUsersUpdateInternalMsg(msg: BreakoutRoomUsersUpdateInternalMsg, state: MeetingState2x): MeetingState2x = {
def broadcastEvent(room: BreakoutRoom2x): BbbCommonEnvCoreMsg = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, props.meetingProp.intId, "not-used")
val envelope = BbbCoreEnvelope(UpdateBreakoutUsersEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(UpdateBreakoutUsersEvtMsg.NAME, props.meetingProp.intId, "not-used")
val users = room.users.map(u => BreakoutUserVO(u.id, u.name))
val body = UpdateBreakoutUsersEvtMsgBody(props.meetingProp.intId, msg.breakoutId, users)
val event = UpdateBreakoutUsersEvtMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
val breakoutModel = for { val breakoutModel = for {
model <- state.breakout model <- state.breakout
room <- model.find(msg.breakoutId) room <- model.find(msg.breakoutId)
} yield { } yield {
val updatedRoom = room.copy(users = msg.users, voiceUsers = msg.voiceUsers) val updatedRoom = room.copy(users = msg.users, voiceUsers = msg.voiceUsers)
val msgEvent = broadcastEvent(updatedRoom)
outGW.send(msgEvent)
//Update user lastActivityTime in parent room (to avoid be ejected while is in Breakout room) //Update user lastActivityTime in parent room (to avoid be ejected while is in Breakout room)
for { for {
@ -35,12 +48,6 @@ trait BreakoutRoomUsersUpdateMsgHdlr {
} }
} }
val usersInRoom = for {
breakoutRoomUser <- updatedRoom.users
u <- RegisteredUsers.findWithBreakoutRoomId(breakoutRoomUser.id, liveMeeting.registeredUsers)
} yield u.id
UserBreakoutRoomDAO.updateLastBreakoutRoom(props.meetingProp.intId, usersInRoom, updatedRoom)
BreakoutRoomUserDAO.updateUserJoined(props.meetingProp.intId, usersInRoom, updatedRoom)
model.update(updatedRoom) model.update(updatedRoom)
} }

View File

@ -2,14 +2,13 @@ package org.bigbluebutton.core.apps.breakout
import org.bigbluebutton.common2.msgs._ import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.api.EjectUserFromBreakoutInternalMsg import org.bigbluebutton.core.api.EjectUserFromBreakoutInternalMsg
import org.bigbluebutton.core.apps.breakout.BreakoutHdlrHelpers.getRedirectUrls import org.bigbluebutton.core.apps.breakout.BreakoutHdlrHelpers.{ getRedirectUrls }
import org.bigbluebutton.core.apps.{PermissionCheck, RightsManagementTrait} import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
import org.bigbluebutton.core.bus.BigBlueButtonEvent import org.bigbluebutton.core.bus.BigBlueButtonEvent
import org.bigbluebutton.core.db.{BreakoutRoomUserDAO, NotificationDAO}
import org.bigbluebutton.core.domain.MeetingState2x import org.bigbluebutton.core.domain.MeetingState2x
import org.bigbluebutton.core.models.EjectReasonCode import org.bigbluebutton.core.models.{ EjectReasonCode }
import org.bigbluebutton.core.running.{MeetingActor, OutMsgRouter} import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter }
import org.bigbluebutton.core2.message.senders.MsgBuilder import org.bigbluebutton.core2.message.senders.{ MsgBuilder }
trait ChangeUserBreakoutReqMsgHdlr extends RightsManagementTrait { trait ChangeUserBreakoutReqMsgHdlr extends RightsManagementTrait {
this: MeetingActor => this: MeetingActor =>
@ -29,6 +28,7 @@ trait ChangeUserBreakoutReqMsgHdlr extends RightsManagementTrait {
for { for {
breakoutModel <- state.breakout breakoutModel <- state.breakout
} yield { } yield {
//Eject user from room From //Eject user from room From
for { for {
roomFrom <- breakoutModel.rooms.get(msg.body.fromBreakoutId) roomFrom <- breakoutModel.rooms.get(msg.body.fromBreakoutId)
@ -38,9 +38,6 @@ trait ChangeUserBreakoutReqMsgHdlr extends RightsManagementTrait {
}) })
} }
val isSameRoom = msg.body.fromBreakoutId == msg.body.toBreakoutId
val removePreviousRoomFromDb = !breakoutModel.rooms.exists(r => r._2.freeJoin) && !isSameRoom
//Get join URL for room To //Get join URL for room To
val redirectToHtml5JoinURL = ( val redirectToHtml5JoinURL = (
for { for {
@ -49,6 +46,7 @@ trait ChangeUserBreakoutReqMsgHdlr extends RightsManagementTrait {
} yield redirectToHtml5JoinURL } yield redirectToHtml5JoinURL
).getOrElse("") ).getOrElse("")
BreakoutHdlrHelpers.sendChangeUserBreakoutMsg( BreakoutHdlrHelpers.sendChangeUserBreakoutMsg(
outGW, outGW,
meetingId, meetingId,
@ -58,15 +56,6 @@ trait ChangeUserBreakoutReqMsgHdlr extends RightsManagementTrait {
redirectToHtml5JoinURL, redirectToHtml5JoinURL,
) )
//Update database
BreakoutRoomUserDAO.updateRoomChanged(
meetingId,
msg.body.userId,
msg.body.fromBreakoutId,
msg.body.toBreakoutId,
redirectToHtml5JoinURL,
removePreviousRoomFromDb)
//Send notification to moved User //Send notification to moved User
for { for {
roomFrom <- breakoutModel.rooms.get(msg.body.fromBreakoutId) roomFrom <- breakoutModel.rooms.get(msg.body.fromBreakoutId)
@ -82,7 +71,6 @@ trait ChangeUserBreakoutReqMsgHdlr extends RightsManagementTrait {
Vector(roomTo.shortName) Vector(roomTo.shortName)
) )
outGW.send(notifyUserEvent) outGW.send(notifyUserEvent)
NotificationDAO.insert(notifyUserEvent)
} }
} }

View File

@ -1,12 +1,10 @@
package org.bigbluebutton.core.apps.breakout package org.bigbluebutton.core.apps.breakout
import org.bigbluebutton.ClientSettings.{getConfigPropertyValueByPath, getConfigPropertyValueByPathAsIntOrElse}
import org.bigbluebutton.common2.msgs._ import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.apps.{BreakoutModel, PermissionCheck, RightsManagementTrait} import org.bigbluebutton.core.apps.{ BreakoutModel, PermissionCheck, RightsManagementTrait }
import org.bigbluebutton.core.db.BreakoutRoomDAO import org.bigbluebutton.core.domain.{ BreakoutRoom2x, MeetingState2x }
import org.bigbluebutton.core.domain.{BreakoutRoom2x, MeetingState2x}
import org.bigbluebutton.core.models.PresentationInPod import org.bigbluebutton.core.models.PresentationInPod
import org.bigbluebutton.core.running.{LiveMeeting, OutMsgRouter} import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter }
import org.bigbluebutton.core.running.MeetingActor import org.bigbluebutton.core.running.MeetingActor
trait CreateBreakoutRoomsCmdMsgHdlr extends RightsManagementTrait { trait CreateBreakoutRoomsCmdMsgHdlr extends RightsManagementTrait {
@ -17,10 +15,6 @@ trait CreateBreakoutRoomsCmdMsgHdlr extends RightsManagementTrait {
def handleCreateBreakoutRoomsCmdMsg(msg: CreateBreakoutRoomsCmdMsg, state: MeetingState2x): MeetingState2x = { def handleCreateBreakoutRoomsCmdMsg(msg: CreateBreakoutRoomsCmdMsg, state: MeetingState2x): MeetingState2x = {
val minOfRooms = 2
val maxOfRooms = getConfigPropertyValueByPathAsIntOrElse(liveMeeting.clientSettings, "public.app.breakouts.breakoutRoomLimit", 16)
if (liveMeeting.props.meetingProp.disabledFeatures.contains("breakoutRooms")) { if (liveMeeting.props.meetingProp.disabledFeatures.contains("breakoutRooms")) {
val meetingId = liveMeeting.props.meetingProp.intId val meetingId = liveMeeting.props.meetingProp.intId
val reason = "Breakout rooms is disabled for this meeting." val reason = "Breakout rooms is disabled for this meeting."
@ -32,15 +26,6 @@ trait CreateBreakoutRoomsCmdMsgHdlr extends RightsManagementTrait {
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId,
reason, outGW, liveMeeting) reason, outGW, liveMeeting)
state state
} else if(msg.body.rooms.length > maxOfRooms || msg.body.rooms.length < minOfRooms) {
log.warning(
"Attempt to create breakout rooms with invalid number of rooms (rooms: {}, max: {}, min: {}) in meeting {}",
msg.body.rooms.size,
maxOfRooms,
minOfRooms,
liveMeeting.props.meetingProp.intId
)
state
} else { } else {
state.breakout match { state.breakout match {
case Some(breakout) => case Some(breakout) =>
@ -69,9 +54,9 @@ trait CreateBreakoutRoomsCmdMsgHdlr extends RightsManagementTrait {
val voiceConf = BreakoutRoomsUtil.createVoiceConfId(liveMeeting.props.voiceProp.voiceConf, i) val voiceConf = BreakoutRoomsUtil.createVoiceConfId(liveMeeting.props.voiceProp.voiceConf, i)
val breakout = BreakoutModel.create(parentId, internalId, externalId, room.name, room.sequence, room.shortName, val breakout = BreakoutModel.create(parentId, internalId, externalId, room.name, room.sequence, room.shortName,
room.isDefaultName, room.freeJoin, voiceConf, room.users, msg.body.captureNotes, room.isDefaultName, room.freeJoin, voiceConf, room.users, msg.body.captureNotes,
msg.body.captureSlides, room.captureNotesFilename, room.captureSlidesFilename, msg.body.captureSlides, room.captureNotesFilename, room.captureSlidesFilename,
room.allPages, roomPresId) room.allPages, roomPresId, room.sourcePresentationFilename)
rooms = rooms + (breakout.id -> breakout) rooms = rooms + (breakout.id -> breakout)
} }
@ -88,18 +73,18 @@ trait CreateBreakoutRoomsCmdMsgHdlr extends RightsManagementTrait {
breakout.freeJoin, breakout.freeJoin,
liveMeeting.props.voiceProp.dialNumber, liveMeeting.props.voiceProp.dialNumber,
breakout.voiceConf, breakout.voiceConf,
msg.body.durationInMinutes, msg.body.durationInMinutes * 60,
liveMeeting.props.password.moderatorPass, liveMeeting.props.password.moderatorPass,
liveMeeting.props.password.viewerPass, liveMeeting.props.password.viewerPass,
breakout.presId, breakout.presId,
roomSlides, roomSlides,
breakout.sourcePresentationFilename,
msg.body.record, msg.body.record,
liveMeeting.props.breakoutProps.privateChatEnabled, liveMeeting.props.breakoutProps.privateChatEnabled,
breakout.captureNotes, breakout.captureNotes,
breakout.captureSlides, breakout.captureSlides,
breakout.captureNotesFilename, breakout.captureNotesFilename,
breakout.captureSlidesFilename, breakout.captureSlidesFilename,
pluginProp = liveMeeting.props.pluginProp,
) )
val event = buildCreateBreakoutRoomSysCmdMsg(liveMeeting.props.meetingProp.intId, roomDetail) val event = buildCreateBreakoutRoomSysCmdMsg(liveMeeting.props.meetingProp.intId, roomDetail)
@ -107,7 +92,6 @@ trait CreateBreakoutRoomsCmdMsgHdlr extends RightsManagementTrait {
} }
val breakoutModel = new BreakoutModel(None, msg.body.durationInMinutes * 60, rooms, msg.body.sendInviteToModerators) val breakoutModel = new BreakoutModel(None, msg.body.durationInMinutes * 60, rooms, msg.body.sendInviteToModerators)
BreakoutRoomDAO.insert(breakoutModel, liveMeeting)
state.update(Some(breakoutModel)) state.update(Some(breakoutModel))
} }

View File

@ -2,8 +2,7 @@ package org.bigbluebutton.core.apps.breakout
import org.bigbluebutton.core.api.EjectUserFromBreakoutInternalMsg import org.bigbluebutton.core.api.EjectUserFromBreakoutInternalMsg
import org.bigbluebutton.core.apps.users.UsersApp import org.bigbluebutton.core.apps.users.UsersApp
import org.bigbluebutton.core.db.{ BreakoutRoomUserDAO, UserDAO } import org.bigbluebutton.core.models.{ RegisteredUsers }
import org.bigbluebutton.core.models.RegisteredUsers
import org.bigbluebutton.core.running.{ LiveMeeting, MeetingActor, OutMsgRouter } import org.bigbluebutton.core.running.{ LiveMeeting, MeetingActor, OutMsgRouter }
import org.bigbluebutton.core2.message.senders.Sender import org.bigbluebutton.core2.message.senders.Sender
@ -28,12 +27,8 @@ trait EjectUserFromBreakoutInternalMsgHdlr {
msg.reasonCode, msg.reasonCode,
msg.ban msg.ban
) )
// send a system message to force disconnection
//TODO inform reason Sender.sendDisconnectClientSysMsg(msg.breakoutId, registeredUser.id, msg.ejectedBy, msg.reasonCode, outGW)
UserDAO.softDelete(registeredUser.meetingId, registeredUser.id)
// Force reconnection with graphql to refresh permissions
Sender.sendForceUserGraphqlReconnectionSysMsg(liveMeeting.props.meetingProp.intId, registeredUser.id, registeredUser.sessionToken, msg.reasonCode, outGW)
//send users update to parent meeting //send users update to parent meeting
BreakoutHdlrHelpers.updateParentMeetingWithUsers(liveMeeting, eventBus) BreakoutHdlrHelpers.updateParentMeetingWithUsers(liveMeeting, eventBus)

View File

@ -6,8 +6,7 @@ import org.bigbluebutton.core.bus.BigBlueButtonEvent
import org.bigbluebutton.core.domain.{ MeetingEndReason, MeetingState2x } import org.bigbluebutton.core.domain.{ MeetingEndReason, MeetingState2x }
import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter } import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter }
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait } import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
import org.bigbluebutton.core.db.{ BreakoutRoomDAO, NotificationDAO, UserBreakoutRoomDAO } import org.bigbluebutton.core2.message.senders.{ MsgBuilder }
import org.bigbluebutton.core2.message.senders.MsgBuilder
trait EndAllBreakoutRoomsMsgHdlr extends RightsManagementTrait { trait EndAllBreakoutRoomsMsgHdlr extends RightsManagementTrait {
this: MeetingActor => this: MeetingActor =>
@ -21,20 +20,25 @@ trait EndAllBreakoutRoomsMsgHdlr extends RightsManagementTrait {
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, outGW, liveMeeting) PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, outGW, liveMeeting)
state state
} else { } else {
endAllBreakoutRooms(eventBus, liveMeeting, state, MeetingEndReason.BREAKOUT_ENDED_BY_MOD) for {
model <- state.breakout
} yield {
model.rooms.values.foreach { room =>
eventBus.publish(BigBlueButtonEvent(room.id, EndBreakoutRoomInternalMsg(meetingId, room.id, MeetingEndReason.BREAKOUT_ENDED_BY_MOD)))
}
val notifyEvent = MsgBuilder.buildNotifyAllInMeetingEvtMsg( val notifyEvent = MsgBuilder.buildNotifyAllInMeetingEvtMsg(
meetingId, meetingId,
"info", "info",
"rooms", "rooms",
"app.toast.breakoutRoomEnded", "app.toast.breakoutRoomEnded",
"Message when the breakout room is ended", "Message when the breakout room is ended",
Vector() Vector()
) )
outGW.send(notifyEvent) outGW.send(notifyEvent)
NotificationDAO.insert(notifyEvent)
}
BreakoutRoomDAO.updateRoomsEnded(meetingId)
state.update(None) state.update(None)
} }
} }

View File

@ -1,11 +1,7 @@
package org.bigbluebutton.core.apps.breakout package org.bigbluebutton.core.apps.breakout
import org.bigbluebutton.common2.msgs.{ BbbClientMsgHeader, BbbCommonEnvCoreMsg, BbbCoreEnvelope, BbbCoreHeaderWithMeetingId, ExportJob, MessageTypes, PresentationConversionUpdateEvtMsg, PresentationConversionUpdateEvtMsgBody, PresentationConversionUpdateSysPubMsg, PresentationPageForExport, PresentationUploadTokenSysPubMsg, PresentationUploadTokenSysPubMsgBody, Routing, StoreExportJobInRedisSysMsg, StoreExportJobInRedisSysMsgBody, StoredAnnotations } import org.bigbluebutton.core.api.{ CaptureSharedNotesReqInternalMsg, CapturePresentationReqInternalMsg, EndBreakoutRoomInternalMsg }
import org.bigbluebutton.core.api.{ CapturePresentationReqInternalMsg, EndBreakoutRoomInternalMsg }
import org.bigbluebutton.core.apps.presentationpod.PresentationPodsApp
import org.bigbluebutton.core.bus.{ BigBlueButtonEvent, InternalEventBus } import org.bigbluebutton.core.bus.{ BigBlueButtonEvent, InternalEventBus }
import org.bigbluebutton.core.db.{ PresPresentationDAO }
import org.bigbluebutton.core.models.{ Pads, PresentationInPod, PresentationPage, PresentationPod }
import org.bigbluebutton.core.running.{ BaseMeetingActor, HandlerHelpers, LiveMeeting, OutMsgRouter } import org.bigbluebutton.core.running.{ BaseMeetingActor, HandlerHelpers, LiveMeeting, OutMsgRouter }
trait EndBreakoutRoomInternalMsgHdlr extends HandlerHelpers { trait EndBreakoutRoomInternalMsgHdlr extends HandlerHelpers {
@ -23,80 +19,12 @@ trait EndBreakoutRoomInternalMsgHdlr extends HandlerHelpers {
} }
if (liveMeeting.props.breakoutProps.captureNotes) { if (liveMeeting.props.breakoutProps.captureNotes) {
handleCaptureNotes(msg) val filename = liveMeeting.props.breakoutProps.captureNotesFilename
val captureNotesEvent = BigBlueButtonEvent(msg.parentId, CaptureSharedNotesReqInternalMsg(msg.breakoutId, filename))
eventBus.publish(captureNotesEvent)
} }
log.info("Breakout room {} ended by parent meeting {}.", msg.breakoutId, msg.parentId) log.info("Breakout room {} ended by parent meeting {}.", msg.breakoutId, msg.parentId)
sendEndMeetingDueToExpiry(msg.reason, eventBus, outGW, liveMeeting, "system") sendEndMeetingDueToExpiry(msg.reason, eventBus, outGW, liveMeeting, "system")
} }
def handleCaptureNotes(msg: EndBreakoutRoomInternalMsg) {
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)
var pres = new PresentationInPod(presentationId, default = false, current = false, name = filename,
pages = Map.empty, downloadable = false, downloadFileExtension = "", removable = true, filenameConverted = filename,
uploadCompleted = false, numPages = 0, errorMsgKey = "", errorDetails = Map.empty)
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 {
pres = pres.copy(errorMsgKey = "204")
val event = buildPresentationConversionUpdateEvtMsg(msg.parentId, presentationId, filename, jobId)
outGW.send(event)
}
PresPresentationDAO.updateConversionStarted(msg.parentId, pres)
}
}
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)
}
} }

View File

@ -4,8 +4,7 @@ import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.domain.MeetingState2x import org.bigbluebutton.core.domain.MeetingState2x
import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter } import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter }
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait } import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
import org.bigbluebutton.core.db.BreakoutRoomUserDAO import org.bigbluebutton.core.models.{ Users2x, Roles }
import org.bigbluebutton.core.models.{ Roles, Users2x }
trait RequestBreakoutJoinURLReqMsgHdlr extends RightsManagementTrait { trait RequestBreakoutJoinURLReqMsgHdlr extends RightsManagementTrait {
this: MeetingActor => this: MeetingActor =>
@ -24,9 +23,6 @@ trait RequestBreakoutJoinURLReqMsgHdlr extends RightsManagementTrait {
requesterUser <- Users2x.findWithIntId(liveMeeting.users2x, msg.header.userId) requesterUser <- Users2x.findWithIntId(liveMeeting.users2x, msg.header.userId)
} yield { } yield {
if (requesterUser.role == Roles.MODERATOR_ROLE || room.freeJoin) { if (requesterUser.role == Roles.MODERATOR_ROLE || room.freeJoin) {
BreakoutRoomUserDAO.insertBreakoutRoom(requesterUser.intId, room, liveMeeting)
BreakoutHdlrHelpers.sendJoinURL( BreakoutHdlrHelpers.sendJoinURL(
liveMeeting, liveMeeting,
outGW, outGW,

View File

@ -0,0 +1,15 @@
package org.bigbluebutton.core.apps.breakout
import org.bigbluebutton.core.api.SendBreakoutTimeRemainingInternalMsg
import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter }
import org.bigbluebutton.core2.message.senders.MsgBuilder
trait SendBreakoutTimeRemainingInternalMsgHdlr {
val liveMeeting: LiveMeeting
val outGW: OutMsgRouter
def handleSendBreakoutTimeRemainingInternalMsg(msg: SendBreakoutTimeRemainingInternalMsg): Unit = {
val event = MsgBuilder.buildMeetingTimeRemainingUpdateEvtMsg(liveMeeting.props.meetingProp.intId, msg.timeLeftInSec.toInt, msg.timeUpdatedInMinutes)
outGW.send(event)
}
}

View File

@ -1,14 +1,13 @@
package org.bigbluebutton.core.apps.breakout package org.bigbluebutton.core.apps.breakout
import org.bigbluebutton.common2.msgs._ import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.api.SendMessageToBreakoutRoomInternalMsg import org.bigbluebutton.core.api.{ SendMessageToBreakoutRoomInternalMsg }
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait } import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
import org.bigbluebutton.core.bus.BigBlueButtonEvent import org.bigbluebutton.core.bus.BigBlueButtonEvent
import org.bigbluebutton.core.db.NotificationDAO
import org.bigbluebutton.core.domain.MeetingState2x import org.bigbluebutton.core.domain.MeetingState2x
import org.bigbluebutton.core.models.RegisteredUsers import org.bigbluebutton.core.models.{ RegisteredUsers }
import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter } import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter }
import org.bigbluebutton.core2.message.senders.MsgBuilder import org.bigbluebutton.core2.message.senders.{ MsgBuilder }
trait SendMessageToAllBreakoutRoomsMsgHdlr extends RightsManagementTrait { trait SendMessageToAllBreakoutRoomsMsgHdlr extends RightsManagementTrait {
this: MeetingActor => this: MeetingActor =>
@ -33,7 +32,7 @@ trait SendMessageToAllBreakoutRoomsMsgHdlr extends RightsManagementTrait {
val event = buildSendMessageToAllBreakoutRoomsEvtMsg(msg.header.userId, msg.body.msg, breakoutModel.rooms.size) val event = buildSendMessageToAllBreakoutRoomsEvtMsg(msg.header.userId, msg.body.msg, breakoutModel.rooms.size)
outGW.send(event) outGW.send(event)
val notifyUserEvent = MsgBuilder.buildNotifyUserInMeetingEvtMsg( val notifyModeratorEvent = MsgBuilder.buildNotifyUserInMeetingEvtMsg(
msg.header.userId, msg.header.userId,
liveMeeting.props.meetingProp.intId, liveMeeting.props.meetingProp.intId,
"info", "info",
@ -42,8 +41,7 @@ trait SendMessageToAllBreakoutRoomsMsgHdlr extends RightsManagementTrait {
"Message for chat sent successfully", "Message for chat sent successfully",
Vector(s"${breakoutModel.rooms.size}") Vector(s"${breakoutModel.rooms.size}")
) )
outGW.send(notifyUserEvent) outGW.send(notifyModeratorEvent)
NotificationDAO.insert(notifyUserEvent)
log.debug("Sending message '{}' to all breakout rooms in meeting {}", msg.body.msg, props.meetingProp.intId) log.debug("Sending message '{}' to all breakout rooms in meeting {}", msg.body.msg, props.meetingProp.intId)
} }

View File

@ -1,6 +1,6 @@
package org.bigbluebutton.core.apps.breakout package org.bigbluebutton.core.apps.breakout
import org.bigbluebutton.common2.msgs.{ GroupChatAccess, GroupChatMessageType, GroupChatMsgFromUser } import org.bigbluebutton.common2.msgs.{ GroupChatAccess, GroupChatMsgFromUser }
import org.bigbluebutton.core.api.SendMessageToBreakoutRoomInternalMsg import org.bigbluebutton.core.api.SendMessageToBreakoutRoomInternalMsg
import org.bigbluebutton.core.apps.groupchats.GroupChatApp import org.bigbluebutton.core.apps.groupchats.GroupChatApp
import org.bigbluebutton.core.bus.MessageBus import org.bigbluebutton.core.bus.MessageBus
@ -18,9 +18,9 @@ trait SendMessageToBreakoutRoomInternalMsgHdlr {
sender <- GroupChatApp.findGroupChatUser(SystemUser.ID, liveMeeting.users2x) sender <- GroupChatApp.findGroupChatUser(SystemUser.ID, liveMeeting.users2x)
chat <- state.groupChats.find(GroupChatApp.MAIN_PUBLIC_CHAT) chat <- state.groupChats.find(GroupChatApp.MAIN_PUBLIC_CHAT)
} yield { } yield {
val groupChatMsgFromUser = GroupChatMsgFromUser(sender.id, sender.copy(name = msg.senderName), msg.msg, replyToMessageId = "") val groupChatMsgFromUser = GroupChatMsgFromUser(sender.id, sender.copy(name = msg.senderName), true, msg.msg)
val gcm = GroupChatApp.toGroupChatMessage(sender.copy(name = msg.senderName), groupChatMsgFromUser, emphasizedText = true) val gcm = GroupChatApp.toGroupChatMessage(sender.copy(name = msg.senderName), groupChatMsgFromUser)
val gcs = GroupChatApp.addGroupChatMessage(liveMeeting.props.meetingProp.intId, chat, state.groupChats, gcm, GroupChatMessageType.BREAKOUTROOM_MOD_MSG) val gcs = GroupChatApp.addGroupChatMessage(chat, state.groupChats, gcm)
val event = buildGroupChatMessageBroadcastEvtMsg( val event = buildGroupChatMessageBroadcastEvtMsg(
liveMeeting.props.meetingProp.intId, liveMeeting.props.meetingProp.intId,

View File

@ -1,22 +0,0 @@
package org.bigbluebutton.core.apps.breakout
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
import org.bigbluebutton.core.db.BreakoutRoomUserDAO
import org.bigbluebutton.core.domain.MeetingState2x
import org.bigbluebutton.core.models.{ Roles, Users2x }
import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter }
trait SetBreakoutRoomInviteDismissedReqMsgHdlr extends RightsManagementTrait {
this: MeetingActor =>
val outGW: OutMsgRouter
def handleSetBreakoutRoomInviteDismissedReqMsg(msg: SetBreakoutRoomInviteDismissedReqMsg) = {
for {
requesterUser <- Users2x.findWithIntId(liveMeeting.users2x, msg.header.userId)
} yield {
BreakoutRoomUserDAO.updateInviteDismissedAt(requesterUser.meetingId, requesterUser.intId)
}
}
}

View File

@ -2,7 +2,6 @@ package org.bigbluebutton.core.apps.breakout
import org.bigbluebutton.common2.msgs._ import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.apps.{ BreakoutModel, PermissionCheck, RightsManagementTrait } import org.bigbluebutton.core.apps.{ BreakoutModel, PermissionCheck, RightsManagementTrait }
import org.bigbluebutton.core.db.UserDAO
import org.bigbluebutton.core.domain.MeetingState2x import org.bigbluebutton.core.domain.MeetingState2x
import org.bigbluebutton.core.models.VoiceUsers import org.bigbluebutton.core.models.VoiceUsers
import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter } import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter }
@ -18,13 +17,13 @@ trait TransferUserToMeetingRequestHdlr extends RightsManagementTrait {
val reason = "No permission to transfer user to voice breakout." val reason = "No permission to transfer user to voice breakout."
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, outGW, liveMeeting) PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, outGW, liveMeeting)
} else { } else {
processTransferUserToMeetingRequest(msg) processRequest(msg)
} }
state state
} }
def processTransferUserToMeetingRequest(msg: TransferUserToMeetingRequestMsg) { def processRequest(msg: TransferUserToMeetingRequestMsg) {
if (msg.body.fromMeetingId == liveMeeting.props.meetingProp.intId) { if (msg.body.fromMeetingId == liveMeeting.props.meetingProp.intId) {
// want to transfer from parent meeting to breakout // want to transfer from parent meeting to breakout
for { for {
@ -33,7 +32,6 @@ trait TransferUserToMeetingRequestHdlr extends RightsManagementTrait {
from <- getVoiceConf(msg.body.fromMeetingId, model) from <- getVoiceConf(msg.body.fromMeetingId, model)
voiceUser <- VoiceUsers.findWithIntId(liveMeeting.voiceUsers, msg.body.userId) voiceUser <- VoiceUsers.findWithIntId(liveMeeting.voiceUsers, msg.body.userId)
} yield { } yield {
UserDAO.transferUserToBreakoutRoomAsAudioOnly(msg.body.userId, msg.body.fromMeetingId, msg.body.toMeetingId)
val event = buildTransferUserToVoiceConfSysMsg(from, to, voiceUser.voiceUserId) val event = buildTransferUserToVoiceConfSysMsg(from, to, voiceUser.voiceUserId)
outGW.send(event) outGW.send(event)
} }
@ -55,7 +53,6 @@ trait TransferUserToMeetingRequestHdlr extends RightsManagementTrait {
room <- model.find(msg.body.fromMeetingId) room <- model.find(msg.body.fromMeetingId)
voiceUser <- room.voiceUsers.find(p => p.id == msg.body.userId) voiceUser <- room.voiceUsers.find(p => p.id == msg.body.userId)
} yield { } yield {
UserDAO.transferUserToBreakoutRoomAsAudioOnly(msg.body.userId, msg.body.fromMeetingId, msg.body.toMeetingId)
val event = buildTransferUserToVoiceConfSysMsg(from, to, voiceUser.voiceUserId) val event = buildTransferUserToVoiceConfSysMsg(from, to, voiceUser.voiceUserId)
outGW.send(event) outGW.send(event)
} }

View File

@ -1,10 +1,9 @@
package org.bigbluebutton.core.apps.breakout package org.bigbluebutton.core.apps.breakout
import org.bigbluebutton.common2.msgs._ import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.api.UpdateBreakoutRoomTimeInternalMsg import org.bigbluebutton.core.api.{ UpdateBreakoutRoomTimeInternalMsg, SendTimeRemainingAuditInternalMsg }
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait } import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
import org.bigbluebutton.core.bus.BigBlueButtonEvent import org.bigbluebutton.core.bus.BigBlueButtonEvent
import org.bigbluebutton.core.db.{ BreakoutRoomDAO, MeetingDAO, NotificationDAO }
import org.bigbluebutton.core.domain.MeetingState2x import org.bigbluebutton.core.domain.MeetingState2x
import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter } import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter }
import org.bigbluebutton.core2.message.senders.{ MsgBuilder, Sender } import org.bigbluebutton.core2.message.senders.{ MsgBuilder, Sender }
@ -63,10 +62,9 @@ trait UpdateBreakoutRoomsTimeMsgHdlr extends RightsManagementTrait {
Vector(s"${msg.body.timeInMinutes}") Vector(s"${msg.body.timeInMinutes}")
) )
outGW.send(notifyEvent) outGW.send(notifyEvent)
NotificationDAO.insert(notifyEvent)
} }
val notifyUserEvent = MsgBuilder.buildNotifyUserInMeetingEvtMsg( val notifyModeratorEvent = MsgBuilder.buildNotifyUserInMeetingEvtMsg(
msg.header.userId, msg.header.userId,
liveMeeting.props.meetingProp.intId, liveMeeting.props.meetingProp.intId,
"info", "info",
@ -75,12 +73,9 @@ trait UpdateBreakoutRoomsTimeMsgHdlr extends RightsManagementTrait {
"Sent to the moderator that requested breakout duration change", "Sent to the moderator that requested breakout duration change",
Vector(s"${msg.body.timeInMinutes}") Vector(s"${msg.body.timeInMinutes}")
) )
outGW.send(notifyUserEvent) outGW.send(notifyModeratorEvent)
NotificationDAO.insert(notifyUserEvent)
log.debug("Updating {} minutes for breakout rooms time in meeting {}", msg.body.timeInMinutes, props.meetingProp.intId) log.debug("Updating {} minutes for breakout rooms time in meeting {}", msg.body.timeInMinutes, props.meetingProp.intId)
BreakoutRoomDAO.updateRoomsDuration(props.meetingProp.intId, newDurationInSeconds)
MeetingDAO.updateMeetingDurationByParentMeeting(props.meetingProp.intId, newDurationInSeconds)
breakoutModel.setTime(newDurationInSeconds) breakoutModel.setTime(newDurationInSeconds)
} }
} }
@ -88,11 +83,12 @@ trait UpdateBreakoutRoomsTimeMsgHdlr extends RightsManagementTrait {
val event = buildUpdateBreakoutRoomsTimeEvtMsg(msg.body.timeInMinutes) val event = buildUpdateBreakoutRoomsTimeEvtMsg(msg.body.timeInMinutes)
outGW.send(event) outGW.send(event)
//Force Update time remaining in the clients
eventBus.publish(BigBlueButtonEvent(props.meetingProp.intId, SendTimeRemainingAuditInternalMsg(props.meetingProp.intId, msg.body.timeInMinutes)))
updatedModel match { updatedModel match {
case Some(model) => { case Some(model) => state.update(Some(model))
state.update(Some(model)) case None => state
}
case None => state
} }
} }
} }

View File

@ -1,12 +1,11 @@
package org.bigbluebutton.core.apps.caption package org.bigbluebutton.core.apps.caption
import org.apache.pekko.actor.ActorContext import akka.actor.ActorContext
import org.apache.pekko.event.Logging import akka.event.Logging
import org.bigbluebutton.common2.msgs._ import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.bus.MessageBus import org.bigbluebutton.core.bus.MessageBus
import org.bigbluebutton.core.running.LiveMeeting import org.bigbluebutton.core.running.{ LiveMeeting }
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait } import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
import org.bigbluebutton.core.db.{ CaptionDAO, CaptionLocaleDAO, CaptionTypes }
class CaptionApp2x(implicit val context: ActorContext) extends RightsManagementTrait { class CaptionApp2x(implicit val context: ActorContext) extends RightsManagementTrait {
val log = Logging(context.system, getClass) val log = Logging(context.system, getClass)
@ -15,10 +14,18 @@ class CaptionApp2x(implicit val context: ActorContext) extends RightsManagementT
liveMeeting.captionModel.getHistory() liveMeeting.captionModel.getHistory()
} }
def updateCaptionOwner(liveMeeting: LiveMeeting, name: String, locale: String, userId: String): Map[String, TranscriptVO] = {
liveMeeting.captionModel.updateTranscriptOwner(name, locale, userId)
}
def editCaptionHistory(liveMeeting: LiveMeeting, userId: String, startIndex: Integer, endIndex: Integer, name: String, text: String): Boolean = { def editCaptionHistory(liveMeeting: LiveMeeting, userId: String, startIndex: Integer, endIndex: Integer, name: String, text: String): Boolean = {
liveMeeting.captionModel.editHistory(userId, startIndex, endIndex, name, text) liveMeeting.captionModel.editHistory(userId, startIndex, endIndex, name, text)
} }
def checkCaptionOwnerLogOut(liveMeeting: LiveMeeting, userId: String): Option[(String, TranscriptVO)] = {
liveMeeting.captionModel.checkCaptionOwnerLogOut(userId)
}
def isUserCaptionOwner(liveMeeting: LiveMeeting, userId: String, name: String): Boolean = { def isUserCaptionOwner(liveMeeting: LiveMeeting, userId: String, name: String): Boolean = {
liveMeeting.captionModel.isUserCaptionOwner(userId, name) liveMeeting.captionModel.isUserCaptionOwner(userId, name)
} }
@ -51,23 +58,7 @@ class CaptionApp2x(implicit val context: ActorContext) extends RightsManagementT
} }
} }
} }
def handle(msg: CaptionSubmitTranscriptPubMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
val meetingId = liveMeeting.props.meetingProp.intId
def broadcastSuccessEvent(transcriptId: String, transcript: String, locale: String): Unit = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, msg.header.userId)
val envelope = BbbCoreEnvelope(CaptionSubmitTranscriptEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(CaptionSubmitTranscriptEvtMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId)
val body = CaptionSubmitTranscriptEvtMsgBody(transcriptId, transcript, locale, msg.body.captionType)
val event = CaptionSubmitTranscriptEvtMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
bus.outGW.send(msgEvent)
}
CaptionDAO.insertOrUpdateCaption(msg.body.transcriptId, meetingId, msg.header.userId,
msg.body.transcript, msg.body.locale, msg.body.captionType)
broadcastSuccessEvent(msg.body.transcriptId, msg.body.transcript, msg.body.locale)
}
def handle(msg: SendCaptionHistoryReqMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = { def handle(msg: SendCaptionHistoryReqMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
def broadcastEvent(msg: SendCaptionHistoryReqMsg, history: Map[String, TranscriptVO]): Unit = { def broadcastEvent(msg: SendCaptionHistoryReqMsg, history: Map[String, TranscriptVO]): Unit = {
val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, liveMeeting.props.meetingProp.intId, msg.header.userId) val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, liveMeeting.props.meetingProp.intId, msg.header.userId)
@ -83,25 +74,45 @@ class CaptionApp2x(implicit val context: ActorContext) extends RightsManagementT
broadcastEvent(msg, getCaptionHistory(liveMeeting)) broadcastEvent(msg, getCaptionHistory(liveMeeting))
} }
def handle(msg: AddCaptionLocalePubMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = { def handle(msg: UpdateCaptionOwnerPubMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
def broadcastAddCaptionLocaleEvent(locale: String, userId: String): Unit = { def broadcastUpdateCaptionOwnerEvent(name: String, locale: String, newOwnerId: String): Unit = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, userId) val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, newOwnerId)
val envelope = BbbCoreEnvelope(AddCaptionLocaleEvtMsg.NAME, routing) val envelope = BbbCoreEnvelope(UpdateCaptionOwnerEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(AddCaptionLocaleEvtMsg.NAME, liveMeeting.props.meetingProp.intId, userId) val header = BbbClientMsgHeader(UpdateCaptionOwnerEvtMsg.NAME, liveMeeting.props.meetingProp.intId, newOwnerId)
val body = AddCaptionLocaleEvtMsgBody(locale) val body = UpdateCaptionOwnerEvtMsgBody(name, locale, newOwnerId)
val event = AddCaptionLocaleEvtMsg(header, body) val event = UpdateCaptionOwnerEvtMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event) val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
bus.outGW.send(msgEvent) bus.outGW.send(msgEvent)
CaptionLocaleDAO.insertOrUpdateCaptionLocale(liveMeeting.props.meetingProp.intId, locale, CaptionTypes.TYPED, userId)
} }
if (permissionFailed(PermissionCheck.MOD_LEVEL, PermissionCheck.VIEWER_LEVEL, liveMeeting.users2x, msg.header.userId)) { if (permissionFailed(PermissionCheck.MOD_LEVEL, PermissionCheck.VIEWER_LEVEL, liveMeeting.users2x, msg.header.userId)) {
val meetingId = liveMeeting.props.meetingProp.intId val meetingId = liveMeeting.props.meetingProp.intId
val reason = "No permission to add caption locale." val reason = "No permission to change caption owners."
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW, liveMeeting) PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
} else { } else {
broadcastAddCaptionLocaleEvent(msg.body.locale, msg.header.userId) updateCaptionOwner(liveMeeting, msg.body.name, msg.body.locale, msg.body.ownerId).foreach(f => {
broadcastUpdateCaptionOwnerEvent(f._1, f._2.locale, f._2.ownerId)
})
}
}
def handleUserLeavingMsg(userId: String, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
def broadcastUpdateCaptionOwnerEvent(name: String, locale: String, newOwnerId: String): Unit = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, newOwnerId)
val envelope = BbbCoreEnvelope(UpdateCaptionOwnerEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(UpdateCaptionOwnerEvtMsg.NAME, liveMeeting.props.meetingProp.intId, newOwnerId)
val body = UpdateCaptionOwnerEvtMsgBody(name, locale, newOwnerId)
val event = UpdateCaptionOwnerEvtMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
bus.outGW.send(msgEvent)
}
for {
transcriptInfo <- checkCaptionOwnerLogOut(liveMeeting, userId)
} yield {
broadcastUpdateCaptionOwnerEvent(transcriptInfo._1, transcriptInfo._2.locale, transcriptInfo._2.ownerId)
} }
} }
} }

View File

@ -1,6 +1,6 @@
package org.bigbluebutton.core.apps.chat package org.bigbluebutton.core.apps.chat
import org.apache.pekko.actor.ActorContext import akka.actor.ActorContext
class ChatApp2x(implicit val context: ActorContext) class ChatApp2x(implicit val context: ActorContext)
extends GetChatHistoryReqMsgHdlr extends GetChatHistoryReqMsgHdlr

View File

@ -3,7 +3,6 @@ package org.bigbluebutton.core.apps.chat
import org.bigbluebutton.common2.msgs._ import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.apps.{ ChatModel, PermissionCheck, RightsManagementTrait } import org.bigbluebutton.core.apps.{ ChatModel, PermissionCheck, RightsManagementTrait }
import org.bigbluebutton.core.bus.MessageBus import org.bigbluebutton.core.bus.MessageBus
import org.bigbluebutton.core.db.ChatMessageDAO
import org.bigbluebutton.core.running.{ LiveMeeting, LogHelper } import org.bigbluebutton.core.running.{ LiveMeeting, LogHelper }
import org.bigbluebutton.core.domain.MeetingState2x import org.bigbluebutton.core.domain.MeetingState2x
@ -32,8 +31,6 @@ trait ClearPublicChatHistoryPubMsgHdlr extends LogHelper with RightsManagementTr
val newState = for { val newState = for {
gc <- state.groupChats.find(msg.body.chatId) gc <- state.groupChats.find(msg.body.chatId)
} yield { } yield {
ChatMessageDAO.deleteAllFromChat(liveMeeting.props.meetingProp.intId, msg.body.chatId)
ChatMessageDAO.insertSystemMsg(liveMeeting.props.meetingProp.intId, msg.body.chatId, "", GroupChatMessageType.PUBLIC_CHAT_HIST_CLEARED, Map(), "")
broadcastEvent(msg) broadcastEvent(msg)
val newGc = gc.clearMessages() val newGc = gc.clearMessages()
val gcs = state.groupChats.update(newGc) val gcs = state.groupChats.update(newGc)

View File

@ -2,7 +2,6 @@ package org.bigbluebutton.core.apps.chat
import org.bigbluebutton.common2.msgs._ import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.bus.MessageBus import org.bigbluebutton.core.bus.MessageBus
import org.bigbluebutton.core.db.ChatUserDAO
import org.bigbluebutton.core.running.{ LiveMeeting, LogHelper } import org.bigbluebutton.core.running.{ LiveMeeting, LogHelper }
trait UserTypingPubMsgHdlr extends LogHelper { trait UserTypingPubMsgHdlr extends LogHelper {
@ -17,7 +16,6 @@ trait UserTypingPubMsgHdlr extends LogHelper {
val msgEvent = BbbCommonEnvCoreMsg(envelope, event) val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
bus.outGW.send(msgEvent) bus.outGW.send(msgEvent)
} }
ChatUserDAO.updateUserTyping(liveMeeting.props.meetingProp.intId, msg.body.chatId, msg.header.userId)
broadcastEvent(msg) broadcastEvent(msg)
} }
} }

View File

@ -1,7 +1,7 @@
package org.bigbluebutton.core.apps.externalvideo package org.bigbluebutton.core.apps.externalvideo
import org.apache.pekko.actor.ActorContext import akka.actor.ActorContext
import org.apache.pekko.event.Logging import akka.event.Logging
class ExternalVideoApp2x(implicit val context: ActorContext) class ExternalVideoApp2x(implicit val context: ActorContext)
extends StartExternalVideoPubMsgHdlr extends StartExternalVideoPubMsgHdlr

View File

@ -4,8 +4,7 @@ import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.apps.{ ExternalVideoModel, PermissionCheck, RightsManagementTrait } import org.bigbluebutton.core.apps.{ ExternalVideoModel, PermissionCheck, RightsManagementTrait }
import org.bigbluebutton.core.bus.MessageBus import org.bigbluebutton.core.bus.MessageBus
import org.bigbluebutton.core.running.LiveMeeting import org.bigbluebutton.core.running.LiveMeeting
import org.bigbluebutton.core.apps.screenshare.ScreenshareApp2x.requestBroadcastStop import org.bigbluebutton.core.apps.screenshare.ScreenshareApp2x.{ requestBroadcastStop }
import org.bigbluebutton.core.db.ExternalVideoDAO
trait StartExternalVideoPubMsgHdlr extends RightsManagementTrait { trait StartExternalVideoPubMsgHdlr extends RightsManagementTrait {
this: ExternalVideoApp2x => this: ExternalVideoApp2x =>
@ -40,7 +39,6 @@ trait StartExternalVideoPubMsgHdlr extends RightsManagementTrait {
requestBroadcastStop(bus.outGW, liveMeeting) requestBroadcastStop(bus.outGW, liveMeeting)
ExternalVideoModel.setURL(liveMeeting.externalVideoModel, msg.body.externalVideoUrl) ExternalVideoModel.setURL(liveMeeting.externalVideoModel, msg.body.externalVideoUrl)
ExternalVideoDAO.insert(liveMeeting.props.meetingProp.intId, msg.body.externalVideoUrl)
broadcastEvent(msg) broadcastEvent(msg)
} }
} }

View File

@ -3,7 +3,6 @@ package org.bigbluebutton.core.apps.externalvideo
import org.bigbluebutton.common2.msgs._ import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.apps.{ ExternalVideoModel, PermissionCheck, RightsManagementTrait } import org.bigbluebutton.core.apps.{ ExternalVideoModel, PermissionCheck, RightsManagementTrait }
import org.bigbluebutton.core.bus.MessageBus import org.bigbluebutton.core.bus.MessageBus
import org.bigbluebutton.core.db.ExternalVideoDAO
import org.bigbluebutton.core.running.LiveMeeting import org.bigbluebutton.core.running.LiveMeeting
import org.bigbluebutton.core2.message.senders.MsgBuilder import org.bigbluebutton.core2.message.senders.MsgBuilder
@ -20,8 +19,6 @@ trait StopExternalVideoPubMsgHdlr extends RightsManagementTrait {
} else { } else {
ExternalVideoModel.clear(liveMeeting.externalVideoModel) ExternalVideoModel.clear(liveMeeting.externalVideoModel)
ExternalVideoDAO.updateStoppedSharing(liveMeeting.props.meetingProp.intId)
//broadcastEvent //broadcastEvent
val msgEvent = MsgBuilder.buildStopExternalVideoEvtMsg(liveMeeting.props.meetingProp.intId, msg.header.userId) val msgEvent = MsgBuilder.buildStopExternalVideoEvtMsg(liveMeeting.props.meetingProp.intId, msg.header.userId)
bus.outGW.send(msgEvent) bus.outGW.send(msgEvent)

View File

@ -3,8 +3,7 @@ package org.bigbluebutton.core.apps.externalvideo
import org.bigbluebutton.common2.msgs._ import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait } import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
import org.bigbluebutton.core.bus.MessageBus import org.bigbluebutton.core.bus.MessageBus
import org.bigbluebutton.core.db.ExternalVideoDAO import org.bigbluebutton.core.running.{ LiveMeeting }
import org.bigbluebutton.core.running.LiveMeeting
trait UpdateExternalVideoPubMsgHdlr extends RightsManagementTrait { trait UpdateExternalVideoPubMsgHdlr extends RightsManagementTrait {
@ -25,7 +24,6 @@ trait UpdateExternalVideoPubMsgHdlr extends RightsManagementTrait {
val reason = "You need to be the presenter to update external video" val reason = "You need to be the presenter to update external video"
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW, liveMeeting) PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
} else { } else {
ExternalVideoDAO.update(liveMeeting.props.meetingProp.intId, msg.body.status, msg.body.rate, msg.body.time, msg.body.state)
broadcastEvent(msg) broadcastEvent(msg)
} }
} }

View File

@ -7,8 +7,6 @@ import org.bigbluebutton.core.models.GroupChat
import org.bigbluebutton.core.running.LiveMeeting import org.bigbluebutton.core.running.LiveMeeting
import org.bigbluebutton.core.apps.PermissionCheck import org.bigbluebutton.core.apps.PermissionCheck
import org.bigbluebutton.SystemConfiguration import org.bigbluebutton.SystemConfiguration
import org.bigbluebutton.core.db.ChatDAO
import org.bigbluebutton.core.db.ChatUserDAO
import org.bigbluebutton.core.models.Users2x import org.bigbluebutton.core.models.Users2x
import org.bigbluebutton.core.models.Roles import org.bigbluebutton.core.models.Roles
import org.bigbluebutton.core2.MeetingStatus2x import org.bigbluebutton.core2.MeetingStatus2x
@ -51,33 +49,27 @@ trait CreateGroupChatReqMsgHdlr extends SystemConfiguration {
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW, liveMeeting) PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
state state
} else { } else {
GroupChatApp.getGroupChatOfUsers(msg.header.userId, msg.body.users, state) match { val newState = for {
case Some(groupChat) => createdBy <- GroupChatApp.findGroupChatUser(msg.header.userId, liveMeeting.users2x)
ChatUserDAO.updateChatVisible(msg.header.meetingId, groupChat.id, msg.header.userId, visible = true) } yield {
state val msgs = msg.body.msg.map(m => GroupChatApp.toGroupChatMessage(createdBy, m))
case None => val users = {
val newState = for { if (msg.body.access == GroupChatAccess.PRIVATE) {
createdBy <- GroupChatApp.findGroupChatUser(msg.header.userId, liveMeeting.users2x) val cu = msg.body.users.toSet + msg.header.userId
} yield { cu.flatMap(u => GroupChatApp.findGroupChatUser(u, liveMeeting.users2x)).toVector
val msgs = msg.body.msg.map(m => GroupChatApp.toGroupChatMessage(createdBy, m, emphasizedText = false)) } else {
val users = { Vector.empty
if (msg.body.access == GroupChatAccess.PRIVATE) {
val cu = msg.body.users.toSet + msg.header.userId
cu.flatMap(u => GroupChatApp.findGroupChatUser(u, liveMeeting.users2x)).toVector
} else {
Vector.empty
}
}
val gc = GroupChatApp.createGroupChat(msg.body.access, createdBy, users, msgs)
sendMessages(msg, gc, liveMeeting, bus)
val groupChats = state.groupChats.add(gc)
ChatDAO.insert(liveMeeting.props.meetingProp.intId, gc)
state.update(groupChats)
} }
newState.getOrElse(state) }
val gc = GroupChatApp.createGroupChat(msg.body.access, createdBy, users, msgs)
sendMessages(msg, gc, liveMeeting, bus)
val groupChats = state.groupChats.add(gc)
state.update(groupChats)
} }
newState.getOrElse(state)
} }
} }

View File

@ -1,66 +0,0 @@
package org.bigbluebutton.core.apps.groupchats
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.apps.PermissionCheck
import org.bigbluebutton.core.bus.MessageBus
import org.bigbluebutton.core.db.ChatMessageReactionDAO
import org.bigbluebutton.core.domain.MeetingState2x
import org.bigbluebutton.core.models.{ Roles, Users2x }
import org.bigbluebutton.core.running.{ HandlerHelpers, LiveMeeting }
import org.bigbluebutton.core2.MeetingStatus2x
trait DeleteGroupChatMessageReactionReqMsgHdlr extends HandlerHelpers {
this: GroupChatHdlrs =>
def handle(msg: DeleteGroupChatMessageReactionReqMsg, state: MeetingState2x, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
val chatDisabled: Boolean = liveMeeting.props.meetingProp.disabledFeatures.contains("chat")
val chatMessageReactionsDisabled: Boolean = liveMeeting.props.meetingProp.disabledFeatures.contains("chatMessageReactions")
var chatLocked: Boolean = false
var chatLockedForUser: Boolean = false
for {
user <- Users2x.findWithIntId(liveMeeting.users2x, msg.header.userId)
groupChat <- state.groupChats.find(msg.body.chatId)
} yield {
if (groupChat.access == GroupChatAccess.PUBLIC && user.userLockSettings.disablePublicChat && user.role != Roles.MODERATOR_ROLE) {
chatLockedForUser = true
}
val userIsModerator = user.role != Roles.MODERATOR_ROLE
if (!userIsModerator && user.locked) {
val permissions = MeetingStatus2x.getPermissions(liveMeeting.status)
if (groupChat.access == GroupChatAccess.PRIVATE) {
val modMembers = groupChat.users.filter(cu => Users2x.findWithIntId(liveMeeting.users2x, cu.id) match {
case Some(user) => user.role == Roles.MODERATOR_ROLE
case None => false
})
// don't lock private chats that involve a moderator
if (modMembers.isEmpty) {
chatLocked = permissions.disablePrivChat
}
} else {
chatLocked = permissions.disablePubChat
}
}
if (!chatDisabled && !chatMessageReactionsDisabled && !(applyPermissionCheck && chatLocked) && !chatLockedForUser) {
for {
gcMessage <- groupChat.msgs.find(gcm => gcm.id == msg.body.messageId)
} yield {
val chatIsPrivate = groupChat.access == GroupChatAccess.PRIVATE
val userIsAParticipant = groupChat.users.exists(u => u.id == user.intId)
if ((chatIsPrivate && userIsAParticipant) || !chatIsPrivate) {
val event = buildGroupChatMessageReactionDeletedEvtMsg(liveMeeting.props.meetingProp.intId, msg.header.userId, msg.body.chatId, gcMessage.id, msg.body.reactionEmoji, msg.body.reactionEmojiId)
bus.outGW.send(event)
ChatMessageReactionDAO.delete(liveMeeting.props.meetingProp.intId, gcMessage.id, msg.header.userId, msg.body.reactionEmoji, msg.body.reactionEmojiId)
} else {
val reason = "User isn't a participant of the chat"
PermissionCheck.ejectUserForFailedPermission(msg.header.meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
}
}
}
}
}
}

View File

@ -1,77 +0,0 @@
package org.bigbluebutton.core.apps.groupchats
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.apps.PermissionCheck
import org.bigbluebutton.core.bus.MessageBus
import org.bigbluebutton.core.domain.MeetingState2x
import org.bigbluebutton.core.models.{ Roles, Users2x }
import org.bigbluebutton.core.running.{ HandlerHelpers, LiveMeeting }
import org.bigbluebutton.core2.MeetingStatus2x
trait DeleteGroupChatMessageReqMsgHdlr extends HandlerHelpers {
this: GroupChatHdlrs =>
def handle(msg: DeleteGroupChatMessageReqMsg, state: MeetingState2x, liveMeeting: LiveMeeting, bus: MessageBus): MeetingState2x = {
val chatDisabled: Boolean = liveMeeting.props.meetingProp.disabledFeatures.contains("chat")
val deleteChatMessageDisabled: Boolean = liveMeeting.props.meetingProp.disabledFeatures.contains("deleteChatMessage")
var chatLocked: Boolean = false
var chatLockedForUser: Boolean = false
var newState = state
for {
user <- Users2x.findWithIntId(liveMeeting.users2x, msg.header.userId)
groupChat <- state.groupChats.find(msg.body.chatId)
} yield {
if (groupChat.access == GroupChatAccess.PUBLIC && user.userLockSettings.disablePublicChat && user.role != Roles.MODERATOR_ROLE) {
chatLockedForUser = true
}
val userIsModerator = user.role == Roles.MODERATOR_ROLE
if (!userIsModerator && user.locked) {
val permissions = MeetingStatus2x.getPermissions(liveMeeting.status)
if (groupChat.access == GroupChatAccess.PRIVATE) {
val modMembers = groupChat.users.filter(cu => Users2x.findWithIntId(liveMeeting.users2x, cu.id) match {
case Some(user) => user.role == Roles.MODERATOR_ROLE
case None => false
})
// don't lock private chats that involve a moderator
if (modMembers.isEmpty) {
chatLocked = permissions.disablePrivChat
}
} else {
chatLocked = permissions.disablePubChat
}
}
if (!chatDisabled && !deleteChatMessageDisabled && !(applyPermissionCheck && chatLocked) && !chatLockedForUser) {
for {
gcMessage <- groupChat.msgs.find(gcm => gcm.id == msg.body.messageId)
} yield {
val chatIsPrivate = groupChat.access == GroupChatAccess.PRIVATE
val userIsAParticipant = groupChat.users.exists(u => u.id == user.intId)
val userIsOwner = gcMessage.sender.id == user.intId
if ((chatIsPrivate && userIsAParticipant) || !chatIsPrivate) {
if (userIsOwner || userIsModerator) {
val updatedGroupChat = GroupChatApp.deleteGroupChatMessage(liveMeeting.props.meetingProp.intId, groupChat, state.groupChats, gcMessage, user.intId)
val event = buildGroupChatMessageDeletedEvtMsg(liveMeeting.props.meetingProp.intId, msg.header.userId, msg.body.chatId, gcMessage.id)
bus.outGW.send(event)
newState = state.update(updatedGroupChat)
} else {
val reason = "User doesn't have permission to delete chat message"
PermissionCheck.ejectUserForFailedPermission(msg.header.meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
}
} else {
val reason = "User isn't a participant of the chat"
PermissionCheck.ejectUserForFailedPermission(msg.header.meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
}
}
}
}
newState
}
}

View File

@ -1,78 +0,0 @@
package org.bigbluebutton.core.apps.groupchats
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.apps.PermissionCheck
import org.bigbluebutton.core.bus.MessageBus
import org.bigbluebutton.core.domain.MeetingState2x
import org.bigbluebutton.core.models.{ Roles, Users2x }
import org.bigbluebutton.core.running.{ HandlerHelpers, LiveMeeting }
import org.bigbluebutton.core2.MeetingStatus2x
trait EditGroupChatMessageReqMsgHdlr extends HandlerHelpers {
this: GroupChatHdlrs =>
def handle(msg: EditGroupChatMessageReqMsg, state: MeetingState2x, liveMeeting: LiveMeeting, bus: MessageBus): MeetingState2x = {
val chatDisabled: Boolean = liveMeeting.props.meetingProp.disabledFeatures.contains("chat")
val editChatMessageDisabled: Boolean = liveMeeting.props.meetingProp.disabledFeatures.contains("editChatMessage")
var chatLocked: Boolean = false
var chatLockedForUser: Boolean = false
var newState = state
for {
user <- Users2x.findWithIntId(liveMeeting.users2x, msg.header.userId)
groupChat <- state.groupChats.find(msg.body.chatId)
} yield {
if (groupChat.access == GroupChatAccess.PUBLIC && user.userLockSettings.disablePublicChat && user.role != Roles.MODERATOR_ROLE) {
chatLockedForUser = true
}
val userIsModerator = user.role == Roles.MODERATOR_ROLE
if (!userIsModerator && user.locked) {
val permissions = MeetingStatus2x.getPermissions(liveMeeting.status)
if (groupChat.access == GroupChatAccess.PRIVATE) {
val modMembers = groupChat.users.filter(cu => Users2x.findWithIntId(liveMeeting.users2x, cu.id) match {
case Some(user) => user.role == Roles.MODERATOR_ROLE
case None => false
})
// don't lock private chats that involve a moderator
if (modMembers.isEmpty) {
chatLocked = permissions.disablePrivChat
}
} else {
chatLocked = permissions.disablePubChat
}
}
if (!chatDisabled && !editChatMessageDisabled && !(applyPermissionCheck && chatLocked) && !chatLockedForUser) {
for {
gcMessage <- groupChat.msgs.find(gcm => gcm.id == msg.body.messageId)
} yield {
val chatIsPrivate = groupChat.access == GroupChatAccess.PRIVATE
val userIsAParticipant = groupChat.users.exists(u => u.id == user.intId)
val userIsOwner = gcMessage.sender.id == user.intId
if ((chatIsPrivate && userIsAParticipant) || !chatIsPrivate) {
if (userIsOwner) {
val editedGCMessage = gcMessage.copy(message = msg.body.message)
val updatedGroupChat = GroupChatApp.updateGroupChatMessage(liveMeeting.props.meetingProp.intId, groupChat, state.groupChats, editedGCMessage)
val event = buildGroupChatMessageEditedEvtMsg(liveMeeting.props.meetingProp.intId, msg.header.userId, msg.body.chatId, editedGCMessage)
bus.outGW.send(event)
newState = state.update(updatedGroupChat)
} else {
val reason = "User doesn't have permission to edit chat message"
PermissionCheck.ejectUserForFailedPermission(msg.header.meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
}
} else {
val reason = "User isn't a participant of the chat"
PermissionCheck.ejectUserForFailedPermission(msg.header.meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
}
}
}
}
newState
}
}

View File

@ -1,16 +1,11 @@
package org.bigbluebutton.core.apps.groupchats package org.bigbluebutton.core.apps.groupchats
import org.bigbluebutton.common2.msgs.{ GroupChatAccess, GroupChatMessageType, GroupChatMsgFromUser, GroupChatMsgToUser, GroupChatUser } import org.bigbluebutton.common2.msgs.{ GroupChatAccess, GroupChatMsgFromUser, GroupChatMsgToUser, GroupChatUser }
import org.bigbluebutton.core.db.ChatMessageDAO
import org.bigbluebutton.core.domain.MeetingState2x import org.bigbluebutton.core.domain.MeetingState2x
import org.bigbluebutton.core.models._ import org.bigbluebutton.core.models._
import org.bigbluebutton.core.running.LiveMeeting import org.bigbluebutton.core.running.LiveMeeting
object GroupChatApp { object GroupChatApp {
def getGroupChatOfUsers(userId: String, participantIds: Vector[String], state: MeetingState2x): Option[GroupChat] = {
state.groupChats.findAllPrivateChatsForUser(userId)
.find(groupChat => participantIds.forall(groupChat.users.map(u => u.id).contains))
}
val MAIN_PUBLIC_CHAT = "MAIN-PUBLIC-GROUP-CHAT" val MAIN_PUBLIC_CHAT = "MAIN-PUBLIC-GROUP-CHAT"
@ -20,10 +15,10 @@ object GroupChatApp {
GroupChatFactory.create(gcId, access, createBy, users, msgs) GroupChatFactory.create(gcId, access, createBy, users, msgs)
} }
def toGroupChatMessage(sender: GroupChatUser, msg: GroupChatMsgFromUser, emphasizedText: Boolean): GroupChatMessage = { def toGroupChatMessage(sender: GroupChatUser, msg: GroupChatMsgFromUser): GroupChatMessage = {
val now = System.currentTimeMillis() val now = System.currentTimeMillis()
val id = GroupChatFactory.genId() val id = GroupChatFactory.genId()
GroupChatMessage(id, now, msg.correlationId, now, now, sender, emphasizedText, msg.message, msg.replyToMessageId, msg.metadata) GroupChatMessage(id, now, msg.correlationId, now, now, sender, msg.chatEmphasizedText, msg.message)
} }
def toMessageToUser(msg: GroupChatMessage): GroupChatMsgToUser = { def toMessageToUser(msg: GroupChatMessage): GroupChatMsgToUser = {
@ -31,32 +26,12 @@ object GroupChatApp {
sender = msg.sender, chatEmphasizedText = msg.chatEmphasizedText, message = msg.message) sender = msg.sender, chatEmphasizedText = msg.chatEmphasizedText, message = msg.message)
} }
def addGroupChatMessage(meetingId: String, chat: GroupChat, chats: GroupChats, def addGroupChatMessage(chat: GroupChat, chats: GroupChats,
msg: GroupChatMessage, messageType: String = GroupChatMessageType.DEFAULT): GroupChats = { msg: GroupChatMessage): GroupChats = {
if (msg.sender.id == SystemUser.ID) {
ChatMessageDAO.insertSystemMsg(meetingId, chat.id, msg.message, messageType, Map(), msg.sender.name)
} else {
ChatMessageDAO.insert(meetingId, chat.id, msg, messageType)
}
val c = chat.add(msg) val c = chat.add(msg)
chats.update(c) chats.update(c)
} }
def updateGroupChatMessage(meetingId: String, chat: GroupChat, chats: GroupChats, msg: GroupChatMessage): GroupChats = {
ChatMessageDAO.update(meetingId, chat.id, msg.id, msg.message)
val c = chat.update(msg)
chats.update(c)
}
def deleteGroupChatMessage(meetingId: String, chat: GroupChat, chats: GroupChats, msg: GroupChatMessage, deletedBy: String): GroupChats = {
ChatMessageDAO.softDelete(meetingId, chat.id, msg.id, deletedBy)
val c = chat.delete(msg.id)
chats.update(c)
}
def findGroupChatUser(userId: String, users: Users2x): Option[GroupChatUser] = { def findGroupChatUser(userId: String, users: Users2x): Option[GroupChatUser] = {
Users2x.findWithIntId(users, userId) match { Users2x.findWithIntId(users, userId) match {
case Some(u) => Some(GroupChatUser(u.intId, u.name, u.role)) case Some(u) => Some(GroupChatUser(u.intId, u.name, u.role))
@ -94,9 +69,9 @@ object GroupChatApp {
sender <- GroupChatApp.findGroupChatUser(userId, liveMeeting.users2x) sender <- GroupChatApp.findGroupChatUser(userId, liveMeeting.users2x)
chat <- state.groupChats.find(chatId) chat <- state.groupChats.find(chatId)
} yield { } yield {
val emphasizedText = sender.role == Roles.MODERATOR_ROLE
val gcm1 = GroupChatApp.toGroupChatMessage(sender, msg, emphasizedText) val gcm1 = GroupChatApp.toGroupChatMessage(sender, msg)
val gcs1 = GroupChatApp.addGroupChatMessage(liveMeeting.props.meetingProp.intId, chat, state.groupChats, gcm1) val gcs1 = GroupChatApp.addGroupChatMessage(chat, state.groupChats, gcm1)
state.update(gcs1) state.update(gcs1)
} }
@ -107,9 +82,9 @@ object GroupChatApp {
} }
val sender = GroupChatUser(SystemUser.ID) val sender = GroupChatUser(SystemUser.ID)
val h1 = GroupChatMsgFromUser(correlationId = "cor1", sender = sender, message = "Hello Foo!", replyToMessageId = "") val h1 = GroupChatMsgFromUser(correlationId = "cor1", sender = sender, message = "Hello Foo!")
val h2 = GroupChatMsgFromUser(correlationId = "cor2", sender = sender, message = "Hello Bar!", replyToMessageId = "") val h2 = GroupChatMsgFromUser(correlationId = "cor2", sender = sender, message = "Hello Bar!")
val h3 = GroupChatMsgFromUser(correlationId = "cor3", sender = sender, message = "Hello Baz!", replyToMessageId = "") val h3 = GroupChatMsgFromUser(correlationId = "cor3", sender = sender, message = "Hello Baz!")
val state1 = addH(state, SystemUser.ID, liveMeeting, h1) val state1 = addH(state, SystemUser.ID, liveMeeting, h1)
val state2 = addH(state1, SystemUser.ID, liveMeeting, h2) val state2 = addH(state1, SystemUser.ID, liveMeeting, h2)
val state3 = addH(state2, SystemUser.ID, liveMeeting, h3) val state3 = addH(state2, SystemUser.ID, liveMeeting, h3)

View File

@ -1,7 +1,7 @@
package org.bigbluebutton.core.apps.groupchats package org.bigbluebutton.core.apps.groupchats
import org.apache.pekko.actor.ActorContext import akka.actor.ActorContext
import org.apache.pekko.event.Logging import akka.event.Logging
class GroupChatHdlrs(implicit val context: ActorContext) class GroupChatHdlrs(implicit val context: ActorContext)
extends CreateGroupChatReqMsgHdlr extends CreateGroupChatReqMsgHdlr
@ -9,13 +9,7 @@ class GroupChatHdlrs(implicit val context: ActorContext)
with GetGroupChatMsgsReqMsgHdlr with GetGroupChatMsgsReqMsgHdlr
with GetGroupChatsReqMsgHdlr with GetGroupChatsReqMsgHdlr
with SendGroupChatMessageMsgHdlr with SendGroupChatMessageMsgHdlr
with EditGroupChatMessageReqMsgHdlr with SyncGetGroupChatsInfoMsgHdlr {
with DeleteGroupChatMessageReqMsgHdlr
with SendGroupChatMessageReactionReqMsgHdlr
with DeleteGroupChatMessageReactionReqMsgHdlr
with SendGroupChatMessageFromApiSysPubMsgHdlr
with SetGroupChatVisibleReqMsgHdlr
with SetGroupChatLastSeenReqMsgHdlr {
val log = Logging(context.system, getClass) val log = Logging(context.system, getClass)
} }

View File

@ -1,46 +0,0 @@
package org.bigbluebutton.core.apps.groupchats
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.bus.MessageBus
import org.bigbluebutton.core.domain.MeetingState2x
import org.bigbluebutton.core.models.SystemUser
import org.bigbluebutton.core.running.{ HandlerHelpers, LiveMeeting }
trait SendGroupChatMessageFromApiSysPubMsgHdlr extends HandlerHelpers {
this: GroupChatHdlrs =>
def handle(msg: SendGroupChatMessageFromApiSysPubMsg, state: MeetingState2x,
liveMeeting: LiveMeeting, bus: MessageBus): MeetingState2x = {
log.debug("RECEIVED SendGroupChatMessageFromApiSysPubMsg {}", msg)
val chatDisabled: Boolean = liveMeeting.props.meetingProp.disabledFeatures.contains("chat")
if (!chatDisabled) {
val newState = for {
sender <- GroupChatApp.findGroupChatUser(SystemUser.ID, liveMeeting.users2x)
chat <- state.groupChats.find(GroupChatApp.MAIN_PUBLIC_CHAT)
} yield {
val groupChatMsgFromUser = GroupChatMsgFromUser(sender.id, sender.copy(name = msg.body.userName), msg.body.message, replyToMessageId = "")
val gcm = GroupChatApp.toGroupChatMessage(sender.copy(name = msg.body.userName), groupChatMsgFromUser, emphasizedText = true)
val gcs = GroupChatApp.addGroupChatMessage(liveMeeting.props.meetingProp.intId, chat, state.groupChats, gcm, GroupChatMessageType.API)
val event = buildGroupChatMessageBroadcastEvtMsg(
liveMeeting.props.meetingProp.intId,
msg.body.userName, GroupChatApp.MAIN_PUBLIC_CHAT, gcm
)
bus.outGW.send(event)
state.update(gcs)
}
newState match {
case Some(ns) => ns
case None => state
}
} else {
state
}
}
}

View File

@ -1,6 +1,5 @@
package org.bigbluebutton.core.apps.groupchats package org.bigbluebutton.core.apps.groupchats
import org.bigbluebutton.ClientSettings.getConfigPropertyValueByPathAsBooleanOrElse
import org.bigbluebutton.common2.msgs._ import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.apps.PermissionCheck import org.bigbluebutton.core.apps.PermissionCheck
import org.bigbluebutton.core.bus.MessageBus import org.bigbluebutton.core.bus.MessageBus
@ -16,27 +15,13 @@ trait SendGroupChatMessageMsgHdlr extends HandlerHelpers {
def handle(msg: SendGroupChatMessageMsg, state: MeetingState2x, def handle(msg: SendGroupChatMessageMsg, state: MeetingState2x,
liveMeeting: LiveMeeting, bus: MessageBus): MeetingState2x = { liveMeeting: LiveMeeting, bus: MessageBus): MeetingState2x = {
def determineMessageType(metadata: Map[String, Any]): String = {
if (metadata.contains("pluginName")) {
GroupChatMessageType.PLUGIN
} else {
GroupChatMessageType.DEFAULT
}
}
val chatDisabled: Boolean = liveMeeting.props.meetingProp.disabledFeatures.contains("chat") val chatDisabled: Boolean = liveMeeting.props.meetingProp.disabledFeatures.contains("chat")
val replyChatMessageDisabled: Boolean = liveMeeting.props.meetingProp.disabledFeatures.contains("replyChatMessage")
var chatLocked: Boolean = false var chatLocked: Boolean = false
var chatLockedForUser: Boolean = false
for { for {
user <- Users2x.findWithIntId(liveMeeting.users2x, msg.header.userId) user <- Users2x.findWithIntId(liveMeeting.users2x, msg.header.userId)
groupChat <- state.groupChats.find(msg.body.chatId) groupChat <- state.groupChats.find(msg.body.chatId)
} yield { } yield {
if (groupChat.access == GroupChatAccess.PUBLIC && user.userLockSettings.disablePublicChat && user.role != Roles.MODERATOR_ROLE) {
chatLockedForUser = true
}
if (user.role != Roles.MODERATOR_ROLE && user.locked) { if (user.role != Roles.MODERATOR_ROLE && user.locked) {
val permissions = MeetingStatus2x.getPermissions(liveMeeting.status) val permissions = MeetingStatus2x.getPermissions(liveMeeting.status)
if (groupChat.access == GroupChatAccess.PRIVATE) { if (groupChat.access == GroupChatAccess.PRIVATE) {
@ -45,7 +30,7 @@ trait SendGroupChatMessageMsgHdlr extends HandlerHelpers {
case None => false case None => false
}) })
// don't lock private chats that involve a moderator // don't lock private chats that involve a moderator
if (modMembers.isEmpty) { if (modMembers.length == 0) {
chatLocked = permissions.disablePrivChat chatLocked = permissions.disablePrivChat
} }
} else { } else {
@ -54,50 +39,32 @@ trait SendGroupChatMessageMsgHdlr extends HandlerHelpers {
} }
} }
if (!chatDisabled && !(applyPermissionCheck && chatLocked) && !chatLockedForUser) { if (!chatDisabled && !(applyPermissionCheck && chatLocked)) {
val newState = for { val newState = for {
sender <- GroupChatApp.findGroupChatUser(msg.header.userId, liveMeeting.users2x) sender <- GroupChatApp.findGroupChatUser(msg.header.userId, liveMeeting.users2x)
chat <- state.groupChats.find(msg.body.chatId) chat <- state.groupChats.find(msg.body.chatId)
} yield { } yield {
val chatIsPrivate = chat.access == GroupChatAccess.PRIVATE; val chatIsPrivate = chat.access == GroupChatAccess.PRIVATE;
val userIsAParticipant = chat.users.exists(u => u.id == sender.id); val userIsAParticipant = chat.users.filter(u => u.id == sender.id).length > 0;
if ((chatIsPrivate && userIsAParticipant) || !chatIsPrivate) { if ((chatIsPrivate && userIsAParticipant) || !chatIsPrivate) {
val moderatorChatEmphasizedEnabled = getConfigPropertyValueByPathAsBooleanOrElse( val gcm = GroupChatApp.toGroupChatMessage(sender, msg.body.msg)
liveMeeting.clientSettings, val gcs = GroupChatApp.addGroupChatMessage(chat, state.groupChats, gcm)
"public.chat.moderatorChatEmphasized",
alternativeValue = true
)
val emphasizedText = moderatorChatEmphasizedEnabled &&
!chatIsPrivate &&
sender.role == Roles.MODERATOR_ROLE
val messageType = determineMessageType(msg.body.msg.metadata)
val groupChatMsgReceived = {
if (replyChatMessageDisabled && msg.body.msg.replyToMessageId != "") {
msg.body.msg.copy(replyToMessageId = "")
} else {
msg.body.msg
}
}
val gcMessage = GroupChatApp.toGroupChatMessage(sender, groupChatMsgReceived, emphasizedText)
val updatedGroupChat = GroupChatApp.addGroupChatMessage(liveMeeting.props.meetingProp.intId, chat, state.groupChats, gcMessage, messageType)
val event = buildGroupChatMessageBroadcastEvtMsg( val event = buildGroupChatMessageBroadcastEvtMsg(
liveMeeting.props.meetingProp.intId, liveMeeting.props.meetingProp.intId,
msg.header.userId, msg.body.chatId, gcMessage msg.header.userId, msg.body.chatId, gcm
) )
bus.outGW.send(event) bus.outGW.send(event)
state.update(updatedGroupChat) state.update(gcs)
} else { } else {
val reason = "User isn't a participant of the chat" val reason = "User isn't a participant of the chat"
PermissionCheck.ejectUserForFailedPermission(msg.header.meetingId, msg.header.userId, reason, bus.outGW, liveMeeting) PermissionCheck.ejectUserForFailedPermission(msg.header.meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
state state
} }
} }
newState match { newState match {

View File

@ -1,66 +0,0 @@
package org.bigbluebutton.core.apps.groupchats
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.apps.PermissionCheck
import org.bigbluebutton.core.bus.MessageBus
import org.bigbluebutton.core.db.ChatMessageReactionDAO
import org.bigbluebutton.core.domain.MeetingState2x
import org.bigbluebutton.core.models.{ Roles, Users2x }
import org.bigbluebutton.core.running.{ HandlerHelpers, LiveMeeting }
import org.bigbluebutton.core2.MeetingStatus2x
trait SendGroupChatMessageReactionReqMsgHdlr extends HandlerHelpers {
this: GroupChatHdlrs =>
def handle(msg: SendGroupChatMessageReactionReqMsg, state: MeetingState2x, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
val chatDisabled: Boolean = liveMeeting.props.meetingProp.disabledFeatures.contains("chat")
val chatMessageReactionsDisabled: Boolean = liveMeeting.props.meetingProp.disabledFeatures.contains("chatMessageReactions")
var chatLocked: Boolean = false
var chatLockedForUser: Boolean = false
for {
user <- Users2x.findWithIntId(liveMeeting.users2x, msg.header.userId)
groupChat <- state.groupChats.find(msg.body.chatId)
} yield {
if (groupChat.access == GroupChatAccess.PUBLIC && user.userLockSettings.disablePublicChat && user.role != Roles.MODERATOR_ROLE) {
chatLockedForUser = true
}
val userIsModerator = user.role == Roles.MODERATOR_ROLE
if (!userIsModerator && user.locked) {
val permissions = MeetingStatus2x.getPermissions(liveMeeting.status)
if (groupChat.access == GroupChatAccess.PRIVATE) {
val modMembers = groupChat.users.filter(cu => Users2x.findWithIntId(liveMeeting.users2x, cu.id) match {
case Some(user) => user.role == Roles.MODERATOR_ROLE
case None => false
})
// don't lock private chats that involve a moderator
if (modMembers.isEmpty) {
chatLocked = permissions.disablePrivChat
}
} else {
chatLocked = permissions.disablePubChat
}
}
if (!chatDisabled && !chatMessageReactionsDisabled && !(applyPermissionCheck && chatLocked) && !chatLockedForUser) {
for {
gcMessage <- groupChat.msgs.find(gcm => gcm.id == msg.body.messageId)
} yield {
val chatIsPrivate = groupChat.access == GroupChatAccess.PRIVATE
val userIsAParticipant = groupChat.users.exists(u => u.id == user.intId)
if ((chatIsPrivate && userIsAParticipant) || !chatIsPrivate) {
val event = buildGroupChatMessageReactionSentEvtMsg(liveMeeting.props.meetingProp.intId, msg.header.userId, msg.body.chatId, gcMessage.id, msg.body.reactionEmoji, msg.body.reactionEmojiId)
bus.outGW.send(event)
ChatMessageReactionDAO.insert(liveMeeting.props.meetingProp.intId, gcMessage.id, msg.header.userId, msg.body.reactionEmoji, msg.body.reactionEmojiId)
} else {
val reason = "User isn't a participant of the chat"
PermissionCheck.ejectUserForFailedPermission(msg.header.meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
}
}
}
}
}
}

View File

@ -1,21 +0,0 @@
package org.bigbluebutton.core.apps.groupchats
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.db.ChatUserDAO
import org.bigbluebutton.core.models.Users2x
import org.bigbluebutton.core.running.LiveMeeting
import java.sql.Timestamp
import java.time.Instant
trait SetGroupChatLastSeenReqMsgHdlr {
def handle(msg: SetGroupChatLastSeenReqMsg, liveMeeting: LiveMeeting): Unit = {
for {
user <- Users2x.findWithIntId(liveMeeting.users2x, msg.header.userId)
} yield {
val lastSeenAtInstant = Instant.parse(msg.body.lastSeenAt)
val lastSeenAtTimestamp = Timestamp.from(lastSeenAtInstant)
ChatUserDAO.updateChatLastSeen(liveMeeting.props.meetingProp.intId, msg.body.chatId, user.intId, lastSeenAtTimestamp)
}
}
}

View File

@ -1,17 +0,0 @@
package org.bigbluebutton.core.apps.groupchats
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.bus.MessageBus
import org.bigbluebutton.core.db.ChatUserDAO
import org.bigbluebutton.core.models.Users2x
import org.bigbluebutton.core.running.{ LiveMeeting, LogHelper }
trait SetGroupChatVisibleReqMsgHdlr {
def handle(msg: SetGroupChatVisibleReqMsg, liveMeeting: LiveMeeting): Unit = {
for {
user <- Users2x.findWithIntId(liveMeeting.users2x, msg.header.userId)
} yield {
ChatUserDAO.updateChatVisible(liveMeeting.props.meetingProp.intId, msg.body.chatId, user.intId, msg.body.visible)
}
}
}

View File

@ -0,0 +1,53 @@
package org.bigbluebutton.core.apps.groupchats
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.bus.MessageBus
import org.bigbluebutton.core.domain.MeetingState2x
import org.bigbluebutton.core.running.LiveMeeting
trait SyncGetGroupChatsInfoMsgHdlr {
this: GroupChatHdlrs =>
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 envelope = BbbCoreEnvelope(SyncGetGroupChatsRespMsg.NAME, routing)
val header = BbbClientMsgHeader(SyncGetGroupChatsRespMsg.NAME, liveMeeting.props.meetingProp.intId, "nodeJSapp")
val body = SyncGetGroupChatsRespMsgBody(allChats)
val event = SyncGetGroupChatsRespMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
def buildSyncGetGroupChatMsgsRespMsg(msgs: Vector[GroupChatMsgToUser], chatId: String): BbbCommonEnvCoreMsg = {
val routing = Routing.addMsgToHtml5InstanceIdRouting(liveMeeting.props.meetingProp.intId, liveMeeting.props.systemProps.html5InstanceId.toString)
val envelope = BbbCoreEnvelope(SyncGetGroupChatMsgsRespMsg.NAME, routing)
val header = BbbClientMsgHeader(SyncGetGroupChatMsgsRespMsg.NAME, liveMeeting.props.meetingProp.intId, "nodeJSapp")
val body = SyncGetGroupChatMsgsRespMsgBody(chatId, msgs)
val event = SyncGetGroupChatMsgsRespMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
// fetching all the group chats in the meeting
val chats = GroupChatApp.getAllGroupChatsInMeeting(state)
// mapping group chats, while fetching and publishing messages for each group chat
val allChats = chats map (pc => {
val msgs = pc.msgs.toVector map (m => GroupChatMsgToUser(m.id, m.createdOn, m.correlationId,
m.sender, m.chatEmphasizedText, m.message))
val respMsg = buildSyncGetGroupChatMsgsRespMsg(msgs, pc.id)
bus.outGW.send(respMsg)
GroupChatInfo(pc.id, pc.access, pc.createdBy, pc.users)
})
// publishing a message with the group chat info
val respMsg = buildSyncGetGroupChatsRespMsg(allChats)
bus.outGW.send(respMsg)
state
}
}

View File

@ -5,8 +5,7 @@ import org.bigbluebutton.core.models.{ Layouts, LayoutsType }
import org.bigbluebutton.core.running.OutMsgRouter import org.bigbluebutton.core.running.OutMsgRouter
import org.bigbluebutton.core2.MeetingStatus2x import org.bigbluebutton.core2.MeetingStatus2x
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait } import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
import org.bigbluebutton.core.db.{ LayoutDAO, NotificationDAO } import org.bigbluebutton.core2.message.senders.{ MsgBuilder }
import org.bigbluebutton.core2.message.senders.MsgBuilder
trait BroadcastLayoutMsgHdlr extends RightsManagementTrait { trait BroadcastLayoutMsgHdlr extends RightsManagementTrait {
this: LayoutApp2x => this: LayoutApp2x =>
@ -36,7 +35,6 @@ trait BroadcastLayoutMsgHdlr extends RightsManagementTrait {
Layouts.setPresentationVideoRate(liveMeeting.layouts, msg.body.presentationVideoRate) Layouts.setPresentationVideoRate(liveMeeting.layouts, msg.body.presentationVideoRate)
Layouts.setRequestedBy(liveMeeting.layouts, msg.header.userId) Layouts.setRequestedBy(liveMeeting.layouts, msg.header.userId)
LayoutDAO.insertOrUpdate(liveMeeting.props.meetingProp.intId, liveMeeting.layouts)
sendBroadcastLayoutEvtMsg(msg.header.userId) sendBroadcastLayoutEvtMsg(msg.header.userId)
} }
} }
@ -73,7 +71,6 @@ trait BroadcastLayoutMsgHdlr extends RightsManagementTrait {
Vector() Vector()
) )
outGW.send(notifyEvent) outGW.send(notifyEvent)
NotificationDAO.insert(notifyEvent)
} }
} }
} }

View File

@ -1,10 +1,9 @@
package org.bigbluebutton.core.apps.layout package org.bigbluebutton.core.apps.layout
import org.bigbluebutton.common2.msgs._ import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.models.Layouts import org.bigbluebutton.core.models.{ Layouts }
import org.bigbluebutton.core.running.OutMsgRouter import org.bigbluebutton.core.running.OutMsgRouter
import org.bigbluebutton.core.apps.{PermissionCheck, RightsManagementTrait} import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
import org.bigbluebutton.core.db.LayoutDAO
trait BroadcastPushLayoutMsgHdlr extends RightsManagementTrait { trait BroadcastPushLayoutMsgHdlr extends RightsManagementTrait {
this: LayoutApp2x => this: LayoutApp2x =>
@ -21,7 +20,6 @@ trait BroadcastPushLayoutMsgHdlr extends RightsManagementTrait {
Layouts.setPushLayout(liveMeeting.layouts, msg.body.pushLayout) Layouts.setPushLayout(liveMeeting.layouts, msg.body.pushLayout)
Layouts.setRequestedBy(liveMeeting.layouts, msg.header.userId) Layouts.setRequestedBy(liveMeeting.layouts, msg.header.userId)
LayoutDAO.insertOrUpdate(liveMeeting.props.meetingProp.intId, liveMeeting.layouts)
sendBroadcastPushLayoutEvtMsg(msg.header.userId) sendBroadcastPushLayoutEvtMsg(msg.header.userId)
} }
} }

View File

@ -0,0 +1,21 @@
package org.bigbluebutton.core.apps.meeting
import org.bigbluebutton.common2.domain.DefaultProps
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.running.OutMsgRouter
trait SyncGetMeetingInfoRespMsgHdlr {
val outGW: OutMsgRouter
def handleSyncGetMeetingInfoRespMsg(props: DefaultProps): Unit = {
val routing = Routing.addMsgToHtml5InstanceIdRouting(props.meetingProp.intId, props.systemProps.html5InstanceId.toString)
val envelope = BbbCoreEnvelope(SyncGetMeetingInfoRespMsg.NAME, routing)
val header = BbbCoreBaseHeader(SyncGetMeetingInfoRespMsg.NAME)
val body = SyncGetMeetingInfoRespMsgBody(props)
val event = SyncGetMeetingInfoRespMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
outGW.send(msgEvent)
}
}

View File

@ -0,0 +1,30 @@
package org.bigbluebutton.core.apps.meeting
import org.bigbluebutton.common2.msgs.ValidateConnAuthTokenSysMsg
import org.bigbluebutton.core.models.RegisteredUsers
import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter }
import org.bigbluebutton.core2.message.senders.MsgBuilder
trait ValidateConnAuthTokenSysMsgHdlr {
val liveMeeting: LiveMeeting
val outGW: OutMsgRouter
def handleValidateConnAuthTokenSysMsg(msg: ValidateConnAuthTokenSysMsg): Unit = {
val regUser = RegisteredUsers.getRegisteredUserWithToken(
msg.body.authToken,
msg.body.userId,
liveMeeting.registeredUsers
)
regUser match {
case Some(u) =>
val event = MsgBuilder.buildValidateConnAuthTokenSysRespMsg(msg.body.meetingId, msg.body.userId,
true, msg.body.connId, msg.body.app)
outGW.send(event)
case None =>
val event = MsgBuilder.buildValidateConnAuthTokenSysRespMsg(msg.body.meetingId, msg.body.userId,
false, msg.body.connId, msg.body.app)
outGW.send(event)
}
}
}

View File

@ -2,7 +2,6 @@ package org.bigbluebutton.core.apps.pads
import org.bigbluebutton.common2.msgs._ import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.bus.MessageBus import org.bigbluebutton.core.bus.MessageBus
import org.bigbluebutton.core.db.{ SharedNotesRevDAO }
import org.bigbluebutton.core.models.Pads import org.bigbluebutton.core.models.Pads
import org.bigbluebutton.core.running.LiveMeeting import org.bigbluebutton.core.running.LiveMeeting
@ -10,6 +9,7 @@ trait PadContentSysMsgHdlr {
this: PadsApp2x => this: PadsApp2x =>
def handle(msg: PadContentSysMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = { def handle(msg: PadContentSysMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
def broadcastEvent(externalId: String, padId: String, rev: String, start: Int, end: Int, text: String): Unit = { def broadcastEvent(externalId: String, padId: String, rev: String, start: Int, end: Int, text: String): Unit = {
val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka") val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka")
val envelope = BbbCoreEnvelope(PadContentEvtMsg.NAME, routing) val envelope = BbbCoreEnvelope(PadContentEvtMsg.NAME, routing)
@ -22,18 +22,8 @@ trait PadContentSysMsgHdlr {
} }
Pads.getGroupById(liveMeeting.pads, msg.body.groupId) match { Pads.getGroupById(liveMeeting.pads, msg.body.groupId) match {
case Some(group) => { case Some(group) => broadcastEvent(group.externalId, msg.body.padId, msg.body.rev, msg.body.start, msg.body.end, msg.body.text)
SharedNotesRevDAO.update( case _ =>
liveMeeting.props.meetingProp.intId,
group.externalId,
msg.body.rev.toInt,
msg.body.start,
msg.body.end,
msg.body.text
)
broadcastEvent(group.externalId, msg.body.padId, msg.body.rev, msg.body.start, msg.body.end, msg.body.text)
}
case _ =>
} }
} }
} }

View File

@ -0,0 +1,35 @@
package org.bigbluebutton.core.apps.pads
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.bus.MessageBus
import org.bigbluebutton.core.models.Pads
import org.bigbluebutton.core.running.LiveMeeting
trait PadCreateGroupReqMsgHdlr {
this: PadsApp2x =>
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")
case _ => false
}
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)
}
}
}

View File

@ -2,7 +2,6 @@ package org.bigbluebutton.core.apps.pads
import org.bigbluebutton.common2.msgs._ import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.bus.MessageBus import org.bigbluebutton.core.bus.MessageBus
import org.bigbluebutton.core.db.SharedNotesDAO
import org.bigbluebutton.core.models.Pads import org.bigbluebutton.core.models.Pads
import org.bigbluebutton.core.running.LiveMeeting import org.bigbluebutton.core.running.LiveMeeting
@ -23,12 +22,8 @@ trait PadCreatedEvtMsgHdlr {
} }
Pads.getGroupById(liveMeeting.pads, msg.body.groupId) match { Pads.getGroupById(liveMeeting.pads, msg.body.groupId) match {
case Some(group) => { case Some(group) => broadcastEvent(group.externalId, group.userId, msg.body.padId, msg.body.name)
Pads.setPadId(liveMeeting.pads, group.externalId, msg.body.padId) case _ =>
SharedNotesDAO.insert(liveMeeting.props.meetingProp.intId, group, msg.body.padId, msg.body.name)
broadcastEvent(group.externalId, group.userId, msg.body.padId, msg.body.name)
}
case _ =>
} }
} }
} }

View File

@ -9,12 +9,22 @@ trait PadGroupCreatedEvtMsgHdlr {
this: PadsApp2x => this: PadsApp2x =>
def handle(msg: PadGroupCreatedEvtMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = { def handle(msg: PadGroupCreatedEvtMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
def broadcastEvent(externalId: String, model: String, name: String, userId: String): Unit = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, userId)
val envelope = BbbCoreEnvelope(PadGroupCreatedRespMsg.NAME, routing)
val header = BbbClientMsgHeader(PadGroupCreatedRespMsg.NAME, liveMeeting.props.meetingProp.intId, userId)
val body = PadGroupCreatedRespMsgBody(externalId, model, name)
val event = PadGroupCreatedRespMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
bus.outGW.send(msgEvent)
}
Pads.getGroup(liveMeeting.pads, msg.body.externalId) match { Pads.getGroup(liveMeeting.pads, msg.body.externalId) match {
case Some(group) => { case Some(group) => {
Pads.setGroupId(liveMeeting.pads, msg.body.externalId, msg.body.groupId) Pads.setGroupId(liveMeeting.pads, msg.body.externalId, msg.body.groupId)
broadcastEvent(msg.body.externalId, group.model, group.name, group.userId)
//Group was created, now request to create the pad
PadslHdlrHelpers.broadcastPadCreateCmdMsg(bus.outGW, liveMeeting.props.meetingProp.intId, msg.body.groupId, msg.body.externalId)
} }
case _ => case _ =>
} }

View File

@ -2,7 +2,6 @@ package org.bigbluebutton.core.apps.pads
import org.bigbluebutton.common2.msgs._ import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.bus.MessageBus import org.bigbluebutton.core.bus.MessageBus
import org.bigbluebutton.core.db.CaptionDAO
import org.bigbluebutton.core.models.Pads import org.bigbluebutton.core.models.Pads
import org.bigbluebutton.core.running.LiveMeeting import org.bigbluebutton.core.running.LiveMeeting
@ -41,7 +40,6 @@ trait PadPatchSysMsgHdlr {
broadcastEditCaptionHistoryEvent(msg.body.userId, msg.body.start, msg.body.end, group.name, locale, msg.body.text) broadcastEditCaptionHistoryEvent(msg.body.userId, msg.body.start, msg.body.end, group.name, locale, msg.body.text)
val tail = liveMeeting.captionModel.getTextTail(group.name) val tail = liveMeeting.captionModel.getTextTail(group.name)
broadcastPadTailEvent(group.externalId, tail) broadcastPadTailEvent(group.externalId, tail)
CaptionDAO.insertOrUpdatePadCaption(liveMeeting.props.meetingProp.intId, locale, msg.body.userId, tail)
} }
} }
case _ => case _ =>

View File

@ -3,7 +3,6 @@ package org.bigbluebutton.core.apps.pads
import org.bigbluebutton.common2.msgs._ import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait } import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
import org.bigbluebutton.core.bus.MessageBus import org.bigbluebutton.core.bus.MessageBus
import org.bigbluebutton.core.db.SharedNotesDAO
import org.bigbluebutton.core.models.Pads import org.bigbluebutton.core.models.Pads
import org.bigbluebutton.core.running.LiveMeeting import org.bigbluebutton.core.running.LiveMeeting
@ -30,11 +29,8 @@ trait PadPinnedReqMsgHdlr extends RightsManagementTrait {
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW, liveMeeting) PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
} else { } else {
Pads.getGroup(liveMeeting.pads, msg.body.externalId) match { Pads.getGroup(liveMeeting.pads, msg.body.externalId) match {
case Some(group) => { case Some(group) => broadcastEvent(group.externalId, msg.body.pinned)
SharedNotesDAO.updatePinned(liveMeeting.props.meetingProp.intId, msg.body.externalId, msg.body.pinned) case _ =>
broadcastEvent(group.externalId, msg.body.pinned)
}
case _ =>
} }
} }
} }

View File

@ -2,7 +2,6 @@ package org.bigbluebutton.core.apps.pads
import org.bigbluebutton.common2.msgs._ import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.bus.MessageBus import org.bigbluebutton.core.bus.MessageBus
import org.bigbluebutton.core.db.SharedNotesSessionDAO
import org.bigbluebutton.core.models.Pads import org.bigbluebutton.core.models.Pads
import org.bigbluebutton.core.running.LiveMeeting import org.bigbluebutton.core.running.LiveMeeting
@ -23,11 +22,8 @@ trait PadSessionCreatedEvtMsgHdlr {
} }
Pads.getGroupById(liveMeeting.pads, msg.body.groupId) match { Pads.getGroupById(liveMeeting.pads, msg.body.groupId) match {
case Some(group) => { case Some(group) => broadcastEvent(group.externalId, msg.body.userId, msg.body.sessionId)
SharedNotesSessionDAO.insert(liveMeeting.props.meetingProp.intId, group.externalId, msg.body.userId, msg.body.sessionId) case _ =>
broadcastEvent(group.externalId, msg.body.userId, msg.body.sessionId)
}
case _ =>
} }
} }
} }

View File

@ -2,7 +2,6 @@ package org.bigbluebutton.core.apps.pads
import org.bigbluebutton.common2.msgs._ import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.bus.MessageBus import org.bigbluebutton.core.bus.MessageBus
import org.bigbluebutton.core.db.SharedNotesSessionDAO
import org.bigbluebutton.core.models.Pads import org.bigbluebutton.core.models.Pads
import org.bigbluebutton.core.running.LiveMeeting import org.bigbluebutton.core.running.LiveMeeting
@ -23,11 +22,8 @@ trait PadSessionDeletedSysMsgHdlr {
} }
Pads.getGroupById(liveMeeting.pads, msg.body.groupId) match { Pads.getGroupById(liveMeeting.pads, msg.body.groupId) match {
case Some(group) => { case Some(group) => broadcastEvent(group.externalId, msg.body.userId, msg.body.sessionId)
SharedNotesSessionDAO.delete(liveMeeting.props.meetingProp.intId, msg.body.userId, msg.body.sessionId) case _ =>
broadcastEvent(group.externalId, msg.body.userId, msg.body.sessionId)
}
case _ =>
} }
} }
} }

View File

@ -2,7 +2,6 @@ package org.bigbluebutton.core.apps.pads
import org.bigbluebutton.common2.msgs._ import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.bus.MessageBus import org.bigbluebutton.core.bus.MessageBus
import org.bigbluebutton.core.db.{ SharedNotesRevDAO }
import org.bigbluebutton.core.models.Pads import org.bigbluebutton.core.models.Pads
import org.bigbluebutton.core.running.LiveMeeting import org.bigbluebutton.core.running.LiveMeeting
@ -23,12 +22,8 @@ trait PadUpdatedSysMsgHdlr {
} }
Pads.getGroupById(liveMeeting.pads, msg.body.groupId) match { Pads.getGroupById(liveMeeting.pads, msg.body.groupId) match {
case Some(group) => { case Some(group) => broadcastEvent(group.externalId, msg.body.padId, msg.body.userId, msg.body.rev, msg.body.changeset)
Pads.setRev(liveMeeting.pads, group.externalId, msg.body.rev) case _ =>
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)
}
case _ =>
} }
} }
} }

View File

@ -1,9 +1,10 @@
package org.bigbluebutton.core.apps.pads package org.bigbluebutton.core.apps.pads
import org.apache.pekko.actor.ActorContext import akka.actor.ActorContext
class PadsApp2x(implicit val context: ActorContext) class PadsApp2x(implicit val context: ActorContext)
extends PadGroupCreatedEvtMsgHdlr extends PadCreateGroupReqMsgHdlr
with PadGroupCreatedEvtMsgHdlr
with PadCreateReqMsgHdlr with PadCreateReqMsgHdlr
with PadCreatedEvtMsgHdlr with PadCreatedEvtMsgHdlr
with PadCreateSessionReqMsgHdlr with PadCreateSessionReqMsgHdlr

View File

@ -1,30 +0,0 @@
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)
}
}

View File

@ -1,29 +0,0 @@
package org.bigbluebutton.core.apps.plugin
import org.bigbluebutton.common2.msgs.PluginDataChannelDeleteEntryMsg
import org.bigbluebutton.core.apps.plugin.PluginHdlrHelpers.{ checkPermission, dataChannelCheckingLogic, defaultCreatorCheck }
import org.bigbluebutton.core.db.PluginDataChannelEntryDAO
import org.bigbluebutton.core.domain.MeetingState2x
import org.bigbluebutton.core.running.{ HandlerHelpers, LiveMeeting }
trait PluginDataChannelDeleteEntryMsgHdlr extends HandlerHelpers {
def handle(msg: PluginDataChannelDeleteEntryMsg, state: MeetingState2x, liveMeeting: LiveMeeting): Unit = {
dataChannelCheckingLogic(liveMeeting, msg.header.userId, msg.body.pluginName, msg.body.channelName, (user, dc, meetingId) => {
val hasPermission = checkPermission(user, dc.replaceOrDeletePermission, defaultCreatorCheck(
meetingId, msg.body, msg.header.userId
))
if (!hasPermission.contains(true)) {
println(s"No permission to delete in plugin: '${msg.body.pluginName}', data channel: '${msg.body.channelName}'.")
} else {
PluginDataChannelEntryDAO.delete(
meetingId,
msg.body.pluginName,
msg.body.channelName,
msg.body.subChannelName,
msg.body.entryId
)
}
})
}
}

View File

@ -1,30 +0,0 @@
package org.bigbluebutton.core.apps.plugin
import org.bigbluebutton.common2.msgs.PluginDataChannelPushEntryMsg
import org.bigbluebutton.core.apps.plugin.PluginHdlrHelpers.{ checkPermission, dataChannelCheckingLogic, defaultCreatorCheck }
import org.bigbluebutton.core.db.PluginDataChannelEntryDAO
import org.bigbluebutton.core.domain.MeetingState2x
import org.bigbluebutton.core.running.{ HandlerHelpers, LiveMeeting }
trait PluginDataChannelPushEntryMsgHdlr extends HandlerHelpers {
def handle(msg: PluginDataChannelPushEntryMsg, state: MeetingState2x, liveMeeting: LiveMeeting): Unit = {
dataChannelCheckingLogic(liveMeeting, msg.header.userId, msg.body.pluginName, msg.body.channelName, (user, dc, meetingId) => {
val hasPermission = checkPermission(user, dc.pushPermission)
if (!hasPermission.contains(true)) {
println(s"No permission to write in plugin: '${msg.body.pluginName}', data channel: '${msg.body.channelName}'.")
} else {
PluginDataChannelEntryDAO.insert(
meetingId,
msg.body.pluginName,
msg.body.channelName,
msg.body.subChannelName,
msg.header.userId,
msg.body.payloadJson,
msg.body.toRoles,
msg.body.toUserIds
)
}
})
}
}

View File

@ -1,31 +0,0 @@
package org.bigbluebutton.core.apps.plugin
import org.bigbluebutton.common2.msgs.PluginDataChannelReplaceEntryMsg
import org.bigbluebutton.core.apps.plugin.PluginHdlrHelpers.{checkPermission, dataChannelCheckingLogic, defaultCreatorCheck}
import org.bigbluebutton.core.db.{JsonUtils, PluginDataChannelEntryDAO}
import org.bigbluebutton.core.domain.MeetingState2x
import org.bigbluebutton.core.running.{HandlerHelpers, LiveMeeting}
trait PluginDataChannelReplaceEntryMsgHdlr extends HandlerHelpers {
def handle(msg: PluginDataChannelReplaceEntryMsg, state: MeetingState2x, liveMeeting: LiveMeeting): Unit = {
dataChannelCheckingLogic(liveMeeting, msg.header.userId, msg.body.pluginName, msg.body.channelName, (user, dc, meetingId) => {
val hasPermission = checkPermission(user, dc.replaceOrDeletePermission, defaultCreatorCheck(
meetingId, msg.body, msg.header.userId))
if (!hasPermission.contains(true)) {
println(s"No permission to write in plugin: '${msg.body.pluginName}', data channel: '${msg.body.channelName}'.")
} else {
PluginDataChannelEntryDAO.replace(
msg.header.meetingId,
msg.body.pluginName,
msg.body.channelName,
msg.body.subChannelName,
msg.body.entryId,
JsonUtils.mapToJson(msg.body.payloadJson),
)
}
})
}
}

View File

@ -1,27 +0,0 @@
package org.bigbluebutton.core.apps.plugin
import org.bigbluebutton.common2.msgs.PluginDataChannelResetMsg
import org.bigbluebutton.core.apps.plugin.PluginHdlrHelpers.{ checkPermission, dataChannelCheckingLogic }
import org.bigbluebutton.core.db.PluginDataChannelEntryDAO
import org.bigbluebutton.core.domain.MeetingState2x
import org.bigbluebutton.core.running.{ HandlerHelpers, LiveMeeting }
trait PluginDataChannelResetMsgHdlr extends HandlerHelpers {
def handle(msg: PluginDataChannelResetMsg, state: MeetingState2x, liveMeeting: LiveMeeting): Unit = {
dataChannelCheckingLogic(liveMeeting, msg.header.userId, msg.body.pluginName, msg.body.channelName, (user, dc, meetingId) => {
val hasPermission = checkPermission(user, dc.replaceOrDeletePermission)
if (!hasPermission.contains(true)) {
println(s"No permission to delete (reset) in plugin: '${msg.body.pluginName}', data channel: '${msg.body.channelName}'.")
} else {
PluginDataChannelEntryDAO.reset(
meetingId,
msg.body.pluginName,
msg.body.channelName,
msg.body.subChannelName
)
}
})
}
}

View File

@ -1,50 +0,0 @@
package org.bigbluebutton.core.apps.plugin
import org.bigbluebutton.common2.msgs.PluginDataChannelReplaceOrDeleteBaseBody
import org.bigbluebutton.core.db.PluginDataChannelEntryDAO
import org.bigbluebutton.core.models.{ DataChannel, PluginModel, Roles, UserState, Users2x }
import org.bigbluebutton.core.running.LiveMeeting
object PluginHdlrHelpers {
def checkPermission(user: UserState, permissionType: List[String], creatorCheck: => Boolean = false): List[Boolean] = {
permissionType.map(_.toLowerCase).map {
case "all" => true
case "moderator" => user.role == Roles.MODERATOR_ROLE
case "presenter" => user.presenter
case "creator" => creatorCheck
case _ => false
}
}
def defaultCreatorCheck[T <: PluginDataChannelReplaceOrDeleteBaseBody](meetingId: String, msgBody: T, userId: String): Boolean = {
val creatorUserId = PluginDataChannelEntryDAO.getEntryCreator(
meetingId,
msgBody.pluginName,
msgBody.channelName,
msgBody.subChannelName,
msgBody.entryId
)
creatorUserId == userId
}
def dataChannelCheckingLogic(liveMeeting: LiveMeeting, userId: String,
pluginName: String, channelName: String,
caseSomeDataChannelAndPlugin: (UserState, DataChannel, String) => Unit): Option[Unit] = {
val pluginsDisabled: Boolean = liveMeeting.props.meetingProp.disabledFeatures.contains("plugins")
val meetingId = liveMeeting.props.meetingProp.intId
for {
_ <- if (!pluginsDisabled) Some(()) else None
user <- Users2x.findWithIntId(liveMeeting.users2x, userId)
} yield {
PluginModel.getPluginByName(liveMeeting.plugins, pluginName) match {
case Some(p) =>
p.manifest.content.dataChannels.getOrElse(List()).find(dc => dc.name == channelName) match {
case Some(dc) =>
caseSomeDataChannelAndPlugin(user, dc, meetingId)
case None => println(s"Data channel '${channelName}' not found in plugin '${pluginName}'.")
}
case None => println(s"Plugin '${pluginName}' not found.")
}
}
}
}

View File

@ -1,14 +0,0 @@
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 PluginDataChannelPushEntryMsgHdlr
with PluginDataChannelReplaceEntryMsgHdlr
with PluginDataChannelDeleteEntryMsgHdlr
with PluginDataChannelResetMsgHdlr {
val log = Logging(context.system, getClass)
}

View File

@ -1,7 +1,7 @@
package org.bigbluebutton.core.apps.polls package org.bigbluebutton.core.apps.polls
import org.apache.pekko.actor.ActorContext import akka.actor.ActorContext
import org.apache.pekko.event.Logging import akka.event.Logging
class PollApp2x(implicit val context: ActorContext) class PollApp2x(implicit val context: ActorContext)
extends GetCurrentPollReqMsgHdlr extends GetCurrentPollReqMsgHdlr

View File

@ -1,56 +0,0 @@
package org.bigbluebutton.core.apps.polls
import org.bigbluebutton.common2.domain.SimplePollResultOutVO
import org.bigbluebutton.common2.msgs.{ BbbClientMsgHeader, BbbCommonEnvCoreMsg, BbbCoreEnvelope, MessageTypes, PollUpdatedEvtMsg, PollUpdatedEvtMsgBody, Routing, UserRespondedToPollRecordMsg, UserRespondedToPollRecordMsgBody, UserRespondedToPollRespMsg, UserRespondedToPollRespMsgBody, UserRespondedToTypedPollRespMsg, UserRespondedToTypedPollRespMsgBody }
import org.bigbluebutton.core.running.OutMsgRouter
object PollHdlrHelpers {
def broadcastPollUpdatedEvent(outGW: OutMsgRouter, meetingId: String, userId: String, pollId: String, poll: SimplePollResultOutVO): Unit = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, userId)
val envelope = BbbCoreEnvelope(PollUpdatedEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(PollUpdatedEvtMsg.NAME, meetingId, userId)
val body = PollUpdatedEvtMsgBody(pollId, poll)
val event = PollUpdatedEvtMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
outGW.send(msgEvent)
}
def broadcastUserRespondedToTypedPollRespMsg(outGW: OutMsgRouter, meetingId: String, userId: String,
pollId: String, answer: String, sendToId: String): Unit = {
val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, meetingId, sendToId)
val envelope = BbbCoreEnvelope(UserRespondedToTypedPollRespMsg.NAME, routing)
val header = BbbClientMsgHeader(UserRespondedToTypedPollRespMsg.NAME, meetingId, sendToId)
val body = UserRespondedToTypedPollRespMsgBody(pollId, userId, answer)
val event = UserRespondedToTypedPollRespMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
outGW.send(msgEvent)
}
def broadcastUserRespondedToPollRecordMsg(outGW: OutMsgRouter, meetingId: String, userId: String,
pollId: String, answerId: Int, answer: String, isSecret: Boolean): Unit = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, userId)
val envelope = BbbCoreEnvelope(UserRespondedToPollRecordMsg.NAME, routing)
val header = BbbClientMsgHeader(UserRespondedToPollRecordMsg.NAME, meetingId, userId)
val body = UserRespondedToPollRecordMsgBody(pollId, answerId, answer, isSecret)
val event = UserRespondedToPollRecordMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
outGW.send(msgEvent)
}
def broadcastUserRespondedToPollRespMsg(outGW: OutMsgRouter, meetingId: String, userId: String,
pollId: String, answerIds: Seq[Int], sendToId: String): Unit = {
val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, meetingId, sendToId)
val envelope = BbbCoreEnvelope(UserRespondedToPollRespMsg.NAME, routing)
val header = BbbClientMsgHeader(UserRespondedToPollRespMsg.NAME, meetingId, sendToId)
val body = UserRespondedToPollRespMsgBody(pollId, userId, answerIds)
val event = UserRespondedToPollRespMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
outGW.send(msgEvent)
}
}

View File

@ -4,7 +4,7 @@ import org.bigbluebutton.common2.domain.SimplePollResultOutVO
import org.bigbluebutton.common2.msgs._ import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.bus.MessageBus import org.bigbluebutton.core.bus.MessageBus
import org.bigbluebutton.core.models.Polls import org.bigbluebutton.core.models.Polls
import org.bigbluebutton.core.running.LiveMeeting import org.bigbluebutton.core.running.{ LiveMeeting }
import org.bigbluebutton.core.models.Users2x import org.bigbluebutton.core.models.Users2x
trait RespondToPollReqMsgHdlr { trait RespondToPollReqMsgHdlr {
@ -12,12 +12,45 @@ trait RespondToPollReqMsgHdlr {
def handle(msg: RespondToPollReqMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = { def handle(msg: RespondToPollReqMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
if (!Polls.hasUserAlreadyResponded(msg.body.pollId, msg.header.userId, liveMeeting.polls)) { def broadcastPollUpdatedEvent(msg: RespondToPollReqMsg, pollId: String, poll: SimplePollResultOutVO): Unit = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, msg.header.userId)
val envelope = BbbCoreEnvelope(PollUpdatedEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(PollUpdatedEvtMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId)
val body = PollUpdatedEvtMsgBody(pollId, poll)
val event = PollUpdatedEvtMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
bus.outGW.send(msgEvent)
}
def broadcastUserRespondedToPollRecordMsg(msg: RespondToPollReqMsg, pollId: String, answerId: Int, answer: String, isSecret: Boolean): Unit = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, msg.header.userId)
val envelope = BbbCoreEnvelope(UserRespondedToPollRecordMsg.NAME, routing)
val header = BbbClientMsgHeader(UserRespondedToPollRecordMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId)
val body = UserRespondedToPollRecordMsgBody(pollId, answerId, answer, isSecret)
val event = UserRespondedToPollRecordMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
bus.outGW.send(msgEvent)
}
def broadcastUserRespondedToPollRespMsg(msg: RespondToPollReqMsg, pollId: String, answerIds: Seq[Int], sendToId: String): Unit = {
val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, liveMeeting.props.meetingProp.intId, sendToId)
val envelope = BbbCoreEnvelope(UserRespondedToPollRespMsg.NAME, routing)
val header = BbbClientMsgHeader(UserRespondedToPollRespMsg.NAME, liveMeeting.props.meetingProp.intId, sendToId)
val body = UserRespondedToPollRespMsgBody(pollId, msg.header.userId, answerIds)
val event = UserRespondedToPollRespMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
bus.outGW.send(msgEvent)
}
if (Polls.checkUserResponded(msg.body.pollId, msg.header.userId, liveMeeting.polls) == false) {
for { for {
(pollId: String, updatedPoll: SimplePollResultOutVO) <- Polls.handleRespondToPollReqMsg(msg.header.userId, msg.body.pollId, (pollId: String, updatedPoll: SimplePollResultOutVO) <- Polls.handleRespondToPollReqMsg(msg.header.userId, msg.body.pollId,
msg.body.questionId, msg.body.answerIds, liveMeeting) msg.body.questionId, msg.body.answerIds, liveMeeting)
} yield { } yield {
PollHdlrHelpers.broadcastPollUpdatedEvent(bus.outGW, liveMeeting.props.meetingProp.intId, msg.header.userId, pollId, updatedPoll) broadcastPollUpdatedEvent(msg, pollId, updatedPoll)
for { for {
poll <- Polls.getPoll(pollId, liveMeeting.polls) poll <- Polls.getPoll(pollId, liveMeeting.polls)
} yield { } yield {
@ -25,14 +58,14 @@ trait RespondToPollReqMsgHdlr {
answerId <- msg.body.answerIds answerId <- msg.body.answerIds
} yield { } yield {
val answerText = poll.questions(0).answers.get(answerId).key val answerText = poll.questions(0).answers.get(answerId).key
PollHdlrHelpers.broadcastUserRespondedToPollRecordMsg(bus.outGW, liveMeeting.props.meetingProp.intId, msg.header.userId, pollId, answerId, answerText, poll.isSecret) broadcastUserRespondedToPollRecordMsg(msg, pollId, answerId, answerText, poll.isSecret)
} }
} }
for { for {
presenter <- Users2x.findPresenter(liveMeeting.users2x) presenter <- Users2x.findPresenter(liveMeeting.users2x)
} yield { } yield {
PollHdlrHelpers.broadcastUserRespondedToPollRespMsg(bus.outGW, liveMeeting.props.meetingProp.intId, msg.header.userId, pollId, msg.body.answerIds, presenter.intId) broadcastUserRespondedToPollRespMsg(msg, pollId, msg.body.answerIds, presenter.intId)
} }
} }
} else { } else {

View File

@ -1,11 +1,10 @@
package org.bigbluebutton.core.apps.polls package org.bigbluebutton.core.apps.polls
import org.bigbluebutton.ClientSettings.getConfigPropertyValueByPathAsIntOrElse
import org.bigbluebutton.common2.domain.SimplePollResultOutVO import org.bigbluebutton.common2.domain.SimplePollResultOutVO
import org.bigbluebutton.common2.msgs._ import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.bus.MessageBus import org.bigbluebutton.core.bus.MessageBus
import org.bigbluebutton.core.models.Polls import org.bigbluebutton.core.models.Polls
import org.bigbluebutton.core.running.LiveMeeting import org.bigbluebutton.core.running.{ LiveMeeting }
import org.bigbluebutton.core.models.Users2x import org.bigbluebutton.core.models.Users2x
trait RespondToTypedPollReqMsgHdlr { trait RespondToTypedPollReqMsgHdlr {
@ -13,60 +12,43 @@ trait RespondToTypedPollReqMsgHdlr {
def handle(msg: RespondToTypedPollReqMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = { def handle(msg: RespondToTypedPollReqMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
def broadcastPollUpdatedEvent(msg: RespondToTypedPollReqMsg, pollId: String, poll: SimplePollResultOutVO): Unit = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, msg.header.userId)
val envelope = BbbCoreEnvelope(PollUpdatedEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(PollUpdatedEvtMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId)
val body = PollUpdatedEvtMsgBody(pollId, poll)
val event = PollUpdatedEvtMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
bus.outGW.send(msgEvent)
}
def broadcastUserRespondedToTypedPollRespMsg(msg: RespondToTypedPollReqMsg, pollId: String, answer: String, sendToId: String): Unit = {
val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, liveMeeting.props.meetingProp.intId, sendToId)
val envelope = BbbCoreEnvelope(UserRespondedToTypedPollRespMsg.NAME, routing)
val header = BbbClientMsgHeader(UserRespondedToTypedPollRespMsg.NAME, liveMeeting.props.meetingProp.intId, sendToId)
val body = UserRespondedToTypedPollRespMsgBody(pollId, msg.header.userId, answer)
val event = UserRespondedToTypedPollRespMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
bus.outGW.send(msgEvent)
}
if (Polls.isResponsePollType(msg.body.pollId, liveMeeting.polls) && if (Polls.isResponsePollType(msg.body.pollId, liveMeeting.polls) &&
!Polls.hasUserAlreadyResponded(msg.body.pollId, msg.header.userId, liveMeeting.polls) && Polls.checkUserResponded(msg.body.pollId, msg.header.userId, liveMeeting.polls) == false &&
!Polls.hasUserAlreadyAddedTypedAnswer(msg.body.pollId, msg.header.userId, liveMeeting.polls)) { Polls.checkUserAddedQuestion(msg.body.pollId, msg.header.userId, liveMeeting.polls) == false) {
for {
(pollId: String, updatedPoll: SimplePollResultOutVO) <- Polls.handleRespondToTypedPollReqMsg(msg.header.userId, msg.body.pollId,
msg.body.questionId, msg.body.answer, liveMeeting)
} yield {
broadcastPollUpdatedEvent(msg, pollId, updatedPoll)
//Truncate answer case it is longer than `maxTypedAnswerLength` for {
val maxTypedAnswerLength = getConfigPropertyValueByPathAsIntOrElse(liveMeeting.clientSettings, "public.poll.maxTypedAnswerLength", 45) presenter <- Users2x.findPresenter(liveMeeting.users2x)
val answer = msg.body.answer.substring(0, Math.min(msg.body.answer.length, maxTypedAnswerLength)) } yield {
broadcastUserRespondedToTypedPollRespMsg(msg, pollId, msg.body.answer, presenter.intId)
val answerExists = Polls.findAnswerWithText(msg.body.pollId, msg.body.questionId, answer, liveMeeting.polls)
//Create answer if it doesn't exist
answerExists match {
case None => {
for {
(pollId: String, updatedPoll: SimplePollResultOutVO) <- Polls.handleRespondToTypedPollReqMsg(msg.header.userId, msg.body.pollId,
msg.body.questionId, answer, liveMeeting)
} yield {
PollHdlrHelpers.broadcastPollUpdatedEvent(bus.outGW, liveMeeting.props.meetingProp.intId, msg.header.userId, pollId, updatedPoll)
for {
presenter <- Users2x.findPresenter(liveMeeting.users2x)
} yield {
PollHdlrHelpers.broadcastUserRespondedToTypedPollRespMsg(bus.outGW, liveMeeting.props.meetingProp.intId, msg.header.userId, pollId, answer, presenter.intId)
}
}
} }
case _ => //Do nothing, answer with same text exists already
} }
//Submit the answer
Polls.findAnswerWithText(msg.body.pollId, msg.body.questionId, answer, liveMeeting.polls) match {
case Some(answerId) => {
for {
(pollId: String, updatedPoll: SimplePollResultOutVO) <- Polls.handleRespondToPollReqMsg(msg.header.userId, msg.body.pollId,
msg.body.questionId, Seq(answerId), liveMeeting)
} yield {
PollHdlrHelpers.broadcastPollUpdatedEvent(bus.outGW, liveMeeting.props.meetingProp.intId, msg.header.userId, pollId, updatedPoll)
for {
poll <- Polls.getPoll(pollId, liveMeeting.polls)
} yield {
val answerText = poll.questions(0).answers.get(answerId).key
PollHdlrHelpers.broadcastUserRespondedToPollRecordMsg(bus.outGW, liveMeeting.props.meetingProp.intId, msg.header.userId, pollId, answerId, answerText, poll.isSecret)
}
for {
presenter <- Users2x.findPresenter(liveMeeting.users2x)
} yield {
PollHdlrHelpers.broadcastUserRespondedToPollRespMsg(bus.outGW, liveMeeting.props.meetingProp.intId, msg.header.userId, pollId, Seq(answerId), presenter.intId)
}
}
}
case None => log.error("Error while trying to answer the poll {} in meeting {}: Answer not found or something went wrong while trying to create the answer.", msg.body.pollId, msg.header.meetingId)
}
} else { } else {
log.info("Ignoring typed answer from user {} once user already added an answer to this poll {} in meeting {}", msg.header.userId, msg.body.pollId, msg.header.meetingId) log.info("Ignoring typed answer from user {} once user already added an answer to this poll {} in meeting {}", msg.header.userId, msg.body.pollId, msg.header.meetingId)
} }

View File

@ -2,15 +2,12 @@ package org.bigbluebutton.core.apps.polls
import org.bigbluebutton.common2.domain.SimplePollResultOutVO import org.bigbluebutton.common2.domain.SimplePollResultOutVO
import org.bigbluebutton.common2.msgs._ import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.apps.groupchats.GroupChatApp
import org.bigbluebutton.core.bus.MessageBus import org.bigbluebutton.core.bus.MessageBus
import org.bigbluebutton.core.domain.MeetingState2x import org.bigbluebutton.core.domain.MeetingState2x
import org.bigbluebutton.core.models.Polls import org.bigbluebutton.core.models.Polls
import org.bigbluebutton.core.running.LiveMeeting import org.bigbluebutton.core.running.LiveMeeting
import org.bigbluebutton.core.apps.{PermissionCheck, RightsManagementTrait} import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
import org.bigbluebutton.core.db.{ChatMessageDAO, JsonUtils, NotificationDAO} import org.bigbluebutton.core2.message.senders.{ MsgBuilder }
import org.bigbluebutton.core2.message.senders.MsgBuilder
import spray.json.DefaultJsonProtocol.jsonFormat2
trait ShowPollResultReqMsgHdlr extends RightsManagementTrait { trait ShowPollResultReqMsgHdlr extends RightsManagementTrait {
this: PollApp2x => this: PollApp2x =>
@ -37,7 +34,6 @@ trait ShowPollResultReqMsgHdlr extends RightsManagementTrait {
Vector() Vector()
) )
bus.outGW.send(notifyEvent) bus.outGW.send(notifyEvent)
NotificationDAO.insert(notifyEvent)
// SendWhiteboardAnnotationPubMsg // SendWhiteboardAnnotationPubMsg
val annotationRouting = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, msg.header.userId) val annotationRouting = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, msg.header.userId)
@ -58,27 +54,6 @@ trait ShowPollResultReqMsgHdlr extends RightsManagementTrait {
for { for {
(result, annotationProp) <- Polls.handleShowPollResultReqMsg(state, msg.header.userId, msg.body.pollId, liveMeeting) (result, annotationProp) <- Polls.handleShowPollResultReqMsg(state, msg.header.userId, msg.body.pollId, liveMeeting)
} yield { } yield {
//it will be used to render the chat message (will be stored as json in chat-msg metadata)
val resultAsSimpleMap = Map(
"id" -> result.id,
"questionType" -> result.questionType,
"questionText" -> result.questionText.getOrElse(""),
"answers" -> {
for {
answer <- result.answers
} yield {
Map(
"id" -> answer.id,
"key" -> answer.key,
"numVotes" -> answer.numVotes
)
}
},
"numRespondents" -> result.numRespondents,
"numResponders" -> result.numResponders,
)
ChatMessageDAO.insertSystemMsg(liveMeeting.props.meetingProp.intId, GroupChatApp.MAIN_PUBLIC_CHAT, "", GroupChatMessageType.POLL, resultAsSimpleMap, "")
broadcastEvent(msg, result, annotationProp) broadcastEvent(msg, result, annotationProp)
} }
} }

View File

@ -1,7 +1,7 @@
package org.bigbluebutton.core.apps.presentation package org.bigbluebutton.core.apps.presentation
import org.apache.pekko.actor.ActorContext import akka.actor.ActorContext
import org.apache.pekko.event.Logging import akka.event.Logging
import org.bigbluebutton.core.apps.Presentation import org.bigbluebutton.core.apps.Presentation
import org.bigbluebutton.core.running.LiveMeeting import org.bigbluebutton.core.running.LiveMeeting

View File

@ -1,11 +1,10 @@
package org.bigbluebutton.core.apps.presentationpod package org.bigbluebutton.core.apps.presentationpod
import org.bigbluebutton.common2.msgs._ import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.api.{ CapturePresentationReqInternalMsg } import org.bigbluebutton.core.api.{ CapturePresentationReqInternalMsg, CaptureSharedNotesReqInternalMsg }
import org.bigbluebutton.core.apps.groupchats.GroupChatApp
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait } import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
import org.bigbluebutton.core.apps.presentationpod.PresentationSender
import org.bigbluebutton.core.bus.MessageBus import org.bigbluebutton.core.bus.MessageBus
import org.bigbluebutton.core.db.{ ChatMessageDAO, PresPresentationDAO }
import org.bigbluebutton.core.domain.MeetingState2x import org.bigbluebutton.core.domain.MeetingState2x
import org.bigbluebutton.core.running.LiveMeeting import org.bigbluebutton.core.running.LiveMeeting
import org.bigbluebutton.core.util.RandomStringGenerator import org.bigbluebutton.core.util.RandomStringGenerator
@ -45,20 +44,19 @@ trait MakePresentationDownloadReqMsgHdlr extends RightsManagementTrait {
def buildNewPresFileAvailable(annotatedFileURI: String, originalFileURI: String, convertedFileURI: String, def buildNewPresFileAvailable(annotatedFileURI: String, originalFileURI: String, convertedFileURI: String,
presId: String, fileStateType: String): NewPresFileAvailableMsg = { presId: String, fileStateType: String): NewPresFileAvailableMsg = {
val header = BbbClientMsgHeader(NewPresFileAvailableMsg.NAME, "not-used", "not-used") val header = BbbClientMsgHeader(NewPresFileAvailableMsg.NAME, "not-used", "not-used")
val body = NewPresFileAvailableMsgBody(annotatedFileURI, originalFileURI, convertedFileURI, presId, fileStateType, "") val body = NewPresFileAvailableMsgBody(annotatedFileURI, originalFileURI, convertedFileURI, presId, fileStateType)
NewPresFileAvailableMsg(header, body) NewPresFileAvailableMsg(header, body)
} }
def buildBroadcastNewPresFileAvailable(newPresFileAvailableMsg: NewPresFileAvailableMsg, liveMeeting: LiveMeeting): BbbCommonEnvCoreMsg = { def buildBroadcastNewPresFileAvailable(newPresFileAvailableMsg: NewPresFileAvailableMsg, liveMeeting: LiveMeeting): BbbCommonEnvCoreMsg = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, "not-used") val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, "not-used")
val envelope = BbbCoreEnvelope(NewPresFileAvailableEvtMsg.NAME, routing) val envelope = BbbCoreEnvelope(PresentationPageConvertedEventMsg.NAME, routing)
val header = BbbClientMsgHeader(NewPresFileAvailableEvtMsg.NAME, liveMeeting.props.meetingProp.intId, "not-used") val header = BbbClientMsgHeader(NewPresFileAvailableEvtMsg.NAME, liveMeeting.props.meetingProp.intId, "not-used")
val body = NewPresFileAvailableEvtMsgBody( val body = NewPresFileAvailableEvtMsgBody(
annotatedFileURI = newPresFileAvailableMsg.body.annotatedFileURI, annotatedFileURI = newPresFileAvailableMsg.body.annotatedFileURI,
originalFileURI = newPresFileAvailableMsg.body.originalFileURI, originalFileURI = newPresFileAvailableMsg.body.originalFileURI,
convertedFileURI = newPresFileAvailableMsg.body.convertedFileURI, convertedFileURI = newPresFileAvailableMsg.body.convertedFileURI, presId = newPresFileAvailableMsg.body.presId,
presId = newPresFileAvailableMsg.body.presId,
fileStateType = newPresFileAvailableMsg.body.fileStateType fileStateType = newPresFileAvailableMsg.body.fileStateType
) )
val event = NewPresFileAvailableEvtMsg(header, body) val event = NewPresFileAvailableEvtMsg(header, body)
@ -85,11 +83,11 @@ trait MakePresentationDownloadReqMsgHdlr extends RightsManagementTrait {
BbbCommonEnvCoreMsg(envelope, event) BbbCommonEnvCoreMsg(envelope, event)
} }
def buildPresentationUploadTokenSysPubMsg(parentMeetingId: String, userId: String, presentationUploadToken: String, filename: String, presId: String): BbbCommonEnvCoreMsg = { def buildPresentationUploadTokenSysPubMsg(parentId: String, userId: String, presentationUploadToken: String, filename: String): BbbCommonEnvCoreMsg = {
val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka") val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka")
val envelope = BbbCoreEnvelope(PresentationUploadTokenSysPubMsg.NAME, routing) val envelope = BbbCoreEnvelope(PresentationUploadTokenSysPubMsg.NAME, routing)
val header = BbbClientMsgHeader(PresentationUploadTokenSysPubMsg.NAME, parentMeetingId, userId) val header = BbbClientMsgHeader(PresentationUploadTokenSysPubMsg.NAME, parentId, userId)
val body = PresentationUploadTokenSysPubMsgBody("DEFAULT_PRESENTATION_POD", presentationUploadToken, filename, parentMeetingId, presId) val body = PresentationUploadTokenSysPubMsgBody("DEFAULT_PRESENTATION_POD", presentationUploadToken, filename, parentId)
val event = PresentationUploadTokenSysPubMsg(header, body) val event = PresentationUploadTokenSysPubMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event) BbbCommonEnvCoreMsg(envelope, event)
} }
@ -103,11 +101,13 @@ trait MakePresentationDownloadReqMsgHdlr extends RightsManagementTrait {
val whiteboardId = s"${presId}/${pageNumber.toString}" val whiteboardId = s"${presId}/${pageNumber.toString}"
val presentationPage: PresentationPage = currentPres.get.pages(whiteboardId) val presentationPage: PresentationPage = currentPres.get.pages(whiteboardId)
val width: Double = presentationPage.width val xOffset: Double = presentationPage.xOffset
val height: Double = presentationPage.height val yOffset: Double = presentationPage.yOffset
val widthRatio: Double = presentationPage.widthRatio
val heightRatio: Double = presentationPage.heightRatio
val whiteboardHistory: Array[AnnotationVO] = liveMeeting.wbModel.getHistory(whiteboardId) val whiteboardHistory: Array[AnnotationVO] = liveMeeting.wbModel.getHistory(whiteboardId)
val page = new PresentationPageForExport(pageNumber, width, height, whiteboardHistory) val page = new PresentationPageForExport(pageNumber, xOffset, yOffset, widthRatio, heightRatio, whiteboardHistory)
getPresentationPagesForExport(pages, pageCount, presId, currentPres, liveMeeting, storeAnnotationPages :+ page) getPresentationPagesForExport(pages, pageCount, presId, currentPres, liveMeeting, storeAnnotationPages :+ page)
} else { } else {
getPresentationPagesForExport(pages, pageCount, presId, currentPres, liveMeeting, storeAnnotationPages) getPresentationPagesForExport(pages, pageCount, presId, currentPres, liveMeeting, storeAnnotationPages)
@ -157,7 +157,7 @@ trait MakePresentationDownloadReqMsgHdlr extends RightsManagementTrait {
val pages: List[Int] = m.body.pages // Desired presentation pages for export val pages: List[Int] = m.body.pages // Desired presentation pages for export
val pagesRange: List[Int] = if (allPages) (1 to pageCount).toList else pages val pagesRange: List[Int] = if (allPages) (1 to pageCount).toList else pages
val exportJob: ExportJob = new ExportJob(jobId, JobTypes.DOWNLOAD, currentPres.get.name, "annotated_slides", presId, presLocation, allPages, pagesRange, meetingId, ""); val exportJob: ExportJob = new ExportJob(jobId, JobTypes.DOWNLOAD, "annotated_slides", presId, presLocation, allPages, pagesRange, meetingId, "");
val storeAnnotationPages: List[PresentationPageForExport] = getPresentationPagesForExport(pagesRange, pageCount, presId, currentPres, liveMeeting); val storeAnnotationPages: List[PresentationPageForExport] = getPresentationPagesForExport(pagesRange, pageCount, presId, currentPres, liveMeeting);
val isPresentationOriginalOrConverted = m.body.fileStateType == "Original" || m.body.fileStateType == "Converted" val isPresentationOriginalOrConverted = m.body.fileStateType == "Original" || m.body.fileStateType == "Converted"
@ -203,22 +203,15 @@ trait MakePresentationDownloadReqMsgHdlr extends RightsManagementTrait {
val filename = m.filename val filename = m.filename
val presentationUploadToken: String = PresentationPodsApp.generateToken("DEFAULT_PRESENTATION_POD", userId) val presentationUploadToken: String = PresentationPodsApp.generateToken("DEFAULT_PRESENTATION_POD", userId)
val presentationId = PresentationPodsApp.generatePresentationId(m.filename)
// Informs bbb-web about the token so that when we use it to upload the presentation, it is able to look it up in the list of tokens // Informs bbb-web about the token so that when we use it to upload the presentation, it is able to look it up in the list of tokens
bus.outGW.send(buildPresentationUploadTokenSysPubMsg(parentMeetingId, userId, presentationUploadToken, filename, presentationId)) bus.outGW.send(buildPresentationUploadTokenSysPubMsg(parentMeetingId, userId, presentationUploadToken, filename))
var pres = new PresentationInPod(presentationId, default = false, current = false, name = filename,
pages = Map.empty, downloadable = false, downloadFileExtension = "", removable = true, filenameConverted = filename,
uploadCompleted = false, numPages = 0, errorMsgKey = "", errorDetails = Map.empty)
if (liveMeeting.props.meetingProp.disabledFeatures.contains("importPresentationWithAnnotationsFromBreakoutRooms")) { if (liveMeeting.props.meetingProp.disabledFeatures.contains("importPresentationWithAnnotationsFromBreakoutRooms")) {
log.error(s"Capturing breakout rooms slides disabled in meeting ${meetingId}.") log.error(s"Capturing breakout rooms slides disabled in meeting ${meetingId}.")
} else if (currentPres.isEmpty) { } else if (currentPres.isEmpty) {
log.error(s"No presentation set in meeting ${meetingId}") log.error(s"No presentation set in meeting ${meetingId}")
pres = pres.copy(errorMsgKey = "204")
bus.outGW.send(buildBroadcastPresentationConversionUpdateEvtMsg(parentMeetingId, "204", jobId, filename, presentationUploadToken)) bus.outGW.send(buildBroadcastPresentationConversionUpdateEvtMsg(parentMeetingId, "204", jobId, filename, presentationUploadToken))
PresPresentationDAO.updateConversionStarted(parentMeetingId, pres)
} else { } else {
val allPages: Boolean = m.allPages val allPages: Boolean = m.allPages
val pageCount = currentPres.get.pages.size val pageCount = currentPres.get.pages.size
@ -229,7 +222,7 @@ trait MakePresentationDownloadReqMsgHdlr extends RightsManagementTrait {
val currentPage: PresentationPage = PresentationInPod.getCurrentPage(currentPres.get).get val currentPage: PresentationPage = PresentationInPod.getCurrentPage(currentPres.get).get
val pagesRange: List[Int] = if (allPages) (1 to pageCount).toList else List(currentPage.num) val pagesRange: List[Int] = if (allPages) (1 to pageCount).toList else List(currentPage.num)
val exportJob: ExportJob = ExportJob(jobId, JobTypes.CAPTURE_PRESENTATION, filename, filename, presId, presLocation, allPages, pagesRange, parentMeetingId, presentationUploadToken) val exportJob: ExportJob = new ExportJob(jobId, JobTypes.CAPTURE_PRESENTATION, filename, presId, presLocation, allPages, pagesRange, parentMeetingId, presentationUploadToken)
val storeAnnotationPages: List[PresentationPageForExport] = getPresentationPagesForExport(pagesRange, pageCount, presId, currentPres, liveMeeting); val storeAnnotationPages: List[PresentationPageForExport] = getPresentationPagesForExport(pagesRange, pageCount, presId, currentPres, liveMeeting);
val annotationCount: Int = storeAnnotationPages.map(_.annotations.size).sum val annotationCount: Int = storeAnnotationPages.map(_.annotations.size).sum
@ -243,13 +236,9 @@ trait MakePresentationDownloadReqMsgHdlr extends RightsManagementTrait {
val annotations = new StoredAnnotations(jobId, presId, storeAnnotationPages) val annotations = new StoredAnnotations(jobId, presId, storeAnnotationPages)
bus.outGW.send(buildStoreAnnotationsInRedisSysMsg(annotations, liveMeeting)) bus.outGW.send(buildStoreAnnotationsInRedisSysMsg(annotations, liveMeeting))
} else { } else {
pres = pres.copy(errorMsgKey = "204")
// Notify that no content is available to capture // Notify that no content is available to capture
bus.outGW.send(buildBroadcastPresentationConversionUpdateEvtMsg(parentMeetingId, "204", jobId, filename, presentationUploadToken)) bus.outGW.send(buildBroadcastPresentationConversionUpdateEvtMsg(parentMeetingId, "204", jobId, filename, presentationUploadToken))
} }
PresPresentationDAO.updateConversionStarted(parentMeetingId, pres)
} }
} }
@ -258,25 +247,36 @@ trait MakePresentationDownloadReqMsgHdlr extends RightsManagementTrait {
"Received NewPresFileAvailableMsg meetingId={} presId={}", "Received NewPresFileAvailableMsg meetingId={} presId={}",
liveMeeting.props.meetingProp.intId, m.body.presId liveMeeting.props.meetingProp.intId, m.body.presId
) )
if (m.body.fileStateType == "Annotated") {
val presentationDownloadInfo = Map(
"fileURI" -> m.body.annotatedFileURI,
"filename" -> m.body.fileName
)
ChatMessageDAO.insertSystemMsg(liveMeeting.props.meetingProp.intId, GroupChatApp.MAIN_PUBLIC_CHAT, "", GroupChatMessageType.PRESENTATION, presentationDownloadInfo, "")
} else if (m.body.fileStateType == "Converted") {
PresPresentationDAO.updateDownloadUri(m.body.presId, m.body.convertedFileURI)
} else if (m.body.fileStateType == "Original") {
PresPresentationDAO.updateDownloadUri(m.body.presId, m.body.originalFileURI)
}
PresPresentationDAO.updateExportToChatStatus(m.body.presId, "EXPORTED")
bus.outGW.send(buildBroadcastNewPresFileAvailable(m, liveMeeting)) bus.outGW.send(buildBroadcastNewPresFileAvailable(m, liveMeeting))
} }
def handle(m: CaptureSharedNotesReqInternalMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
val parentMeetingId = liveMeeting.props.meetingProp.intId
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, parentMeetingId, "not-used")
val envelope = BbbCoreEnvelope(PresentationPageConversionStartedEventMsg.NAME, routing)
val header = BbbClientMsgHeader(CaptureSharedNotesReqEvtMsg.NAME, parentMeetingId, "not-used")
val body = CaptureSharedNotesReqEvtMsgBody(m.breakoutId, m.filename)
val event = CaptureSharedNotesReqEvtMsg(header, body)
bus.outGW.send(BbbCommonEnvCoreMsg(envelope, event))
}
def handle(m: PresAnnStatusMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = { def handle(m: PresAnnStatusMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
PresPresentationDAO.updateExportToChat(m.body.presId, m.body.status, m.body.pageNumber, m.body.error)
bus.outGW.send(buildBroadcastPresAnnStatusMsg(m, liveMeeting)) bus.outGW.send(buildBroadcastPresAnnStatusMsg(m, liveMeeting))
} }
def handle(m: PadCapturePubMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
val userId: String = "system"
val jobId: String = s"${m.body.breakoutId}-notes" // Used as the temporaryPresentationId upon upload
val filename = m.body.filename
val presentationUploadToken: String = PresentationPodsApp.generateToken("DEFAULT_PRESENTATION_POD", userId)
bus.outGW.send(buildPresentationUploadTokenSysPubMsg(m.body.parentMeetingId, userId, presentationUploadToken, filename))
val exportJob = new ExportJob(jobId, JobTypes.CAPTURE_NOTES, filename, m.body.padId, "", true, List(), m.body.parentMeetingId, presentationUploadToken)
val job = buildStoreExportJobInRedisSysMsg(exportJob, liveMeeting)
bus.outGW.send(job)
}
} }

View File

@ -2,9 +2,7 @@ package org.bigbluebutton.core.apps.presentationpod
import org.bigbluebutton.common2.msgs._ import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.bus.MessageBus import org.bigbluebutton.core.bus.MessageBus
import org.bigbluebutton.core.db.PresPresentationDAO
import org.bigbluebutton.core.domain.MeetingState2x import org.bigbluebutton.core.domain.MeetingState2x
import org.bigbluebutton.core.models.PresentationInPod
import org.bigbluebutton.core.running.LiveMeeting import org.bigbluebutton.core.running.LiveMeeting
trait PdfConversionInvalidErrorSysPubMsgHdlr { trait PdfConversionInvalidErrorSysPubMsgHdlr {
@ -32,30 +30,7 @@ trait PdfConversionInvalidErrorSysPubMsgHdlr {
bus.outGW.send(msgEvent) bus.outGW.send(msgEvent)
} }
val errorDetails = scala.collection.immutable.Map(
"bigPageNumber" -> msg.body.bigPageNumber.toString,
"bigPageSize" -> msg.body.bigPageSize.toString
)
val newState = for {
pod <- PresentationPodsApp.getPresentationPod(state, msg.body.podId)
pres <- pod.getPresentation(msg.body.presentationId)
} yield {
val presWithError = PresentationInPod(pres.id, pres.name, pres.default, pres.current, pres.pages, pres.downloadable,
pres.downloadFileExtension, pres.removable, pres.filenameConverted, pres.uploadCompleted, pres.numPages,
msg.body.messageKey, errorDetails)
var pods = state.presentationPodManager.addPod(pod)
pods = pods.addPresentationToPod(pod.id, presWithError)
state.update(pods)
}
PresPresentationDAO.updateErrors(msg.body.presentationId, msg.body.messageKey, errorDetails)
broadcastEvent(msg) broadcastEvent(msg)
state
newState match {
case Some(ns) => ns
case None => state
}
} }
} }

View File

@ -2,19 +2,17 @@ package org.bigbluebutton.core.apps.presentationpod
import org.bigbluebutton.common2.msgs._ import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.bus.MessageBus import org.bigbluebutton.core.bus.MessageBus
import org.bigbluebutton.core.db.PresPresentationDAO
import org.bigbluebutton.core.domain.MeetingState2x import org.bigbluebutton.core.domain.MeetingState2x
import org.bigbluebutton.core.models.PresentationInPod import org.bigbluebutton.core.models.PresentationInPod
import org.bigbluebutton.core.running.LiveMeeting import org.bigbluebutton.core.running.LiveMeeting
trait PresentationConversionCompletedSysPubMsgHdlr { trait PresentationConversionCompletedSysPubMsgHdlr {
this: PresentationPodHdlrs => this: PresentationPodHdlrs =>
def handle( def handle(
msg: PresentationConversionCompletedSysPubMsg, msg: PresentationConversionCompletedSysPubMsg, state: MeetingState2x,
state: MeetingState2x, liveMeeting: LiveMeeting, bus: MessageBus
liveMeeting: LiveMeeting,
bus: MessageBus
): MeetingState2x = { ): MeetingState2x = {
val meetingId = liveMeeting.props.meetingProp.intId val meetingId = liveMeeting.props.meetingProp.intId
@ -25,7 +23,7 @@ trait PresentationConversionCompletedSysPubMsgHdlr {
pres <- pod.getPresentation(msg.body.presentation.id) pres <- pod.getPresentation(msg.body.presentation.id)
} yield { } yield {
val presVO = PresentationPodsApp.translatePresentationToPresentationVO(pres, temporaryPresentationId, val presVO = PresentationPodsApp.translatePresentationToPresentationVO(pres, temporaryPresentationId,
msg.body.presentation.defaultPresentation, msg.body.presentation.filenameConverted) msg.body.presentation.isInitialPresentation, msg.body.presentation.filenameConverted)
PresentationSender.broadcastPresentationConversionCompletedEvtMsg( PresentationSender.broadcastPresentationConversionCompletedEvtMsg(
bus, bus,
meetingId, meetingId,
@ -48,13 +46,11 @@ trait PresentationConversionCompletedSysPubMsgHdlr {
originalDownloadableExtension originalDownloadableExtension
) )
val presWithConvertedName = PresentationInPod(pres.id, pres.name, default = msg.body.presentation.defaultPresentation, val presWithConvertedName = PresentationInPod(pres.id, pres.name, pres.current, pres.pages,
pres.current, pres.pages, pres.downloadable, pres.downloadFileExtension, pres.removable, msg.body.presentation.filenameConverted, pres.downloadable, pres.removable, msg.body.presentation.filenameConverted)
uploadCompleted = true, numPages = pres.numPages, errorDetails = Map.empty)
var pods = state.presentationPodManager.addPod(pod) var pods = state.presentationPodManager.addPod(pod)
pods = pods.addPresentationToPod(pod.id, presWithConvertedName) pods = pods.addPresentationToPod(pod.id, presWithConvertedName)
PresPresentationDAO.updatePages(presWithConvertedName)
state.update(pods) state.update(pods)
} }

Some files were not shown because too many files have changed in this diff Show More