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
402 changed files with 38982 additions and 26488 deletions

View File

@ -13,7 +13,7 @@ This issue tracker is only for bbb development or docs related issues.-->
**Link to the portion of the docs that is out of date** **Link to the portion of the docs that is out of date**
If applicable, link to the section of the docs that is out of date. If applicable, link to the section of the docs that is out of date.
**Describe what you belive the correct version should be** **Describe what you believe the correct version should be**
**Screenshots** **Screenshots**
If applicable, add screenshots to help explain your concern. If applicable, add screenshots to help explain your concern.

View File

@ -52,7 +52,7 @@ jobs:
- 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-etherpad - package: bbb-etherpad
cache-files-list: bbb-etherpad.placeholder.sh build/packages-template/bbb-etherpad cache-files-list: bbb-etherpad.placeholder.sh
cache-urls-list: https://api.github.com/repos/mconf/ep_pad_ttl/commits https://api.github.com/repos/alangecker/bbb-etherpad-plugin/commits https://api.github.com/repos/mconf/ep_redis_publisher/commits https://api.github.com/repos/alangecker/bbb-etherpad-skin/commits 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
- package: bbb-web - package: bbb-web
cache-files-list: bigbluebutton-web bbb-common-message bbb-common-web cache-files-list: bigbluebutton-web bbb-common-message bbb-common-web
@ -63,11 +63,11 @@ jobs:
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
cache-files-list: freeswitch.placeholder.sh build/packages-template/bbb-freeswitch-core build/packages-template/bbb-freeswitch-sounds cache-files-list: freeswitch.placeholder.sh
cache-urls-list: http://bigbluebutton.org/downloads/sounds.tar.gz cache-urls-list: http://bigbluebutton.org/downloads/sounds.tar.gz
- package: bbb-webrtc - package: bbb-webrtc
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 build/packages-template/bbb-webrtc-sfu build/packages-template/bbb-webrtc-recorder 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 build-list: bbb-mkclean bbb-pads bbb-libreoffice-docker bbb-transcription-controller bigbluebutton
steps: steps:
@ -76,7 +76,9 @@ jobs:
uses: ./.github/actions/merge-branches uses: ./.github/actions/merge-branches
- name: Set cache-key vars - name: Set cache-key vars
run: | run: |
echo "CACHE_KEY_FILES=$(echo '${{ matrix.cache-files-list }} .gitlab-ci.yml build/deb-helper.sh' | xargs -n1 git log -1 --format=%h -- | tr '\n' '-' | sed 's/-$//')" >> $GITHUB_ENV BUILD_DIRS="$(echo '${{ matrix.build-list || matrix.package }}' | sed 's/[^ ]\+/build\/packages-template\/&/g')"
echo "Including build dirs: $BUILD_DIRS"
echo "CACHE_KEY_FILES=$(echo '${{ matrix.cache-files-list }} '$BUILD_DIRS' .gitlab-ci.yml build/deb-helper.sh' | xargs -n1 git log -1 --format=%h -- | tr '\n' '-' | sed 's/-$//')" >> $GITHUB_ENV
echo "CACHE_KEY_URLS=$(echo '${{ matrix.cache-urls-list }}' | xargs -r -n 1 curl -Is | grep -i 'Last-Modified' | md5sum | cut -c1-10)" >> $GITHUB_ENV echo "CACHE_KEY_URLS=$(echo '${{ matrix.cache-urls-list }}' | xargs -r -n 1 curl -Is | grep -i 'Last-Modified' | md5sum | cut -c1-10)" >> $GITHUB_ENV
cat bigbluebutton-config/bigbluebutton-release >> $GITHUB_ENV cat bigbluebutton-config/bigbluebutton-release >> $GITHUB_ENV
echo "FORCE_GIT_REV=0" >> $GITHUB_ENV #used by setup.sh echo "FORCE_GIT_REV=0" >> $GITHUB_ENV #used by setup.sh

View File

@ -75,5 +75,6 @@ daemonUser in Linux := user
daemonGroup in Linux := group daemonGroup in Linux := group
javaOptions in Universal ++= Seq("-J-Xms130m", "-J-Xmx256m", "-Dconfig.file=/etc/bigbluebutton/bbb-apps-akka.conf", "-Dlogback.configurationFile=conf/logback.xml") javaOptions in Universal ++= Seq("-J-Xms130m", "-J-Xmx256m", "-Dconfig.file=/etc/bigbluebutton/bbb-apps-akka.conf", "-Dlogback.configurationFile=conf/logback.xml")
javaOptions in reStart ++= Seq("-Dconfig.file=/etc/bigbluebutton/bbb-apps-akka.conf", "-Dlogback.configurationFile=conf/logback.xml")
debianPackageDependencies in Debian ++= Seq("java17-runtime-headless", "bash") debianPackageDependencies in Debian ++= Seq("java17-runtime-headless", "bash")

View File

@ -17,7 +17,7 @@ object Dependencies {
val akkaHttpVersion = "10.2.7" 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.11" val logback = "1.2.13"
val quicklens = "1.7.5" val quicklens = "1.7.5"
val spray = "1.3.6" val spray = "1.3.6"

View File

@ -1,9 +1,10 @@
package org.bigbluebutton package org.bigbluebutton
import org.bigbluebutton.common2.msgs.{ BbbCommonEnvCoreMsg, BbbCoreEnvelope, BbbCoreHeaderWithMeetingId, MessageTypes, MuteUserInVoiceConfSysMsg, MuteUserInVoiceConfSysMsgBody, 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 }
import org.bigbluebutton.core.apps.webcam.CameraHdlrHelpers import org.bigbluebutton.core.apps.webcam.CameraHdlrHelpers
import org.bigbluebutton.core.apps.voice.VoiceApp
import org.bigbluebutton.core.models.{ import org.bigbluebutton.core.models.{
Roles, Roles,
Users2x, Users2x,
@ -16,19 +17,19 @@ import org.bigbluebutton.core.models.{
object LockSettingsUtil { object LockSettingsUtil {
private def muteUserInVoiceConf(liveMeeting: LiveMeeting, outGW: OutMsgRouter, vu: VoiceUserState, mute: Boolean): Unit = { private def muteUserInVoiceConf(
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, vu.intId) liveMeeting: LiveMeeting,
val envelope = BbbCoreEnvelope(MuteUserInVoiceConfSysMsg.NAME, routing) outGW: OutMsgRouter,
val header = BbbCoreHeaderWithMeetingId(MuteUserInVoiceConfSysMsg.NAME, liveMeeting.props.meetingProp.intId) vu: VoiceUserState, mute: Boolean
)(implicit context: akka.actor.ActorContext): Unit = {
val body = MuteUserInVoiceConfSysMsgBody(liveMeeting.props.voiceProp.voiceConf, vu.voiceUserId, mute) VoiceApp.muteUserInVoiceConf(liveMeeting, outGW, vu.intId, mute)
val event = MuteUserInVoiceConfSysMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
outGW.send(msgEvent)
} }
private def applyMutingOfUsers(disableMic: Boolean, liveMeeting: LiveMeeting, outGW: OutMsgRouter): Unit = { private def applyMutingOfUsers(
disableMic: Boolean,
liveMeeting: LiveMeeting,
outGW: OutMsgRouter
)(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) {
@ -44,12 +45,20 @@ object LockSettingsUtil {
} }
} }
def enforceLockSettingsForAllVoiceUsers(liveMeeting: LiveMeeting, outGW: OutMsgRouter): Unit = { def enforceLockSettingsForAllVoiceUsers(
liveMeeting: LiveMeeting,
outGW: OutMsgRouter
)(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)
} }
def enforceLockSettingsForVoiceUser(voiceUser: VoiceUserState, liveMeeting: LiveMeeting, outGW: OutMsgRouter): Unit = { def enforceLockSettingsForVoiceUser(
voiceUser: VoiceUserState,
liveMeeting: LiveMeeting,
outGW: OutMsgRouter
)(implicit context: akka.actor.ActorContext): Unit = {
val permissions = MeetingStatus2x.getPermissions(liveMeeting.status) val permissions = MeetingStatus2x.getPermissions(liveMeeting.status)
if (permissions.disableMic) { if (permissions.disableMic) {
Users2x.findWithIntId(liveMeeting.users2x, voiceUser.intId).foreach { user => Users2x.findWithIntId(liveMeeting.users2x, voiceUser.intId).foreach { user =>
@ -65,7 +74,11 @@ object LockSettingsUtil {
} }
} }
private def enforceListenOnlyUserIsMuted(intUserId: String, liveMeeting: LiveMeeting, outGW: OutMsgRouter): Unit = { private def enforceListenOnlyUserIsMuted(
intUserId: String,
liveMeeting: LiveMeeting,
outGW: OutMsgRouter
)(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

@ -10,6 +10,7 @@ trait SystemConfiguration {
lazy val bbbWebPort = Try(config.getInt("services.bbbWebPort")).getOrElse(8888) lazy val bbbWebPort = Try(config.getInt("services.bbbWebPort")).getOrElse(8888)
lazy val bbbWebAPI = Try(config.getString("services.bbbWebAPI")).getOrElse("localhost") lazy val bbbWebAPI = Try(config.getString("services.bbbWebAPI")).getOrElse("localhost")
lazy val bbbWebSharedSecret = Try(config.getString("services.sharedSecret")).getOrElse("changeme") lazy val bbbWebSharedSecret = Try(config.getString("services.sharedSecret")).getOrElse("changeme")
lazy val checkSumAlgorithmForBreakouts = Try(config.getString("services.checkSumAlgorithmForBreakouts")).getOrElse("sha256")
lazy val bbbWebModeratorPassword = Try(config.getString("services.moderatorPassword")).getOrElse("changeme") lazy val bbbWebModeratorPassword = Try(config.getString("services.moderatorPassword")).getOrElse("changeme")
lazy val bbbWebViewerPassword = Try(config.getString("services.viewerPassword")).getOrElse("changeme") lazy val bbbWebViewerPassword = Try(config.getString("services.viewerPassword")).getOrElse("changeme")
lazy val keysExpiresInSec = Try(config.getInt("redis.keyExpiry")).getOrElse(14 * 86400) // 14 days lazy val keysExpiresInSec = Try(config.getInt("redis.keyExpiry")).getOrElse(14 * 86400) // 14 days
@ -42,6 +43,7 @@ trait SystemConfiguration {
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 recordingChapterBreakLengthInMinutes = Try(config.getInt("recording.chapterBreakLengthInMinutes")).getOrElse(0) lazy val recordingChapterBreakLengthInMinutes = Try(config.getInt("recording.chapterBreakLengthInMinutes")).getOrElse(0)

View File

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

View File

@ -4,6 +4,7 @@ import akka.actor.ActorContext
class AudioCaptionsApp2x(implicit val context: ActorContext) class AudioCaptionsApp2x(implicit val context: ActorContext)
extends UpdateTranscriptPubMsgHdlr extends UpdateTranscriptPubMsgHdlr
with TranscriptionProviderErrorMsgHdlr
with AudioFloorChangedVoiceConfEvtMsgHdlr { with AudioFloorChangedVoiceConfEvtMsgHdlr {
} }

View File

@ -0,0 +1,27 @@
package org.bigbluebutton.core.apps.audiocaptions
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.bus.MessageBus
import org.bigbluebutton.core.models.AudioCaptions
import org.bigbluebutton.core.running.LiveMeeting
trait TranscriptionProviderErrorMsgHdlr {
this: AudioCaptionsApp2x =>
def handleTranscriptionProviderErrorMsg(msg: TranscriptionProviderErrorMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
val meetingId = liveMeeting.props.meetingProp.intId
def broadcastEvent(userId: String, errorCode: String, errorMessage: String): Unit = {
val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, meetingId, "nodeJSapp")
val envelope = BbbCoreEnvelope(TranscriptionProviderErrorEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(TranscriptionProviderErrorEvtMsg.NAME, meetingId, userId)
val body = TranscriptionProviderErrorEvtMsgBody(errorCode, errorMessage)
val event = TranscriptionProviderErrorEvtMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
bus.outGW.send(msgEvent)
}
broadcastEvent(msg.header.userId, msg.body.errorCode, msg.body.errorMessage)
}
}

View File

@ -4,6 +4,7 @@ import org.bigbluebutton.core.running.MeetingActor
import java.net.URLEncoder import java.net.URLEncoder
import scala.collection.SortedSet import scala.collection.SortedSet
import org.apache.commons.codec.digest.DigestUtils import org.apache.commons.codec.digest.DigestUtils
import org.bigbluebutton.SystemConfiguration
trait BreakoutApp2x extends BreakoutRoomCreatedMsgHdlr trait BreakoutApp2x extends BreakoutRoomCreatedMsgHdlr
with BreakoutRoomsListMsgHdlr with BreakoutRoomsListMsgHdlr
@ -26,7 +27,7 @@ trait BreakoutApp2x extends BreakoutRoomCreatedMsgHdlr
} }
object BreakoutRoomsUtil { object BreakoutRoomsUtil extends SystemConfiguration {
def createMeetingIds(id: String, index: Int): (String, String) = { def createMeetingIds(id: String, index: Int): (String, String) = {
val timeStamp = System.currentTimeMillis() val timeStamp = System.currentTimeMillis()
val externalHash = DigestUtils.sha1Hex(id.concat("-").concat(timeStamp.toString()).concat("-").concat(index.toString())) val externalHash = DigestUtils.sha1Hex(id.concat("-").concat(timeStamp.toString()).concat("-").concat(index.toString()))
@ -48,7 +49,13 @@ object BreakoutRoomsUtil {
//checksum() -- Return a checksum based on SHA-1 digest //checksum() -- Return a checksum based on SHA-1 digest
// //
def checksum(s: String): String = { def checksum(s: String): String = {
DigestUtils.sha256Hex(s); checkSumAlgorithmForBreakouts match {
case "sha1" => DigestUtils.sha1Hex(s);
case "sha256" => DigestUtils.sha256Hex(s);
case "sha384" => DigestUtils.sha384Hex(s);
case "sha512" => DigestUtils.sha512Hex(s);
case _ => DigestUtils.sha256Hex(s); // default
}
} }
def calculateChecksum(apiCall: String, baseString: String, sharedSecret: String): String = { def calculateChecksum(apiCall: String, baseString: String, sharedSecret: String): String = {

View File

@ -40,26 +40,30 @@ trait CreateBreakoutRoomsCmdMsgHdlr extends RightsManagementTrait {
} }
def processRequest(msg: CreateBreakoutRoomsCmdMsg, state: MeetingState2x): MeetingState2x = { def processRequest(msg: CreateBreakoutRoomsCmdMsg, state: MeetingState2x): MeetingState2x = {
val presId = getPresentationId(state) // The current presentation
val presId = getPresentationId(state) val presSlide = getPresentationSlide(state) // The current slide
val presSlide = getPresentationSlide(state)
val parentId = liveMeeting.props.meetingProp.intId val parentId = liveMeeting.props.meetingProp.intId
var rooms = new collection.immutable.HashMap[String, BreakoutRoom2x] var rooms = new collection.immutable.HashMap[String, BreakoutRoom2x]
var i = 0 var i = 0
for (room <- msg.body.rooms) { for (room <- msg.body.rooms) {
val roomPresId = if (room.presId.isEmpty) presId else room.presId;
i += 1 i += 1
val (internalId, externalId) = BreakoutRoomsUtil.createMeetingIds(liveMeeting.props.meetingProp.intId, i) val (internalId, externalId) = BreakoutRoomsUtil.createMeetingIds(liveMeeting.props.meetingProp.intId, i)
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.sourcePresentationFilename)
rooms = rooms + (breakout.id -> breakout) rooms = rooms + (breakout.id -> breakout)
} }
for (breakout <- rooms.values.toVector) { for (breakout <- rooms.values.toVector) {
val roomSlides = if (breakout.allPages) -1 else presSlide;
val roomDetail = new BreakoutRoomDetail( val roomDetail = new BreakoutRoomDetail(
breakout.id, breakout.name, breakout.id, breakout.name,
liveMeeting.props.meetingProp.intId, liveMeeting.props.meetingProp.intId,
@ -72,7 +76,10 @@ trait CreateBreakoutRoomsCmdMsgHdlr extends RightsManagementTrait {
msg.body.durationInMinutes * 60, msg.body.durationInMinutes * 60,
liveMeeting.props.password.moderatorPass, liveMeeting.props.password.moderatorPass,
liveMeeting.props.password.viewerPass, liveMeeting.props.password.viewerPass,
presId, presSlide, msg.body.record, breakout.presId,
roomSlides,
breakout.sourcePresentationFilename,
msg.body.record,
liveMeeting.props.breakoutProps.privateChatEnabled, liveMeeting.props.breakoutProps.privateChatEnabled,
breakout.captureNotes, breakout.captureNotes,
breakout.captureSlides, breakout.captureSlides,

View File

@ -5,6 +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.core2.message.senders.{ MsgBuilder }
trait BroadcastLayoutMsgHdlr extends RightsManagementTrait { trait BroadcastLayoutMsgHdlr extends RightsManagementTrait {
this: LayoutApp2x => this: LayoutApp2x =>
@ -58,5 +59,18 @@ trait BroadcastLayoutMsgHdlr extends RightsManagementTrait {
val msgEvent = BbbCommonEnvCoreMsg(envelope, event) val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
outGW.send(msgEvent) outGW.send(msgEvent)
if (body.pushLayout) {
val notifyEvent = MsgBuilder.buildNotifyUserInMeetingEvtMsg(
fromUserId,
liveMeeting.props.meetingProp.intId,
"info",
"user",
"app.layoutUpdate.label",
"Notification to when the presenter changes size of cams",
Vector()
)
outGW.send(notifyEvent)
}
} }
} }

View File

@ -21,7 +21,7 @@ trait PadUpdatePubMsgHdlr {
bus.outGW.send(msgEvent) bus.outGW.send(msgEvent)
} }
if (Pads.hasAccess(liveMeeting, msg.body.externalId, msg.header.userId)) { if (Pads.hasAccess(liveMeeting, msg.body.externalId, msg.header.userId) || msg.body.transcript == true) {
Pads.getGroup(liveMeeting.pads, msg.body.externalId) match { Pads.getGroup(liveMeeting.pads, msg.body.externalId) match {
case Some(group) => broadcastEvent(group.groupId, msg.body.externalId, msg.body.text) case Some(group) => broadcastEvent(group.groupId, msg.body.externalId, msg.body.text)
case _ => case _ =>

View File

@ -143,7 +143,7 @@ trait MakePresentationDownloadReqMsgHdlr extends RightsManagementTrait {
&& m.body.fileStateType == "Converted") { && m.body.fileStateType == "Converted") {
val reason = "Converted presentation download disabled for this meeting. (PDF format)" val reason = "Converted presentation download disabled for this meeting. (PDF format)"
PermissionCheck.ejectUserForFailedPermission(meetingId, userId, reason, bus.outGW, liveMeeting) PermissionCheck.ejectUserForFailedPermission(meetingId, userId, reason, bus.outGW, liveMeeting)
} else if (permissionFailed(PermissionCheck.MOD_LEVEL, PermissionCheck.VIEWER_LEVEL, liveMeeting.users2x, userId)) { } else if (permissionFailed(PermissionCheck.GUEST_LEVEL, PermissionCheck.PRESENTER_LEVEL, liveMeeting.users2x, userId)) {
val reason = "No permission to download presentation." val reason = "No permission to download presentation."
PermissionCheck.ejectUserForFailedPermission(meetingId, userId, reason, bus.outGW, liveMeeting) PermissionCheck.ejectUserForFailedPermission(meetingId, userId, reason, bus.outGW, liveMeeting)
} else if (currentPres.isEmpty) { } else if (currentPres.isEmpty) {

View File

@ -29,7 +29,10 @@ trait ChangeUserEmojiCmdMsgHdlr extends RightsManagementTrait {
msg.header.userId msg.header.userId
) )
val initialEmojiState = Users2x.findWithIntId(liveMeeting.users2x, msg.body.userId).get.emoji for {
user <- Users2x.findWithIntId(liveMeeting.users2x, msg.body.userId)
} yield {
val initialEmojiState = user.emoji
val nextEmojiState = msg.body.emoji val nextEmojiState = msg.body.emoji
if (isUserSettingOwnEmoji if (isUserSettingOwnEmoji
@ -57,5 +60,6 @@ trait ChangeUserEmojiCmdMsgHdlr extends RightsManagementTrait {
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, outGW, liveMeeting) PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, outGW, liveMeeting)
} }
} }
}
} }

View File

@ -30,7 +30,7 @@ trait ChangeUserRoleCmdMsgHdlr extends RightsManagementTrait {
} yield { } yield {
RegisteredUsers.updateUserRole(liveMeeting.registeredUsers, u, userRole) RegisteredUsers.updateUserRole(liveMeeting.registeredUsers, u, userRole)
} }
val promoteGuest = !liveMeeting.props.usersProp.authenticatedGuest val promoteGuest = !liveMeeting.props.usersProp.authenticatedGuest || liveMeeting.props.usersProp.allowPromoteGuestToModerator
if (msg.body.role == Roles.MODERATOR_ROLE && (!uvo.guest || promoteGuest)) { if (msg.body.role == Roles.MODERATOR_ROLE && (!uvo.guest || promoteGuest)) {
// Promote non-guest users. // Promote non-guest users.
val notifyEvent = MsgBuilder.buildNotifyUserInMeetingEvtMsg( val notifyEvent = MsgBuilder.buildNotifyUserInMeetingEvtMsg(

View File

@ -0,0 +1,36 @@
package org.bigbluebutton.core.apps.users
import org.bigbluebutton.LockSettingsUtil
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.models.{ Users2x, VoiceUsers }
import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter }
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
trait LockUserChatInMeetingCmdMsgHdlr extends RightsManagementTrait {
this: MeetingActor =>
val outGW: OutMsgRouter
def handleLockUserChatInMeetingCmdMsg(msg: LockUserChatInMeetingCmdMsg) {
def build(meetingId: String, userId: String, isLocked: Boolean): BbbCommonEnvCoreMsg = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, userId)
val envelope = BbbCoreEnvelope(LockUserChatInMeetingEvtMsg.NAME, routing)
val body = LockUserChatInMeetingEvtMsgBody(userId, isLocked)
val header = BbbClientMsgHeader(LockUserChatInMeetingEvtMsg.NAME, meetingId, userId)
val event = LockUserChatInMeetingEvtMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
if (permissionFailed(PermissionCheck.MOD_LEVEL, PermissionCheck.VIEWER_LEVEL, liveMeeting.users2x, msg.header.userId)) {
val meetingId = liveMeeting.props.meetingProp.intId
val reason = "No permission to lock user chat in meeting."
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, outGW, liveMeeting)
} else {
log.info("Lock user chat. meetingId=" + props.meetingProp.intId + " userId=" + msg.body.userId + " isLocked=" + msg.body.isLocked)
val event = build(props.meetingProp.intId, msg.body.userId, msg.body.isLocked)
outGW.send(event)
}
}
}

View File

@ -2,6 +2,7 @@ package org.bigbluebutton.core.apps.users
import org.bigbluebutton.common2.msgs.MuteUserCmdMsg import org.bigbluebutton.common2.msgs.MuteUserCmdMsg
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait } import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
import org.bigbluebutton.core.apps.voice.VoiceApp
import org.bigbluebutton.core.models.{ Roles, Users2x, VoiceUsers } import org.bigbluebutton.core.models.{ Roles, Users2x, VoiceUsers }
import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter } import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter }
import org.bigbluebutton.core2.MeetingStatus2x import org.bigbluebutton.core2.MeetingStatus2x
@ -51,13 +52,12 @@ trait MuteUserCmdMsgHdlr extends RightsManagementTrait {
} else { } else {
if (u.muted != msg.body.mute) { if (u.muted != msg.body.mute) {
log.info("Send mute user request. meetingId=" + meetingId + " userId=" + u.intId + " user=" + u) log.info("Send mute user request. meetingId=" + meetingId + " userId=" + u.intId + " user=" + u)
val event = MsgBuilder.buildMuteUserInVoiceConfSysMsg( VoiceApp.muteUserInVoiceConf(
meetingId, liveMeeting,
voiceConf, outGW,
u.voiceUserId, u.intId,
msg.body.mute msg.body.mute
) )
outGW.send(event)
} }
} }
} }

View File

@ -57,12 +57,22 @@ trait RegisterUserReqMsgHdlr {
val regUser = RegisteredUsers.create(msg.body.intUserId, msg.body.extUserId, val regUser = RegisteredUsers.create(msg.body.intUserId, msg.body.extUserId,
msg.body.name, msg.body.role, msg.body.authToken, msg.body.name, msg.body.role, msg.body.authToken,
msg.body.avatarURL, ColorPicker.nextColor(liveMeeting.props.meetingProp.intId), msg.body.guest, msg.body.authed, guestStatus, msg.body.excludeFromDashboard, false) msg.body.avatarURL,
msg.body.webcamBackgroundURL,
ColorPicker.nextColor(liveMeeting.props.meetingProp.intId), msg.body.guest, msg.body.authed, guestStatus, msg.body.excludeFromDashboard, false)
checkUserConcurrentAccesses(regUser) checkUserConcurrentAccesses(regUser)
RegisteredUsers.add(liveMeeting.registeredUsers, regUser) RegisteredUsers.add(liveMeeting.registeredUsers, regUser)
val userCustomData: Map[String, String] = msg.body.userCustomData.map {
case (k, v) => k -> v.toString
}
if (userCustomData.nonEmpty) {
RegisteredUsers.updateUserCustomData(liveMeeting.registeredUsers, regUser, userCustomData)
}
log.info("Register user success. meetingId=" + liveMeeting.props.meetingProp.intId log.info("Register user success. meetingId=" + liveMeeting.props.meetingProp.intId
+ " userId=" + msg.body.extUserId + " user=" + regUser) + " userId=" + msg.body.extUserId + " user=" + regUser)
@ -90,7 +100,7 @@ trait RegisterUserReqMsgHdlr {
val g = GuestApprovedVO(regUser.id, GuestStatus.ALLOW) val g = GuestApprovedVO(regUser.id, GuestStatus.ALLOW)
UsersApp.approveOrRejectGuest(liveMeeting, outGW, g, SystemUser.ID) UsersApp.approveOrRejectGuest(liveMeeting, outGW, g, SystemUser.ID)
case GuestStatus.WAIT => case GuestStatus.WAIT =>
val guest = GuestWaiting(regUser.id, regUser.name, regUser.role, regUser.guest, regUser.avatarURL, regUser.color, regUser.authed, regUser.registeredOn) val guest = GuestWaiting(regUser.id, regUser.name, regUser.role, regUser.guest, regUser.avatarURL, regUser.webcamBackgroundURL, regUser.color, regUser.authed, regUser.registeredOn)
addGuestToWaitingForApproval(guest, liveMeeting.guestsWaiting) addGuestToWaitingForApproval(guest, liveMeeting.guestsWaiting)
notifyModeratorsOfGuestWaiting(Vector(guest), liveMeeting.users2x, liveMeeting.props.meetingProp.intId) notifyModeratorsOfGuestWaiting(Vector(guest), liveMeeting.users2x, liveMeeting.props.meetingProp.intId)
val notifyEvent = MsgBuilder.buildNotifyRoleInMeetingEvtMsg( val notifyEvent = MsgBuilder.buildNotifyRoleInMeetingEvtMsg(

View File

@ -0,0 +1,41 @@
package org.bigbluebutton.core.apps.users
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.models.{ UserState, Users2x }
import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter }
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
import org.bigbluebutton.core.domain.MeetingState2x
trait SetUserSpeechOptionsMsgHdlr extends RightsManagementTrait {
this: UsersApp =>
val liveMeeting: LiveMeeting
val outGW: OutMsgRouter
def handleSetUserSpeechOptionsReqMsg(msg: SetUserSpeechOptionsReqMsg): Unit = {
log.info("handleSetUserSpeechOptionsReqMsg: partialUtterances={} minUtteranceLength={} userId={}", msg.body.partialUtterances, msg.body.minUtteranceLength, msg.header.userId)
def broadcastUserSpeechOptionsChanged(user: UserState, partialUtterances: Boolean, minUtteranceLength: Int): Unit = {
val routingChange = Routing.addMsgToClientRouting(
MessageTypes.BROADCAST_TO_MEETING,
liveMeeting.props.meetingProp.intId, user.intId
)
val envelopeChange = BbbCoreEnvelope(UserSpeechOptionsChangedEvtMsg.NAME, routingChange)
val headerChange = BbbClientMsgHeader(UserSpeechOptionsChangedEvtMsg.NAME, liveMeeting.props.meetingProp.intId, user.intId)
val bodyChange = UserSpeechOptionsChangedEvtMsgBody(partialUtterances, minUtteranceLength)
val eventChange = UserSpeechOptionsChangedEvtMsg(headerChange, bodyChange)
val msgEventChange = BbbCommonEnvCoreMsg(envelopeChange, eventChange)
outGW.send(msgEventChange)
}
for {
user <- Users2x.findWithIntId(liveMeeting.users2x, msg.header.userId)
} yield {
var changeLocale: Option[UserState] = None;
//changeLocale = Users2x.setUserSpeechLocale(liveMeeting.users2x, msg.header.userId, msg.body.locale)
broadcastUserSpeechOptionsChanged(user, msg.body.partialUtterances, msg.body.minUtteranceLength)
}
}
}

View File

@ -150,6 +150,7 @@ class UsersApp(
with RegisterUserReqMsgHdlr with RegisterUserReqMsgHdlr
with ChangeUserRoleCmdMsgHdlr with ChangeUserRoleCmdMsgHdlr
with SetUserSpeechLocaleMsgHdlr with SetUserSpeechLocaleMsgHdlr
with SetUserSpeechOptionsMsgHdlr
with SyncGetUsersMeetingRespMsgHdlr with SyncGetUsersMeetingRespMsgHdlr
with LogoutAndEndMeetingCmdMsgHdlr with LogoutAndEndMeetingCmdMsgHdlr
with SetRecordingStatusCmdMsgHdlr with SetRecordingStatusCmdMsgHdlr

View File

@ -5,6 +5,7 @@ import org.bigbluebutton.core.running.MeetingActor
trait UsersApp2x trait UsersApp2x
extends UserLeaveReqMsgHdlr extends UserLeaveReqMsgHdlr
with LockUserInMeetingCmdMsgHdlr with LockUserInMeetingCmdMsgHdlr
with LockUserChatInMeetingCmdMsgHdlr
with LockUsersInMeetingCmdMsgHdlr with LockUsersInMeetingCmdMsgHdlr
with GetLockSettingsReqMsgHdlr with GetLockSettingsReqMsgHdlr
with ChangeUserEmojiCmdMsgHdlr with ChangeUserEmojiCmdMsgHdlr

View File

@ -12,8 +12,20 @@ trait ListenOnlyModeToggledInSfuEvtMsgHdlr {
def handleListenOnlyModeToggledInSfuEvtMsg(msg: ListenOnlyModeToggledInSfuEvtMsg): Unit = { def handleListenOnlyModeToggledInSfuEvtMsg(msg: ListenOnlyModeToggledInSfuEvtMsg): Unit = {
for { for {
vu <- VoiceUsers.findWithIntId(liveMeeting.voiceUsers, msg.body.userId) vu <- VoiceUsers.findWithIntIdAndCallerNum(
liveMeeting.voiceUsers,
msg.body.userId,
msg.body.callerNum
)
} yield { } yield {
// Do not execute if the command is asking for the channel to be HELD
// and the channel is already HELD. 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.
// The unhold (uuid_hold off) command is not affected by this, but we don't
// want to send it if the channel is already unheld.
if ((msg.body.enabled && !vu.hold) || !msg.body.enabled) {
VoiceApp.holdChannelInVoiceConf( VoiceApp.holdChannelInVoiceConf(
liveMeeting, liveMeeting,
outGW, outGW,
@ -21,5 +33,16 @@ trait ListenOnlyModeToggledInSfuEvtMsgHdlr {
msg.body.enabled msg.body.enabled
) )
} }
// If the channel is already in the desired state, just make sure
// any pending mute or unmute commands are sent.
VoiceApp.handleChannelHoldChanged(
liveMeeting,
outGW,
msg.body.userId,
vu.uuid,
msg.body.enabled
)
}
} }
} }

View File

@ -34,8 +34,8 @@ trait UserJoinedVoiceConfEvtMsgHdlr extends SystemConfiguration {
def registerUserInRegisteredUsers() = { def registerUserInRegisteredUsers() = {
val regUser = RegisteredUsers.create(msg.body.intId, msg.body.voiceUserId, val regUser = RegisteredUsers.create(msg.body.intId, msg.body.voiceUserId,
msg.body.callerIdName, Roles.VIEWER_ROLE, "", userColor, msg.body.callerIdName, Roles.VIEWER_ROLE, msg.body.intId, "", "",
"", true, true, GuestStatus.WAIT, true, false) userColor, true, true, GuestStatus.WAIT, true, false)
RegisteredUsers.add(liveMeeting.registeredUsers, regUser) RegisteredUsers.add(liveMeeting.registeredUsers, regUser)
} }
@ -57,6 +57,7 @@ trait UserJoinedVoiceConfEvtMsgHdlr extends SystemConfiguration {
presenter = false, presenter = false,
locked = MeetingStatus2x.getPermissions(liveMeeting.status).lockOnJoin, locked = MeetingStatus2x.getPermissions(liveMeeting.status).lockOnJoin,
avatar = "", avatar = "",
webcamBackground = "",
color = userColor, color = userColor,
clientType = "", clientType = "",
pickExempted = false, pickExempted = false,
@ -67,7 +68,7 @@ trait UserJoinedVoiceConfEvtMsgHdlr extends SystemConfiguration {
def registerUserAsGuest() = { def registerUserAsGuest() = {
if (GuestsWaiting.findWithIntId(liveMeeting.guestsWaiting, msg.body.intId) == None) { if (GuestsWaiting.findWithIntId(liveMeeting.guestsWaiting, msg.body.intId) == None) {
val guest = GuestWaiting(msg.body.intId, msg.body.callerIdName, Roles.VIEWER_ROLE, true, "", userColor, true, System.currentTimeMillis()) val guest = GuestWaiting(msg.body.intId, msg.body.callerIdName, Roles.VIEWER_ROLE, true, "", "", userColor, true, System.currentTimeMillis())
GuestsWaiting.add(liveMeeting.guestsWaiting, guest) GuestsWaiting.add(liveMeeting.guestsWaiting, guest)
notifyModeratorsOfGuestWaiting(guest, liveMeeting.users2x, liveMeeting.props.meetingProp.intId) notifyModeratorsOfGuestWaiting(guest, liveMeeting.users2x, liveMeeting.props.meetingProp.intId)

View File

@ -6,47 +6,4 @@ trait UserJoinedVoiceConfMessageHdlr {
this: MeetingActor => this: MeetingActor =>
val outGW: OutMsgRouter val outGW: OutMsgRouter
/*
def startRecordingVoiceConference() {
if (Users.numUsersInVoiceConference(liveMeeting.users) == 1 &&
props.recordProp.record &&
!MeetingStatus2x.isVoiceRecording(liveMeeting.status)) {
MeetingStatus2x.startRecordingVoice(liveMeeting.status)
log.info("Send START RECORDING voice conf. meetingId=" + props.meetingProp.intId + " voice conf=" + props.voiceProp.voiceConf)
outGW.send(new StartRecordingVoiceConf(props.meetingProp.intId, props.recordProp.record, props.voiceProp.voiceConf))
}
}
def handleUserJoinedVoiceConfMessage(msg: UserJoinedVoiceConfMessage) = {
log.info("Received user joined voice. meetingId=" + props.meetingProp.intId + " callername=" + msg.callerIdName
+ " userId=" + msg.userId + " extUserId=" + msg.externUserId)
Users.findWithId(msg.userId, liveMeeting.users) match {
case Some(user) => {
// this is used to restore the mute state on reconnect
val previouslyMuted = user.voiceUser.muted
val nu = Users.restoreMuteState(user, liveMeeting.users, msg.voiceUserId, msg.userId, msg.callerIdName,
msg.callerIdNum, msg.muted, msg.talking, msg.avatarURL, msg.listenOnly)
log.info("User joined voice. meetingId=" + props.meetingProp.intId + " userId=" + user.id + " user=" + nu)
outGW.send(new UserJoinedVoice(props.meetingProp.intId, props.recordProp.record, props.voiceProp.voiceConf, nu))
if (MeetingStatus2x.isMeetingMuted(liveMeeting.status) || previouslyMuted) {
outGW.send(new MuteVoiceUser(props.meetingProp.intId, props.recordProp.record,
nu.id, nu.id, props.voiceProp.voiceConf,
nu.voiceUser.userId, true))
}
startRecordingVoiceConference()
}
case None => {
startRecordingVoiceConference()
}
}
}
*/
} }

View File

@ -131,6 +131,7 @@ object VoiceApp extends SystemConfiguration {
liveMeeting, liveMeeting,
outGW, outGW,
mutedUser.intId, mutedUser.intId,
mutedUser.callerNum,
muted, muted,
toggleListenOnlyAfterMuteTimer toggleListenOnlyAfterMuteTimer
) )
@ -148,7 +149,6 @@ object VoiceApp extends SystemConfiguration {
outGW outGW
) )
} }
} }
} }
@ -259,7 +259,7 @@ object VoiceApp extends SystemConfiguration {
callingInto: String, callingInto: String,
hold: Boolean, hold: Boolean,
uuid: String = "unused" uuid: String = "unused"
): Unit = { )(implicit context: akka.actor.ActorContext): Unit = {
def broadcastEvent(voiceUserState: VoiceUserState): Unit = { def broadcastEvent(voiceUserState: VoiceUserState): Unit = {
val routing = Routing.addMsgToClientRouting( val routing = Routing.addMsgToClientRouting(
@ -322,8 +322,28 @@ object VoiceApp extends SystemConfiguration {
hold, hold,
uuid uuid
) )
val prevTransparentLOStatus = VoiceHdlrHelpers.transparentListenOnlyAllowed(
liveMeeting
)
VoiceUsers.add(liveMeeting.voiceUsers, voiceUserState) VoiceUsers.add(liveMeeting.voiceUsers, voiceUserState)
val newTransparentLOStatus = VoiceHdlrHelpers.transparentListenOnlyAllowed(
liveMeeting
)
if (prevTransparentLOStatus != newTransparentLOStatus) {
// If the transparent listen only mode was activated or deactivated
// we need to update the listen only mode for all users in the meeting
// that are not muted.
handleTransparentLOModeChange(
liveMeeting,
outGW,
newTransparentLOStatus
)
}
broadcastEvent(voiceUserState) broadcastEvent(voiceUserState)
if (liveMeeting.props.meetingProp.isBreakout) { if (liveMeeting.props.meetingProp.isBreakout) {
@ -472,27 +492,52 @@ object VoiceApp extends SystemConfiguration {
} }
} }
def handleTransparentLOModeChange(
liveMeeting: LiveMeeting,
outGW: OutMsgRouter,
allowed: Boolean,
)(implicit context: akka.actor.ActorContext): Unit = {
VoiceUsers.findAllMutedVoiceUsers(liveMeeting.voiceUsers) foreach { vu =>
toggleListenOnlyMode(
liveMeeting,
outGW,
vu.intId,
vu.callerNum,
allowed
)
}
}
def toggleListenOnlyMode( def toggleListenOnlyMode(
liveMeeting: LiveMeeting, liveMeeting: LiveMeeting,
outGW: OutMsgRouter, outGW: OutMsgRouter,
userId: String, userId: String,
callerNum: String,
enabled: Boolean, enabled: Boolean,
delay: Int = 0 delay: Int = 0
)(implicit context: ActorContext): Unit = { )(implicit context: ActorContext): Unit = {
implicit def executionContext = context.system.dispatcher implicit def executionContext = context.system.dispatcher
val allowed = VoiceHdlrHelpers.transparentListenOnlyAllowed(liveMeeting)
// Guarantee there are no other tasks for this channel
removeToggleListenOnlyTask(userId)
// If the meeting has not yet hit the minium amount of duplex channels
// for transparent listen only to be enabled, we don't need to do anything
if (!allowed && enabled) {
return
}
def broacastEvent(): Unit = { def broacastEvent(): Unit = {
val event = MsgBuilder.buildToggleListenOnlyModeSysMsg( val event = MsgBuilder.buildToggleListenOnlyModeSysMsg(
liveMeeting.props.meetingProp.intId, liveMeeting.props.meetingProp.intId,
liveMeeting.props.voiceProp.voiceConf, liveMeeting.props.voiceProp.voiceConf,
userId, userId,
callerNum,
enabled enabled
) )
outGW.send(event) outGW.send(event)
} }
// Guarantee there are no other tasks for this channel
removeToggleListenOnlyTask(userId)
if (enabled && delay > 0) { if (enabled && delay > 0) {
// If we are enabling listen only mode, we wait a bit before actually // If we are enabling listen only mode, we wait a bit before actually
// dispatching the command - the idea is that recently muted users // dispatching the command - the idea is that recently muted users
@ -543,13 +588,15 @@ object VoiceApp extends SystemConfiguration {
hold hold
) match { ) match {
case Some(vu) => case Some(vu) =>
// Mute vs hold state mismatch, enforce hold state again. // Mute vs hold state mismatch. Enforce it if the user is unmuted,
// Mute state is the predominant one here. // but hold is active, to avoid the user being unable to talk when
if (vu.muted != hold) { // the channel is active again.
if (!vu.muted && vu.hold) {
toggleListenOnlyMode( toggleListenOnlyMode(
liveMeeting, liveMeeting,
outGW, outGW,
intId, intId,
vu.callerNum,
vu.muted vu.muted
) )
} }
@ -566,4 +613,48 @@ object VoiceApp extends SystemConfiguration {
case _ => case _ =>
} }
} }
def muteUserInVoiceConf(
liveMeeting: LiveMeeting,
outGW: OutMsgRouter,
userId: String,
muted: Boolean
)(implicit context: akka.actor.ActorContext): Unit = {
for {
u <- VoiceUsers.findWithIntId(
liveMeeting.voiceUsers,
userId
)
} yield {
if (u.muted != muted) {
val muteEvent = MsgBuilder.buildMuteUserInVoiceConfSysMsg(
liveMeeting.props.meetingProp.intId,
liveMeeting.props.voiceProp.voiceConf,
u.voiceUserId,
muted
)
// If we're unmuting, trigger a channel unhold -> toggle listen only
// mode -> unmute
if (!muted) {
holdChannelInVoiceConf(
liveMeeting,
outGW,
u.uuid,
muted
)
toggleListenOnlyMode(
liveMeeting,
outGW,
u.intId,
u.callerNum,
muted,
0
)
}
outGW.send(muteEvent)
}
}
}
} }

View File

@ -50,4 +50,14 @@ object VoiceHdlrHelpers extends SystemConfiguration {
case _ => false case _ => false
} }
} }
def transparentListenOnlyAllowed(liveMeeting: LiveMeeting): Boolean = {
// Transparent listen only meeting-wide activation threshold.
// Threshold is the number of muted duplex audio channels in a meeting.
// 0 means no threshold, all users are subject to it
val mutedDuplexChannels = VoiceUsers.findAllMutedVoiceUsers(liveMeeting.voiceUsers).length
val threshold = transparentListenOnlyThreshold
(threshold == 0) || (mutedDuplexChannels >= threshold)
}
} }

View File

@ -52,11 +52,11 @@ trait SendWhiteboardAnnotationsPubMsgHdlr extends RightsManagementTrait {
) )
if (isUserOneOfPermited || isUserAmongPresenters) { if (isUserOneOfPermited || isUserAmongPresenters) {
println("============= Printing Sanitized annotations ============") // println("============= Printing Sanitized annotations ============")
for (annotation <- msg.body.annotations) { // for (annotation <- msg.body.annotations) {
printAnnotationInfo(annotation) // printAnnotationInfo(annotation)
} // }
println("============= Printed Sanitized annotations ============") // println("============= Printed Sanitized annotations ============")
val annotations = sendWhiteboardAnnotations(msg.body.whiteboardId, msg.header.userId, msg.body.annotations, liveMeeting, isUserAmongPresenters, isUserModerator) val annotations = sendWhiteboardAnnotations(msg.body.whiteboardId, msg.header.userId, msg.body.annotations, liveMeeting, isUserAmongPresenters, isUserModerator)
broadcastEvent(msg, msg.body.whiteboardId, annotations, msg.body.html5InstanceId) broadcastEvent(msg, msg.body.whiteboardId, annotations, msg.body.html5InstanceId)
} else { } else {

View File

@ -19,6 +19,9 @@ case class BreakoutRoom2x(
captureSlides: Boolean, captureSlides: Boolean,
captureNotesFilename: String, captureNotesFilename: String,
captureSlidesFilename: String, captureSlidesFilename: String,
allPages: Boolean,
presId: String,
sourcePresentationFilename: String,
) { ) {
} }

View File

@ -7,12 +7,10 @@ import org.bigbluebutton.SystemConfiguration
object AudioCaptions extends SystemConfiguration { object AudioCaptions extends SystemConfiguration {
def setFloor(audioCaptions: AudioCaptions, userId: String) = audioCaptions.floor = userId def setFloor(audioCaptions: AudioCaptions, userId: String) = audioCaptions.floor = userId
def isFloor(audioCaptions: AudioCaptions, userId: String) = audioCaptions.floor == userId def isFloor(audioCaptions: AudioCaptions, userId: String) = true
def parseTranscript(transcript: String): String = { def parseTranscript(transcript: String): String = {
val words = transcript.split("\\s+") // Split on whitespaces transcript
val lines = words.grouped(transcriptWords).toArray // Group each X words into lines
lines.takeRight(transcriptLines).map(l => l.mkString(" ")).mkString("\n") // Join the last X lines
} }
/* /*

View File

@ -68,7 +68,7 @@ class GuestsWaiting {
} }
} }
case class GuestWaiting(intId: String, name: String, role: String, guest: Boolean, avatar: String, color: String, authenticated: Boolean, registeredOn: Long) case class GuestWaiting(intId: String, name: String, role: String, guest: Boolean, avatar: String, webcamBackground: String, color: String, authenticated: Boolean, registeredOn: Long)
case class GuestPolicy(policy: String, setBy: String) case class GuestPolicy(policy: String, setBy: String)
object GuestPolicyType { object GuestPolicyType {

View File

@ -5,7 +5,7 @@ import org.bigbluebutton.core.domain.BreakoutRoom2x
object RegisteredUsers { object RegisteredUsers {
def create(userId: String, extId: String, name: String, roles: String, def create(userId: String, extId: String, name: String, roles: String,
token: String, avatar: String, color: String, guest: Boolean, authenticated: Boolean, token: String, avatar: String, webcamBackground: String, color: String, guest: Boolean, authenticated: Boolean,
guestStatus: String, excludeFromDashboard: Boolean, loggedOut: Boolean): RegisteredUser = { guestStatus: String, excludeFromDashboard: Boolean, loggedOut: Boolean): RegisteredUser = {
new RegisteredUser( new RegisteredUser(
userId, userId,
@ -14,6 +14,7 @@ object RegisteredUsers {
roles, roles,
token, token,
avatar, avatar,
webcamBackground,
color, color,
guest, guest,
authenticated, authenticated,
@ -164,6 +165,12 @@ object RegisteredUsers {
u u
} }
def updateUserCustomData(users: RegisteredUsers, user: RegisteredUser, userCustomData: Map[String, String]): RegisteredUser = {
val u = user.modify(_.userCustomData).setTo(userCustomData)
users.save(u)
u
}
} }
class RegisteredUsers { class RegisteredUsers {
@ -192,6 +199,7 @@ case class RegisteredUser(
role: String, role: String,
authToken: String, authToken: String,
avatarURL: String, avatarURL: String,
webcamBackgroundURL: String,
color: String, color: String,
guest: Boolean, guest: Boolean,
authed: Boolean, authed: Boolean,
@ -202,6 +210,7 @@ case class RegisteredUser(
joined: Boolean, joined: Boolean,
banned: Boolean, banned: Boolean,
loggedOut: Boolean, loggedOut: Boolean,
lastBreakoutRoom: BreakoutRoom2x = null lastBreakoutRoom: BreakoutRoom2x = null,
userCustomData: Map[String, String] = Map.empty
) )

View File

@ -413,6 +413,7 @@ case class UserState(
locked: Boolean, locked: Boolean,
presenter: Boolean, presenter: Boolean,
avatar: String, avatar: String,
webcamBackground: String,
color: String, color: String,
roleChangedOn: Long = System.currentTimeMillis(), roleChangedOn: Long = System.currentTimeMillis(),
lastActivityTime: Long = System.currentTimeMillis(), lastActivityTime: Long = System.currentTimeMillis(),
@ -420,7 +421,8 @@ case class UserState(
clientType: String, clientType: String,
pickExempted: Boolean, pickExempted: Boolean,
userLeftFlag: UserLeftFlag, userLeftFlag: UserLeftFlag,
speechLocale: String = "" speechLocale: String = "",
userCustomData: Map[String, String] = Map.empty
) )
case class UserIdAndName(id: String, name: String) case class UserIdAndName(id: String, name: String)

View File

@ -15,12 +15,25 @@ object VoiceUsers {
users.toVector.find(u => u.uuid == uuid && u.intId == intId) users.toVector.find(u => u.uuid == uuid && u.intId == intId)
} }
def findWithIntIdAndCallerNum(users: VoiceUsers, intId: String, callerNum: String): Option[VoiceUserState] = {
// prlanzarin: This is a hack to allow for partial matching of callerNums.
// This is needed because the callerNums are incorrectly generated by
// FREESWITCH's ESL events when 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).
// We should review callerNum generation in the future as well as stop
// relying on it for session matching (use UUIDs or client session numbers instead).
users.toVector.find(u => u.intId == intId &&
(u.callerNum.startsWith(callerNum) || callerNum.startsWith(u.callerNum)))
}
def findAll(users: VoiceUsers): Vector[VoiceUserState] = users.toVector def findAll(users: VoiceUsers): Vector[VoiceUserState] = users.toVector
def findAllNonListenOnlyVoiceUsers(users: VoiceUsers): Vector[VoiceUserState] = users.toVector.filter(u => u.listenOnly == false) def findAllNonListenOnlyVoiceUsers(users: VoiceUsers): Vector[VoiceUserState] = users.toVector.filter(u => u.listenOnly == false)
def findAllListenOnlyVoiceUsers(users: VoiceUsers): Vector[VoiceUserState] = users.toVector.filter(u => u.listenOnly == true) def findAllListenOnlyVoiceUsers(users: VoiceUsers): Vector[VoiceUserState] = users.toVector.filter(u => u.listenOnly == true)
def findAllFreeswitchCallers(users: VoiceUsers): Vector[VoiceUserState] = users.toVector.filter(u => u.calledInto == "freeswitch") def findAllFreeswitchCallers(users: VoiceUsers): Vector[VoiceUserState] = users.toVector.filter(u => u.calledInto == "freeswitch")
def findAllKurentoCallers(users: VoiceUsers): Vector[VoiceUserState] = users.toVector.filter(u => u.calledInto == "kms") def findAllKurentoCallers(users: VoiceUsers): Vector[VoiceUserState] = users.toVector.filter(u => u.calledInto == "kms")
def findAllMutedVoiceUsers(users: VoiceUsers): Vector[VoiceUserState] = users.toVector.filter(u => u.muted == true && u.listenOnly == false)
def findAllBannedCallers(users: VoiceUsers): Vector[VoiceUserState] = users.bannedUsers.values.toVector def findAllBannedCallers(users: VoiceUsers): Vector[VoiceUserState] = users.bannedUsers.values.toVector

View File

@ -113,6 +113,8 @@ class ReceivedJsonMsgHandlerActor(
routeGenericMsg[ChangeUserMobileFlagReqMsg](envelope, jsonNode) routeGenericMsg[ChangeUserMobileFlagReqMsg](envelope, jsonNode)
case SetUserSpeechLocaleReqMsg.NAME => case SetUserSpeechLocaleReqMsg.NAME =>
routeGenericMsg[SetUserSpeechLocaleReqMsg](envelope, jsonNode) routeGenericMsg[SetUserSpeechLocaleReqMsg](envelope, jsonNode)
case SetUserSpeechOptionsReqMsg.NAME =>
routeGenericMsg[SetUserSpeechOptionsReqMsg](envelope, jsonNode)
case SelectRandomViewerReqMsg.NAME => case SelectRandomViewerReqMsg.NAME =>
routeGenericMsg[SelectRandomViewerReqMsg](envelope, jsonNode) routeGenericMsg[SelectRandomViewerReqMsg](envelope, jsonNode)
@ -384,6 +386,8 @@ class ReceivedJsonMsgHandlerActor(
// Lock settings // Lock settings
case LockUserInMeetingCmdMsg.NAME => case LockUserInMeetingCmdMsg.NAME =>
routeGenericMsg[LockUserInMeetingCmdMsg](envelope, jsonNode) routeGenericMsg[LockUserInMeetingCmdMsg](envelope, jsonNode)
case LockUserChatInMeetingCmdMsg.NAME =>
routeGenericMsg[LockUserChatInMeetingCmdMsg](envelope, jsonNode)
case ChangeLockSettingsInMeetingCmdMsg.NAME => case ChangeLockSettingsInMeetingCmdMsg.NAME =>
routeGenericMsg[ChangeLockSettingsInMeetingCmdMsg](envelope, jsonNode) routeGenericMsg[ChangeLockSettingsInMeetingCmdMsg](envelope, jsonNode)
case LockUsersInMeetingCmdMsg.NAME => case LockUsersInMeetingCmdMsg.NAME =>
@ -404,6 +408,8 @@ class ReceivedJsonMsgHandlerActor(
// AudioCaptions // AudioCaptions
case UpdateTranscriptPubMsg.NAME => case UpdateTranscriptPubMsg.NAME =>
routeGenericMsg[UpdateTranscriptPubMsg](envelope, jsonNode) routeGenericMsg[UpdateTranscriptPubMsg](envelope, jsonNode)
case TranscriptionProviderErrorMsg.NAME =>
routeGenericMsg[TranscriptionProviderErrorMsg](envelope, jsonNode)
// GroupChats // GroupChats
case GetGroupChatsReqMsg.NAME => case GetGroupChatsReqMsg.NAME =>

View File

@ -19,8 +19,11 @@
package org.bigbluebutton.core.record.events package org.bigbluebutton.core.record.events
import spray.json._
class ParticipantJoinRecordEvent extends AbstractParticipantRecordEvent { class ParticipantJoinRecordEvent extends AbstractParticipantRecordEvent {
import ParticipantJoinRecordEvent._ import ParticipantJoinRecordEvent._
import ParticipantJoinRecordEventJsonProtocol._
setEvent("ParticipantJoinEvent") setEvent("ParticipantJoinEvent")
@ -43,6 +46,10 @@ class ParticipantJoinRecordEvent extends AbstractParticipantRecordEvent {
def setRole(role: String) { def setRole(role: String) {
eventMap.put(ROLE, role) eventMap.put(ROLE, role)
} }
def setUserdata(userCustomData: Map[String, String]): Unit = {
eventMap.put(USER_DATA, userCustomData.toJson.compactPrint)
}
} }
object ParticipantJoinRecordEvent { object ParticipantJoinRecordEvent {
@ -50,4 +57,9 @@ object ParticipantJoinRecordEvent {
protected final val EXT_USER_ID = "externalUserId" protected final val EXT_USER_ID = "externalUserId"
protected final val NAME = "name" protected final val NAME = "name"
protected final val ROLE = "role" protected final val ROLE = "role"
protected final val USER_DATA = "userdata"
}
object ParticipantJoinRecordEventJsonProtocol extends DefaultJsonProtocol {
} }

View File

@ -70,10 +70,12 @@ trait HandlerHelpers extends SystemConfiguration {
presenter = false, presenter = false,
locked = MeetingStatus2x.getPermissions(liveMeeting.status).lockOnJoin, locked = MeetingStatus2x.getPermissions(liveMeeting.status).lockOnJoin,
avatar = regUser.avatarURL, avatar = regUser.avatarURL,
webcamBackground = regUser.webcamBackgroundURL,
color = regUser.color, color = regUser.color,
clientType = clientType, clientType = clientType,
pickExempted = false, pickExempted = false,
userLeftFlag = UserLeftFlag(false, 0) userLeftFlag = UserLeftFlag(false, 0),
userCustomData = regUser.userCustomData
) )
} }

View File

@ -399,6 +399,7 @@ class MeetingActor(
case m: ChangeUserPinStateReqMsg => usersApp.handleChangeUserPinStateReqMsg(m) case m: ChangeUserPinStateReqMsg => usersApp.handleChangeUserPinStateReqMsg(m)
case m: ChangeUserMobileFlagReqMsg => usersApp.handleChangeUserMobileFlagReqMsg(m) case m: ChangeUserMobileFlagReqMsg => usersApp.handleChangeUserMobileFlagReqMsg(m)
case m: SetUserSpeechLocaleReqMsg => usersApp.handleSetUserSpeechLocaleReqMsg(m) case m: SetUserSpeechLocaleReqMsg => usersApp.handleSetUserSpeechLocaleReqMsg(m)
case m: SetUserSpeechOptionsReqMsg => usersApp.handleSetUserSpeechOptionsReqMsg(m)
// Client requested to eject user // Client requested to eject user
case m: EjectUserFromMeetingCmdMsg => case m: EjectUserFromMeetingCmdMsg =>
@ -513,6 +514,7 @@ class MeetingActor(
handleSetLockSettings(m) handleSetLockSettings(m)
updateUserLastActivity(m.body.setBy) updateUserLastActivity(m.body.setBy)
case m: LockUserInMeetingCmdMsg => handleLockUserInMeetingCmdMsg(m) case m: LockUserInMeetingCmdMsg => handleLockUserInMeetingCmdMsg(m)
case m: LockUserChatInMeetingCmdMsg => handleLockUserChatInMeetingCmdMsg(m)
case m: LockUsersInMeetingCmdMsg => handleLockUsersInMeetingCmdMsg(m) case m: LockUsersInMeetingCmdMsg => handleLockUsersInMeetingCmdMsg(m)
case m: GetLockSettingsReqMsg => handleGetLockSettingsReqMsg(m) case m: GetLockSettingsReqMsg => handleGetLockSettingsReqMsg(m)
@ -582,6 +584,7 @@ class MeetingActor(
// AudioCaptions // AudioCaptions
case m: UpdateTranscriptPubMsg => audioCaptionsApp2x.handle(m, liveMeeting, msgBus) case m: UpdateTranscriptPubMsg => audioCaptionsApp2x.handle(m, liveMeeting, msgBus)
case m: TranscriptionProviderErrorMsg => audioCaptionsApp2x.handleTranscriptionProviderErrorMsg(m, liveMeeting, msgBus)
// GroupChat // GroupChat
case m: CreateGroupChatReqMsg => case m: CreateGroupChatReqMsg =>
@ -869,6 +872,7 @@ class MeetingActor(
val hasModeratorLeftRecently = (TimeUtil.timeNowInMs() - state.expiryTracker.endWhenNoModeratorDelayInMs) < state.expiryTracker.lastModeratorLeftOnInMs val hasModeratorLeftRecently = (TimeUtil.timeNowInMs() - state.expiryTracker.endWhenNoModeratorDelayInMs) < state.expiryTracker.lastModeratorLeftOnInMs
if (!hasModeratorLeftRecently) { if (!hasModeratorLeftRecently) {
log.info("Meeting will end due option endWhenNoModerator is enabled and all moderators have left the meeting. meetingId=" + props.meetingProp.intId) log.info("Meeting will end due option endWhenNoModerator is enabled and all moderators have left the meeting. meetingId=" + props.meetingProp.intId)
endAllBreakoutRooms(eventBus, liveMeeting, state, MeetingEndReason.ENDED_DUE_TO_NO_MODERATOR)
sendEndMeetingDueToExpiry( sendEndMeetingDueToExpiry(
MeetingEndReason.ENDED_DUE_TO_NO_MODERATOR, MeetingEndReason.ENDED_DUE_TO_NO_MODERATOR,
eventBus, outGW, liveMeeting, eventBus, outGW, liveMeeting,

View File

@ -6,6 +6,7 @@ import org.bigbluebutton.core.running.{ MeetingActor, 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.core2.message.senders.{ MsgBuilder } import org.bigbluebutton.core2.message.senders.{ MsgBuilder }
import org.bigbluebutton.core.apps.voice.VoiceApp
trait MuteAllExceptPresentersCmdMsgHdlr extends RightsManagementTrait { trait MuteAllExceptPresentersCmdMsgHdlr extends RightsManagementTrait {
this: MeetingActor => this: MeetingActor =>
@ -57,8 +58,8 @@ trait MuteAllExceptPresentersCmdMsgHdlr extends RightsManagementTrait {
VoiceUsers.findAll(liveMeeting.voiceUsers) foreach { vu => VoiceUsers.findAll(liveMeeting.voiceUsers) foreach { vu =>
if (!vu.listenOnly) { if (!vu.listenOnly) {
Users2x.findWithIntId(liveMeeting.users2x, vu.intId) match { Users2x.findWithIntId(liveMeeting.users2x, vu.intId) match {
case Some(u) => if (!u.presenter) muteUserInVoiceConf(vu, muted) case Some(u) => if (!u.presenter) VoiceApp.muteUserInVoiceConf(liveMeeting, outGW, vu.intId, muted)
case None => muteUserInVoiceConf(vu, muted) case None => VoiceApp.muteUserInVoiceConf(liveMeeting, outGW, vu.intId, muted)
} }
} }
} }
@ -82,17 +83,4 @@ trait MuteAllExceptPresentersCmdMsgHdlr extends RightsManagementTrait {
BbbCommonEnvCoreMsg(envelope, event) BbbCommonEnvCoreMsg(envelope, event)
} }
def muteUserInVoiceConf(vu: VoiceUserState, mute: Boolean): Unit = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, props.meetingProp.intId, vu.intId)
val envelope = BbbCoreEnvelope(MuteUserInVoiceConfSysMsg.NAME, routing)
val header = BbbCoreHeaderWithMeetingId(MuteUserInVoiceConfSysMsg.NAME, props.meetingProp.intId)
val body = MuteUserInVoiceConfSysMsgBody(props.voiceProp.voiceConf, vu.voiceUserId, mute)
val event = MuteUserInVoiceConfSysMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
outGW.send(msgEvent)
}
} }

View File

@ -6,6 +6,7 @@ import org.bigbluebutton.core.models.{ VoiceUserState, VoiceUsers }
import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter } import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter }
import org.bigbluebutton.core2.MeetingStatus2x import org.bigbluebutton.core2.MeetingStatus2x
import org.bigbluebutton.core2.message.senders.{ MsgBuilder } import org.bigbluebutton.core2.message.senders.{ MsgBuilder }
import org.bigbluebutton.core.apps.voice.VoiceApp
trait MuteMeetingCmdMsgHdlr extends RightsManagementTrait { trait MuteMeetingCmdMsgHdlr extends RightsManagementTrait {
this: MeetingActor => this: MeetingActor =>
@ -30,19 +31,6 @@ trait MuteMeetingCmdMsgHdlr extends RightsManagementTrait {
BbbCommonEnvCoreMsg(envelope, event) BbbCommonEnvCoreMsg(envelope, event)
} }
def muteUserInVoiceConf(vu: VoiceUserState, mute: Boolean): Unit = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, props.meetingProp.intId, vu.intId)
val envelope = BbbCoreEnvelope(MuteUserInVoiceConfSysMsg.NAME, routing)
val header = BbbCoreHeaderWithMeetingId(MuteUserInVoiceConfSysMsg.NAME, props.meetingProp.intId)
val body = MuteUserInVoiceConfSysMsgBody(props.voiceProp.voiceConf, vu.voiceUserId, mute)
val event = MuteUserInVoiceConfSysMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
outGW.send(msgEvent)
}
if (msg.body.mute != MeetingStatus2x.isMeetingMuted(liveMeeting.status)) { if (msg.body.mute != MeetingStatus2x.isMeetingMuted(liveMeeting.status)) {
if (msg.body.mute) { if (msg.body.mute) {
val notifyEvent = MsgBuilder.buildNotifyAllInMeetingEvtMsg( val notifyEvent = MsgBuilder.buildNotifyAllInMeetingEvtMsg(
@ -79,7 +67,7 @@ trait MuteMeetingCmdMsgHdlr extends RightsManagementTrait {
if (muted) { if (muted) {
VoiceUsers.findAll(liveMeeting.voiceUsers) foreach { vu => VoiceUsers.findAll(liveMeeting.voiceUsers) foreach { vu =>
if (!vu.listenOnly) { if (!vu.listenOnly) {
muteUserInVoiceConf(vu, muted) VoiceApp.muteUserInVoiceConf(liveMeeting, outGW, vu.intId, muted)
} }
} }
} }

View File

@ -637,11 +637,12 @@ object MsgBuilder {
meetingId: String, meetingId: String,
voiceConf: String, voiceConf: String,
userId: String, userId: String,
callerNum: String,
enabled: Boolean enabled: Boolean
): BbbCommonEnvCoreMsg = { ): BbbCommonEnvCoreMsg = {
val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka") val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka")
val envelope = BbbCoreEnvelope(ToggleListenOnlyModeSysMsg.NAME, routing) val envelope = BbbCoreEnvelope(ToggleListenOnlyModeSysMsg.NAME, routing)
val body = ToggleListenOnlyModeSysMsgBody(voiceConf, userId, enabled) val body = ToggleListenOnlyModeSysMsgBody(voiceConf, userId, callerNum, enabled)
val header = BbbCoreHeaderWithMeetingId(ToggleListenOnlyModeSysMsg.NAME, meetingId) val header = BbbCoreHeaderWithMeetingId(ToggleListenOnlyModeSysMsg.NAME, meetingId)
val event = ToggleListenOnlyModeSysMsg(header, body) val event = ToggleListenOnlyModeSysMsg(header, body)

View File

@ -16,8 +16,8 @@ object UserJoinedMeetingEvtMsgBuilder {
raiseHand = userState.raiseHand, raiseHand = userState.raiseHand,
away = userState.away, away = userState.away,
pin = userState.pin, pin = userState.pin,
presenter = userState.presenter, locked = userState.locked, avatar = userState.avatar, color = userState.color, presenter = userState.presenter, locked = userState.locked, avatar = userState.avatar, webcamBackground = userState.webcamBackground, color = userState.color,
clientType = userState.clientType) clientType = userState.clientType, userCustomData = userState.userCustomData)
val event = UserJoinedMeetingEvtMsg(meetingId, userState.intId, body) val event = UserJoinedMeetingEvtMsg(meetingId, userState.intId, body)

View File

@ -20,13 +20,13 @@ trait FakeTestData {
val guest1 = createUserVoiceAndCam(liveMeeting, Roles.VIEWER_ROLE, guest = true, authed = true, CallingWith.WEBRTC, muted = false, val guest1 = createUserVoiceAndCam(liveMeeting, Roles.VIEWER_ROLE, guest = true, authed = true, CallingWith.WEBRTC, muted = false,
talking = false, listenOnly = false) talking = false, listenOnly = false)
Users2x.add(liveMeeting.users2x, guest1) Users2x.add(liveMeeting.users2x, guest1)
val guestWait1 = GuestWaiting(guest1.intId, guest1.name, guest1.role, guest1.guest, "", "#ff6242", guest1.authed, System.currentTimeMillis()) val guestWait1 = GuestWaiting(guest1.intId, guest1.name, guest1.role, guest1.guest, "", "", "#ff6242", guest1.authed, System.currentTimeMillis())
GuestsWaiting.add(liveMeeting.guestsWaiting, guestWait1) GuestsWaiting.add(liveMeeting.guestsWaiting, guestWait1)
val guest2 = createUserVoiceAndCam(liveMeeting, Roles.VIEWER_ROLE, guest = true, authed = true, CallingWith.FLASH, muted = false, val guest2 = createUserVoiceAndCam(liveMeeting, Roles.VIEWER_ROLE, guest = true, authed = true, CallingWith.FLASH, muted = false,
talking = false, listenOnly = false) talking = false, listenOnly = false)
Users2x.add(liveMeeting.users2x, guest2) Users2x.add(liveMeeting.users2x, guest2)
val guestWait2 = GuestWaiting(guest2.intId, guest2.name, guest2.role, guest2.guest, "", "#ff6242", guest2.authed, System.currentTimeMillis()) val guestWait2 = GuestWaiting(guest2.intId, guest2.name, guest2.role, guest2.guest, "", "", "#ff6242", guest2.authed, System.currentTimeMillis())
GuestsWaiting.add(liveMeeting.guestsWaiting, guestWait2) GuestsWaiting.add(liveMeeting.guestsWaiting, guestWait2)
val vu1 = FakeUserGenerator.createFakeVoiceOnlyUser(CallingWith.PHONE, muted = false, talking = false, listenOnly = false) val vu1 = FakeUserGenerator.createFakeVoiceOnlyUser(CallingWith.PHONE, muted = false, talking = false, listenOnly = false)
@ -69,7 +69,8 @@ trait FakeTestData {
UserState(intId = regUser.id, extId = regUser.externId, name = regUser.name, role = regUser.role, pin = false, UserState(intId = regUser.id, extId = regUser.externId, name = regUser.name, role = regUser.role, pin = false,
mobile = false, guest = regUser.guest, authed = regUser.authed, guestStatus = regUser.guestStatus, mobile = false, guest = regUser.guest, authed = regUser.authed, guestStatus = regUser.guestStatus,
emoji = "none", reactionEmoji = "none", raiseHand = false, away = false, locked = false, presenter = false, emoji = "none", reactionEmoji = "none", raiseHand = false, away = false, locked = false, presenter = false,
avatar = regUser.avatarURL, color = "#ff6242", clientType = "unknown", avatar = regUser.avatarURL, webcamBackground = regUser.webcamBackgroundURL,
color = "#ff6242", clientType = "unknown",
pickExempted = false, userLeftFlag = UserLeftFlag(false, 0)) pickExempted = false, userLeftFlag = UserLeftFlag(false, 0))
} }

View File

@ -52,10 +52,12 @@ object FakeUserGenerator {
val authToken = RandomStringGenerator.randomAlphanumericString(16) val authToken = RandomStringGenerator.randomAlphanumericString(16)
val avatarURL = "https://www." + RandomStringGenerator.randomAlphanumericString(32) + ".com/" + val avatarURL = "https://www." + RandomStringGenerator.randomAlphanumericString(32) + ".com/" +
RandomStringGenerator.randomAlphanumericString(10) + ".png" RandomStringGenerator.randomAlphanumericString(10) + ".png"
val webcamBackgroundURL = "https://www." + RandomStringGenerator.randomAlphanumericString(32) + ".com/" +
RandomStringGenerator.randomAlphanumericString(10) + ".jpg"
val color = "#ff6242" val color = "#ff6242"
val ru = RegisteredUsers.create(userId = id, extId, name, role, val ru = RegisteredUsers.create(userId = id, extId, name, role,
authToken, avatarURL, color, guest, authed, guestStatus = GuestStatus.ALLOW, false, false) authToken, avatarURL, webcamBackgroundURL, color, guest, authed, guestStatus = GuestStatus.ALLOW, false, false)
RegisteredUsers.add(users, ru) RegisteredUsers.add(users, ru)
ru ru
} }

View File

@ -20,6 +20,7 @@ case class Meeting(
intId: String, intId: String,
extId: String, extId: String,
name: String, name: String,
downloadSessionDataEnabled: Boolean,
users: Map[String, User] = Map(), users: Map[String, User] = Map(),
polls: Map[String, Poll] = Map(), polls: Map[String, Poll] = Map(),
screenshares: Vector[Screenshare] = Vector(), screenshares: Vector[Screenshare] = Vector(),
@ -397,10 +398,33 @@ class LearningDashboardActor(
user <- findUserByIntId(meeting, msg.body.userId) user <- findUserByIntId(meeting, msg.body.userId)
} yield { } yield {
if (msg.body.reactionEmoji != "none") { if (msg.body.reactionEmoji != "none") {
//Ignore multiple Reactions to prevent flooding
val hasSameReactionInLast30Seconds = user.reactions.filter(r => {
System.currentTimeMillis() - r.sentOn < (30 * 1000) && r.name == msg.body.reactionEmoji
}).length > 0
if(!hasSameReactionInLast30Seconds) {
val updatedUser = user.copy(reactions = user.reactions :+ Emoji(msg.body.reactionEmoji)) val updatedUser = user.copy(reactions = user.reactions :+ Emoji(msg.body.reactionEmoji))
val updatedMeeting = meeting.copy(users = meeting.users + (updatedUser.userKey -> updatedUser)) val updatedMeeting = meeting.copy(users = meeting.users + (updatedUser.userKey -> updatedUser))
meetings += (updatedMeeting.intId -> updatedMeeting) meetings += (updatedMeeting.intId -> updatedMeeting)
//Convert Reactions to legacy Emoji (while LearningDashboard doesn't support Reactions)
val emoji = msg.body.reactionEmoji.codePointAt(0) match {
case 128515 => "happy"
case 128528 => "neutral"
case 128577 => "sad"
case 128077 => "thumbsUp"
case 128078 => "thumbsDown"
case 128079 => "applause"
case _ => "none"
}
if (emoji != "none") {
val updatedUserWithEmoji = updatedUser.copy(emojis = user.emojis :+ Emoji(emoji))
val updatedMeetingWithEmoji = meeting.copy(users = meeting.users + (updatedUserWithEmoji.userKey -> updatedUserWithEmoji))
meetings += (updatedMeeting.intId -> updatedMeetingWithEmoji)
}
}
} }
} }
} }
@ -562,6 +586,7 @@ class LearningDashboardActor(
msg.body.props.meetingProp.intId, msg.body.props.meetingProp.intId,
msg.body.props.meetingProp.extId, msg.body.props.meetingProp.extId,
msg.body.props.meetingProp.name, msg.body.props.meetingProp.name,
downloadSessionDataEnabled = !msg.body.props.meetingProp.disabledFeatures.contains("learningDashboardDownloadSessionData"),
) )
meetings += (newMeeting.intId -> newMeeting) meetings += (newMeeting.intId -> newMeeting)

View File

@ -85,6 +85,9 @@ class RedisRecorderActor(
case m: UserLeftMeetingEvtMsg => handleUserLeftMeetingEvtMsg(m) case m: UserLeftMeetingEvtMsg => handleUserLeftMeetingEvtMsg(m)
case m: PresenterAssignedEvtMsg => handlePresenterAssignedEvtMsg(m) case m: PresenterAssignedEvtMsg => handlePresenterAssignedEvtMsg(m)
case m: UserEmojiChangedEvtMsg => handleUserEmojiChangedEvtMsg(m) case m: UserEmojiChangedEvtMsg => handleUserEmojiChangedEvtMsg(m)
case m: UserAwayChangedEvtMsg => handleUserAwayChangedEvtMsg(m)
case m: UserRaiseHandChangedEvtMsg => handleUserRaiseHandChangedEvtMsg(m)
case m: UserReactionEmojiChangedEvtMsg => handleUserReactionEmojiChangedEvtMsg(m)
case m: UserRoleChangedEvtMsg => handleUserRoleChangedEvtMsg(m) case m: UserRoleChangedEvtMsg => handleUserRoleChangedEvtMsg(m)
case m: UserBroadcastCamStartedEvtMsg => handleUserBroadcastCamStartedEvtMsg(m) case m: UserBroadcastCamStartedEvtMsg => handleUserBroadcastCamStartedEvtMsg(m)
case m: UserBroadcastCamStoppedEvtMsg => handleUserBroadcastCamStoppedEvtMsg(m) case m: UserBroadcastCamStoppedEvtMsg => handleUserBroadcastCamStoppedEvtMsg(m)
@ -112,7 +115,7 @@ class RedisRecorderActor(
//case m: DeskShareNotifyViewersRTMP => handleDeskShareNotifyViewersRTMP(m) //case m: DeskShareNotifyViewersRTMP => handleDeskShareNotifyViewersRTMP(m)
// AudioCaptions // AudioCaptions
case m: TranscriptUpdatedEvtMsg => handleTranscriptUpdatedEvtMsg(m) //case m: TranscriptUpdatedEvtMsg => handleTranscriptUpdatedEvtMsg(m) // temporarily disabling due to issue https://github.com/bigbluebutton/bigbluebutton/issues/19701
// Meeting // Meeting
case m: RecordingStatusChangedEvtMsg => handleRecordingStatusChangedEvtMsg(m) case m: RecordingStatusChangedEvtMsg => handleRecordingStatusChangedEvtMsg(m)
@ -354,6 +357,7 @@ class RedisRecorderActor(
ev.setExternalUserId(msg.body.extId) ev.setExternalUserId(msg.body.extId)
ev.setName(msg.body.name) ev.setName(msg.body.name)
ev.setRole(msg.body.role) ev.setRole(msg.body.role)
ev.setUserdata(msg.body.userCustomData)
record(msg.header.meetingId, ev.toMap.asJava) record(msg.header.meetingId, ev.toMap.asJava)
} }
@ -379,6 +383,18 @@ class RedisRecorderActor(
handleUserStatusChange(msg.header.meetingId, msg.body.userId, "emojiStatus", msg.body.emoji) handleUserStatusChange(msg.header.meetingId, msg.body.userId, "emojiStatus", msg.body.emoji)
} }
private def handleUserAwayChangedEvtMsg(msg: UserAwayChangedEvtMsg) {
handleUserStatusChange(msg.header.meetingId, msg.body.userId, "away", if (msg.body.away) "true" else "false")
}
private def handleUserRaiseHandChangedEvtMsg(msg: UserRaiseHandChangedEvtMsg) {
handleUserStatusChange(msg.header.meetingId, msg.body.userId, "raiseHand", if (msg.body.raiseHand) "true" else "false")
}
private def handleUserReactionEmojiChangedEvtMsg(msg: UserReactionEmojiChangedEvtMsg) {
handleUserStatusChange(msg.header.meetingId, msg.body.userId, "reactionEmoji", msg.body.reactionEmoji)
}
private def handleUserRoleChangedEvtMsg(msg: UserRoleChangedEvtMsg) { private def handleUserRoleChangedEvtMsg(msg: UserRoleChangedEvtMsg) {
handleUserStatusChange(msg.header.meetingId, msg.body.userId, "role", msg.body.role) handleUserStatusChange(msg.header.meetingId, msg.body.userId, "role", msg.body.role)
} }
@ -521,6 +537,7 @@ class RedisRecorderActor(
} }
*/ */
/* temporarily disabling due to issue https://github.com/bigbluebutton/bigbluebutton/issues/19701
private def handleTranscriptUpdatedEvtMsg(msg: TranscriptUpdatedEvtMsg) { private def handleTranscriptUpdatedEvtMsg(msg: TranscriptUpdatedEvtMsg) {
val ev = new TranscriptUpdatedRecordEvent() val ev = new TranscriptUpdatedRecordEvent()
ev.setMeetingId(msg.header.meetingId) ev.setMeetingId(msg.header.meetingId)
@ -529,6 +546,7 @@ class RedisRecorderActor(
record(msg.header.meetingId, ev.toMap.asJava) record(msg.header.meetingId, ev.toMap.asJava)
} }
*/
private def handleStartExternalVideoEvtMsg(msg: StartExternalVideoEvtMsg) { private def handleStartExternalVideoEvtMsg(msg: StartExternalVideoEvtMsg) {
val ev = new StartExternalVideoRecordEvent() val ev = new StartExternalVideoRecordEvent()

View File

@ -44,6 +44,7 @@ trait AppsTestFixtures {
val allowModsToUnmuteUsers = false val allowModsToUnmuteUsers = false
val allowModsToEjectCameras = false val allowModsToEjectCameras = false
val authenticatedGuest = false val authenticatedGuest = false
val allowPromoteGuestToModerator = false
val meetingLayout = "" val meetingLayout = ""
val captureNotesFilename = s"Room 0${sequence} (Notes)" val captureNotesFilename = s"Room 0${sequence} (Notes)"
val captureSlidesFilename = s"Room 0${sequence} (Whiteboard)" val captureSlidesFilename = s"Room 0${sequence} (Whiteboard)"
@ -70,7 +71,7 @@ trait AppsTestFixtures {
val usersProp = UsersProp(maxUsers = maxUsers, webcamsOnlyForModerator = webcamsOnlyForModerator, val usersProp = UsersProp(maxUsers = maxUsers, webcamsOnlyForModerator = webcamsOnlyForModerator,
userCameraCap = userCameraCap, userCameraCap = userCameraCap,
guestPolicy = guestPolicy, allowModsToUnmuteUsers = allowModsToUnmuteUsers, allowModsToEjectCameras = allowModsToEjectCameras, guestPolicy = guestPolicy, allowModsToUnmuteUsers = allowModsToUnmuteUsers, allowModsToEjectCameras = allowModsToEjectCameras,
authenticatedGuest = authenticatedGuest, meetingLayout = meetingLayout) authenticatedGuest = authenticatedGuest, allowPromoteGuestToModerator = allowPromoteGuestToModerator, meetingLayout = meetingLayout)
val metadataProp = new MetadataProp(metadata) val metadataProp = new MetadataProp(metadata)
val defaultProps = DefaultProps(meetingProp, breakoutProps, durationProps, password, recordProp, welcomeProp, voiceProp, val defaultProps = DefaultProps(meetingProp, breakoutProps, durationProps, password, recordProp, welcomeProp, voiceProp,

View File

@ -12,9 +12,11 @@ object TestDataGen {
val authToken = RandomStringGenerator.randomAlphanumericString(16) val authToken = RandomStringGenerator.randomAlphanumericString(16)
val avatarURL = "https://www." + RandomStringGenerator.randomAlphanumericString(32) + ".com/" + val avatarURL = "https://www." + RandomStringGenerator.randomAlphanumericString(32) + ".com/" +
RandomStringGenerator.randomAlphanumericString(10) + ".png" RandomStringGenerator.randomAlphanumericString(10) + ".png"
val webcamBackgroundURL = "https://www." + RandomStringGenerator.randomAlphanumericString(32) + ".com/" +
RandomStringGenerator.randomAlphanumericString(10) + ".jpg"
val ru = RegisteredUsers.create(userId = id, extId, name, role, val ru = RegisteredUsers.create(userId = id, extId, name, role,
authToken, avatarURL, guest, authed, GuestStatus.ALLOW, false) authToken, avatarURL, webcamBackgroundURL, guest, authed, GuestStatus.ALLOW, false)
RegisteredUsers.add(users, ru) RegisteredUsers.add(users, ru)
ru ru
@ -48,7 +50,7 @@ object TestDataGen {
val u = UserState(intId = regUser.id, extId = regUser.externId, name = regUser.name, role = regUser.role, val u = UserState(intId = regUser.id, extId = regUser.externId, name = regUser.name, role = regUser.role,
guest = regUser.guest, authed = regUser.authed, guestStatus = regUser.guestStatus, guest = regUser.guest, authed = regUser.authed, guestStatus = regUser.guestStatus,
emoji = "none", reactionEmoji = "none", raiseHand = false, away = false, pin = false, mobile = false, emoji = "none", reactionEmoji = "none", raiseHand = false, away = false, pin = false, mobile = false,
locked = false, presenter = false, avatar = regUser.avatarURL, color = "#ff6242", locked = false, presenter = false, avatar = regUser.avatarURL, regUser.webcamBackgroundURL, color = "#ff6242",
clientType = "unknown", pickExempted = false, userLeftFlag = UserLeftFlag(false, 0)) clientType = "unknown", pickExempted = false, userLeftFlag = UserLeftFlag(false, 0))
Users2x.add(liveMeeting.users2x, u) Users2x.add(liveMeeting.users2x, u)
u u

View File

@ -44,6 +44,7 @@ expire {
services { services {
bbbWebAPI = "https://192.168.23.33/bigbluebutton/api" bbbWebAPI = "https://192.168.23.33/bigbluebutton/api"
sharedSecret = "changeme" sharedSecret = "changeme"
checkSumAlgorithmForBreakouts = "sha256"
} }
eventBus { eventBus {
@ -96,6 +97,11 @@ voiceConf {
# Time (seconds) to wait before requesting an audio channel hold after # Time (seconds) to wait before requesting an audio channel hold after
# muting a user. Used in the experimental, transparent listen only mode. # muting a user. Used in the experimental, transparent listen only mode.
toggleListenOnlyAfterMuteTimer = 4 toggleListenOnlyAfterMuteTimer = 4
# Transparent listen only meeting-wide activation threshold.
# Threshold is the number of muted duplex audio channels in a meeting.
# 0 = disabled
transparentListenOnlyThreshold = 0
} }
recording { recording {

View File

@ -14,7 +14,7 @@ object Dependencies {
// Libraries // Libraries
val akkaVersion = "2.6.17" val akkaVersion = "2.6.17"
val akkaHttpVersion = "10.2.7" val akkaHttpVersion = "10.2.7"
val logback = "1.2.10" val logback = "1.2.13"
// Apache Commons // Apache Commons
val lang = "3.12.0" val lang = "3.12.0"

View File

@ -109,6 +109,7 @@ public class FreeswitchConferenceEventListener implements ConferenceEventListene
evt.callSession, evt.callSession,
evt.clientSession, evt.clientSession,
evt.userId, evt.userId,
evt.getVoiceUserId(),
evt.callerName, evt.callerName,
evt.callState, evt.callState,
evt.origCallerIdName, evt.origCallerIdName,

View File

@ -59,6 +59,7 @@ public interface IVoiceConferenceService {
String callSession, String callSession,
String clientSession, String clientSession,
String userId, String userId,
String voiceUserId,
String callerName, String callerName,
String callState, String callState,
String origCallerIdName, String origCallerIdName,

View File

@ -4,6 +4,8 @@ public class VoiceCallStateEvent extends VoiceConferenceEvent {
public final String callSession; public final String callSession;
public final String clientSession; public final String clientSession;
public final String userId; public final String userId;
// AKA mod_conference memberId
public final String voiceUserId;
public final String callerName; public final String callerName;
public final String callState; public final String callState;
public final String origCallerIdName; public final String origCallerIdName;
@ -14,6 +16,7 @@ public class VoiceCallStateEvent extends VoiceConferenceEvent {
String callSession, String callSession,
String clientSession, String clientSession,
String userId, String userId,
String voiceUserId,
String callerName, String callerName,
String callState, String callState,
String origCallerIdName, String origCallerIdName,
@ -22,9 +25,14 @@ public class VoiceCallStateEvent extends VoiceConferenceEvent {
this.callSession = callSession; this.callSession = callSession;
this.clientSession = clientSession; this.clientSession = clientSession;
this.userId = userId; this.userId = userId;
this.voiceUserId = voiceUserId;
this.callerName = callerName; this.callerName = callerName;
this.callState = callState; this.callState = callState;
this.origCallerIdName = origCallerIdName; this.origCallerIdName = origCallerIdName;
this.origCalledDest = origCalledDest; this.origCalledDest = origCalledDest;
} }
public String getVoiceUserId() {
return voiceUserId;
}
} }

View File

@ -84,6 +84,7 @@ public class ESLEventListener implements IEslEventListener {
String origCallerIdName = headers.get("Caller-Caller-ID-Name"); String origCallerIdName = headers.get("Caller-Caller-ID-Name");
String origCallerDestNumber = headers.get("Caller-Destination-Number"); String origCallerDestNumber = headers.get("Caller-Destination-Number");
String clientSession = "0"; String clientSession = "0";
String memberIdStr = memberId != null ? memberId.toString() : "";
Matcher matcher = CALLERNAME_PATTERN.matcher(callerIdName); Matcher matcher = CALLERNAME_PATTERN.matcher(callerIdName);
Matcher callWithSess = CALLERNAME_WITH_SESS_INFO_PATTERN.matcher(callerIdName); Matcher callWithSess = CALLERNAME_WITH_SESS_INFO_PATTERN.matcher(callerIdName);
@ -106,6 +107,7 @@ public class ESLEventListener implements IEslEventListener {
coreuuid, coreuuid,
clientSession, clientSession,
voiceUserId, voiceUserId,
memberIdStr,
callerIdName, callerIdName,
callState, callState,
origCallerIdName, origCallerIdName,
@ -281,6 +283,7 @@ public class ESLEventListener implements IEslEventListener {
String varvBridge = (eventHeaders.get("variable_vbridge") == null) ? "" : eventHeaders.get("variable_vbridge"); String varvBridge = (eventHeaders.get("variable_vbridge") == null) ? "" : eventHeaders.get("variable_vbridge");
if ("echo".equalsIgnoreCase(application) && !varvBridge.isEmpty()) { if ("echo".equalsIgnoreCase(application) && !varvBridge.isEmpty()) {
Integer memberId = this.getMemberId(eventHeaders);
String origCallerIdName = eventHeaders.get("Caller-Caller-ID-Name"); String origCallerIdName = eventHeaders.get("Caller-Caller-ID-Name");
String origCallerDestNumber = eventHeaders.get("Caller-Destination-Number"); String origCallerDestNumber = eventHeaders.get("Caller-Destination-Number");
String coreuuid = eventHeaders.get("Core-UUID"); String coreuuid = eventHeaders.get("Core-UUID");
@ -291,6 +294,7 @@ public class ESLEventListener implements IEslEventListener {
String callerName = origCallerIdName; String callerName = origCallerIdName;
String clientSession = "0"; String clientSession = "0";
String callState = "IN_ECHO_TEST"; String callState = "IN_ECHO_TEST";
String memberIdStr = memberId != null ? memberId.toString() : "";
Matcher callerListenOnly = CALLERNAME_LISTENONLY_PATTERN.matcher(origCallerIdName); Matcher callerListenOnly = CALLERNAME_LISTENONLY_PATTERN.matcher(origCallerIdName);
Matcher callWithSess = CALLERNAME_WITH_SESS_INFO_PATTERN.matcher(origCallerIdName); Matcher callWithSess = CALLERNAME_WITH_SESS_INFO_PATTERN.matcher(origCallerIdName);
@ -314,6 +318,7 @@ public class ESLEventListener implements IEslEventListener {
coreuuid, coreuuid,
clientSession, clientSession,
voiceUserId, voiceUserId,
memberIdStr,
callerName, callerName,
callState, callState,
origCallerIdName, origCallerIdName,
@ -321,6 +326,7 @@ public class ESLEventListener implements IEslEventListener {
conferenceEventListener.handleConferenceEvent(csEvent); conferenceEventListener.handleConferenceEvent(csEvent);
} else if ("RINGING".equalsIgnoreCase(channelCallState) && !varvBridge.isEmpty()) { } else if ("RINGING".equalsIgnoreCase(channelCallState) && !varvBridge.isEmpty()) {
Integer memberId = this.getMemberId(eventHeaders);
String origCallerIdName = eventHeaders.get("Caller-Caller-ID-Name"); String origCallerIdName = eventHeaders.get("Caller-Caller-ID-Name");
String origCallerDestNumber = eventHeaders.get("Caller-Destination-Number"); String origCallerDestNumber = eventHeaders.get("Caller-Destination-Number");
String coreuuid = eventHeaders.get("Core-UUID"); String coreuuid = eventHeaders.get("Core-UUID");
@ -330,6 +336,7 @@ public class ESLEventListener implements IEslEventListener {
String callerName = origCallerIdName; String callerName = origCallerIdName;
String clientSession = "0"; String clientSession = "0";
String callState = "CALL_STARTED"; String callState = "CALL_STARTED";
String memberIdStr = memberId != null ? memberId.toString() : "";
Matcher callerListenOnly = CALLERNAME_LISTENONLY_PATTERN.matcher(origCallerIdName); Matcher callerListenOnly = CALLERNAME_LISTENONLY_PATTERN.matcher(origCallerIdName);
Matcher callWithSess = CALLERNAME_WITH_SESS_INFO_PATTERN.matcher(origCallerIdName); Matcher callWithSess = CALLERNAME_WITH_SESS_INFO_PATTERN.matcher(origCallerIdName);
@ -353,6 +360,7 @@ public class ESLEventListener implements IEslEventListener {
coreuuid, coreuuid,
clientSession, clientSession,
voiceUserId, voiceUserId,
memberIdStr,
callerName, callerName,
callState, callState,
origCallerIdName, origCallerIdName,
@ -365,6 +373,7 @@ public class ESLEventListener implements IEslEventListener {
String channelState = (eventHeaders.get("Channel-State") == null) ? "" : eventHeaders.get("Channel-State"); String channelState = (eventHeaders.get("Channel-State") == null) ? "" : eventHeaders.get("Channel-State");
if ("HANGUP".equalsIgnoreCase(channelCallState) && "CS_DESTROY".equalsIgnoreCase(channelState)) { if ("HANGUP".equalsIgnoreCase(channelCallState) && "CS_DESTROY".equalsIgnoreCase(channelState)) {
Integer memberId = this.getMemberId(eventHeaders);
String origCallerIdName = eventHeaders.get("Caller-Caller-ID-Name"); String origCallerIdName = eventHeaders.get("Caller-Caller-ID-Name");
String origCallerDestNumber = eventHeaders.get("Caller-Destination-Number"); String origCallerDestNumber = eventHeaders.get("Caller-Destination-Number");
String coreuuid = eventHeaders.get("Core-UUID"); String coreuuid = eventHeaders.get("Core-UUID");
@ -374,6 +383,7 @@ public class ESLEventListener implements IEslEventListener {
String callerName = origCallerIdName; String callerName = origCallerIdName;
String clientSession = "0"; String clientSession = "0";
String callState = "CALL_ENDED"; String callState = "CALL_ENDED";
String memberIdStr = memberId != null ? memberId.toString() : "";
Matcher callerListenOnly = CALLERNAME_LISTENONLY_PATTERN.matcher(origCallerIdName); Matcher callerListenOnly = CALLERNAME_LISTENONLY_PATTERN.matcher(origCallerIdName);
Matcher callWithSess = CALLERNAME_WITH_SESS_INFO_PATTERN.matcher(origCallerIdName); Matcher callWithSess = CALLERNAME_WITH_SESS_INFO_PATTERN.matcher(origCallerIdName);
@ -397,6 +407,7 @@ public class ESLEventListener implements IEslEventListener {
coreuuid, coreuuid,
clientSession, clientSession,
voiceUserId, voiceUserId,
memberIdStr,
callerName, callerName,
callState, callState,
origCallerIdName, origCallerIdName,
@ -405,6 +416,7 @@ public class ESLEventListener implements IEslEventListener {
conferenceEventListener.handleConferenceEvent(csEvent); conferenceEventListener.handleConferenceEvent(csEvent);
} else if ("RINGING".equalsIgnoreCase(channelCallState) && "CS_EXECUTE".equalsIgnoreCase(channelState)) { } else if ("RINGING".equalsIgnoreCase(channelCallState) && "CS_EXECUTE".equalsIgnoreCase(channelState)) {
Integer memberId = this.getMemberId(eventHeaders);
String origCallerIdName = eventHeaders.get("Caller-Caller-ID-Name"); String origCallerIdName = eventHeaders.get("Caller-Caller-ID-Name");
String origCallerDestNumber = eventHeaders.get("Caller-Destination-Number"); String origCallerDestNumber = eventHeaders.get("Caller-Destination-Number");
String coreuuid = eventHeaders.get("Core-UUID"); String coreuuid = eventHeaders.get("Core-UUID");
@ -414,6 +426,7 @@ public class ESLEventListener implements IEslEventListener {
String callerName = origCallerIdName; String callerName = origCallerIdName;
String clientSession = "0"; String clientSession = "0";
String callState = "CALL_STARTED"; String callState = "CALL_STARTED";
String memberIdStr = memberId != null ? memberId.toString() : "";
Matcher callerListenOnly = CALLERNAME_LISTENONLY_PATTERN.matcher(origCallerIdName); Matcher callerListenOnly = CALLERNAME_LISTENONLY_PATTERN.matcher(origCallerIdName);
Matcher callWithSess = CALLERNAME_WITH_SESS_INFO_PATTERN.matcher(origCallerIdName); Matcher callWithSess = CALLERNAME_WITH_SESS_INFO_PATTERN.matcher(origCallerIdName);
@ -437,6 +450,7 @@ public class ESLEventListener implements IEslEventListener {
coreuuid, coreuuid,
clientSession, clientSession,
voiceUserId, voiceUserId,
memberIdStr,
callerName, callerName,
callState, callState,
origCallerIdName, origCallerIdName,

View File

@ -229,6 +229,7 @@ class VoiceConferenceService(healthz: HealthzService,
callSession: String, callSession: String,
clientSession: String, clientSession: String,
userId: String, userId: String,
voiceUserId: String,
callerName: String, callerName: String,
callState: String, callState: String,
origCallerIdName: String, origCallerIdName: String,
@ -240,6 +241,7 @@ class VoiceConferenceService(healthz: HealthzService,
callSession = callSession, callSession = callSession,
clientSession = clientSession, clientSession = clientSession,
userId = userId, userId = userId,
voiceUserId = voiceUserId,
callerName = callerName, callerName = callerName,
callState = callState, callState = callState,
origCallerIdName = origCallerIdName, origCallerIdName = origCallerIdName,

View File

@ -49,7 +49,8 @@ case class UsersProp(
meetingLayout: String, meetingLayout: String,
allowModsToUnmuteUsers: Boolean, allowModsToUnmuteUsers: Boolean,
allowModsToEjectCameras: Boolean, allowModsToEjectCameras: Boolean,
authenticatedGuest: Boolean authenticatedGuest: Boolean,
allowPromoteGuestToModerator: Boolean
) )
case class MetadataProp(metadata: collection.immutable.Map[String, String]) case class MetadataProp(metadata: collection.immutable.Map[String, String])
@ -114,8 +115,8 @@ case class UserVO(id: String, externalId: String, name: String, role: String,
guest: Boolean, authed: Boolean, guestStatus: String, emojiStatus: String, guest: Boolean, authed: Boolean, guestStatus: String, emojiStatus: String,
presenter: Boolean, hasStream: Boolean, locked: Boolean, webcamStreams: Set[String], presenter: Boolean, hasStream: Boolean, locked: Boolean, webcamStreams: Set[String],
phoneUser: Boolean, voiceUser: VoiceUserVO, listenOnly: Boolean, avatarURL: String, phoneUser: Boolean, voiceUser: VoiceUserVO, listenOnly: Boolean, avatarURL: String,
joinedWeb: Boolean) webcamBackgroundURL: String, joinedWeb: Boolean)
case class VoiceUserVO(userId: String, webUserId: String, callerName: String, case class VoiceUserVO(userId: String, webUserId: String, callerName: String,
callerNum: String, joined: Boolean, locked: Boolean, muted: Boolean, callerNum: String, joined: Boolean, locked: Boolean, muted: Boolean,
talking: Boolean, avatarURL: String, listenOnly: Boolean) talking: Boolean, avatarURL: String, webcamBackgroundURL: String, listenOnly: Boolean)

View File

@ -1,5 +1,12 @@
package org.bigbluebutton.common2.msgs package org.bigbluebutton.common2.msgs
object TranscriptionProviderErrorMsg { val NAME = "TranscriptionProviderErrorMsg" }
case class TranscriptionProviderErrorMsg(header: BbbClientMsgHeader, body: TranscriptionProviderErrorMsgBody) extends StandardMsg
case class TranscriptionProviderErrorMsgBody(
errorCode: String,
errorMessage: String,
)
// In messages // In messages
object UpdateTranscriptPubMsg { val NAME = "UpdateTranscriptPubMsg" } object UpdateTranscriptPubMsg { val NAME = "UpdateTranscriptPubMsg" }
case class UpdateTranscriptPubMsg(header: BbbClientMsgHeader, body: UpdateTranscriptPubMsgBody) extends StandardMsg case class UpdateTranscriptPubMsg(header: BbbClientMsgHeader, body: UpdateTranscriptPubMsgBody) extends StandardMsg
@ -14,6 +21,10 @@ case class UpdateTranscriptPubMsgBody(
) )
// Out messages // Out messages
object TranscriptionProviderErrorEvtMsg { val NAME = "TranscriptionProviderErrorEvtMsg" }
case class TranscriptionProviderErrorEvtMsg(header: BbbClientMsgHeader, body: TranscriptionProviderErrorEvtMsgBody) extends BbbCoreMsg
case class TranscriptionProviderErrorEvtMsgBody(errorCode: String, errorMessage: String)
object TranscriptUpdatedEvtMsg { val NAME = "TranscriptUpdatedEvtMsg" } object TranscriptUpdatedEvtMsg { val NAME = "TranscriptUpdatedEvtMsg" }
case class TranscriptUpdatedEvtMsg(header: BbbClientMsgHeader, body: TranscriptUpdatedEvtMsgBody) extends BbbCoreMsg case class TranscriptUpdatedEvtMsg(header: BbbClientMsgHeader, body: TranscriptUpdatedEvtMsgBody) extends BbbCoreMsg
case class TranscriptUpdatedEvtMsgBody(transcriptId: String, transcript: String, locale: String, result: Boolean) case class TranscriptUpdatedEvtMsgBody(transcriptId: String, transcript: String, locale: String, result: Boolean)

View File

@ -57,6 +57,7 @@ case class BreakoutRoomDetail(
viewerPassword: String, viewerPassword: String,
sourcePresentationId: String, sourcePresentationId: String,
sourcePresentationSlide: Int, sourcePresentationSlide: Int,
sourcePresentationFilename: String,
record: Boolean, record: Boolean,
privateChatEnabled: Boolean, privateChatEnabled: Boolean,
captureNotes: Boolean, captureNotes: Boolean,
@ -71,7 +72,7 @@ case class BreakoutRoomDetail(
object CreateBreakoutRoomsCmdMsg { val NAME = "CreateBreakoutRoomsCmdMsg" } object CreateBreakoutRoomsCmdMsg { val NAME = "CreateBreakoutRoomsCmdMsg" }
case class CreateBreakoutRoomsCmdMsg(header: BbbClientMsgHeader, body: CreateBreakoutRoomsCmdMsgBody) extends StandardMsg case class CreateBreakoutRoomsCmdMsg(header: BbbClientMsgHeader, body: CreateBreakoutRoomsCmdMsgBody) extends StandardMsg
case class CreateBreakoutRoomsCmdMsgBody(meetingId: String, durationInMinutes: Int, record: Boolean, captureNotes: Boolean, captureSlides: Boolean, rooms: Vector[BreakoutRoomMsgBody], sendInviteToModerators: Boolean) case class CreateBreakoutRoomsCmdMsgBody(meetingId: String, durationInMinutes: Int, record: Boolean, captureNotes: Boolean, captureSlides: Boolean, rooms: Vector[BreakoutRoomMsgBody], sendInviteToModerators: Boolean)
case class BreakoutRoomMsgBody(name: String, sequence: Int, shortName: String, captureNotesFilename: String, captureSlidesFilename: String, isDefaultName: Boolean, freeJoin: Boolean, users: Vector[String]) case class BreakoutRoomMsgBody(name: String, sequence: Int, shortName: String, captureNotesFilename: String, captureSlidesFilename: String, isDefaultName: Boolean, freeJoin: Boolean, users: Vector[String], allPages: Boolean, presId: String, sourcePresentationFilename: String)
// Sent by user to request ending all the breakout rooms // Sent by user to request ending all the breakout rooms
object EndAllBreakoutRoomsMsg { val NAME = "EndAllBreakoutRoomsMsg" } object EndAllBreakoutRoomsMsg { val NAME = "EndAllBreakoutRoomsMsg" }

View File

@ -107,7 +107,7 @@ case class PadTailEvtMsgBody(externalId: String, tail: String)
// client -> apps // client -> apps
object PadUpdatePubMsg { val NAME = "PadUpdatePubMsg" } object PadUpdatePubMsg { val NAME = "PadUpdatePubMsg" }
case class PadUpdatePubMsg(header: BbbClientMsgHeader, body: PadUpdatePubMsgBody) extends StandardMsg case class PadUpdatePubMsg(header: BbbClientMsgHeader, body: PadUpdatePubMsgBody) extends StandardMsg
case class PadUpdatePubMsgBody(externalId: String, text: String) case class PadUpdatePubMsgBody(externalId: String, text: String, transcript: Boolean)
// apps -> pads // apps -> pads
object PadUpdateCmdMsg { val NAME = "PadUpdateCmdMsg" } object PadUpdateCmdMsg { val NAME = "PadUpdateCmdMsg" }

View File

@ -6,8 +6,9 @@ case class RegisterUserReqMsg(
body: RegisterUserReqMsgBody body: RegisterUserReqMsgBody
) extends BbbCoreMsg ) extends BbbCoreMsg
case class RegisterUserReqMsgBody(meetingId: String, intUserId: String, name: String, role: String, case class RegisterUserReqMsgBody(meetingId: String, intUserId: String, name: String, role: String,
extUserId: String, authToken: String, avatarURL: String, extUserId: String, authToken: String, avatarURL: String, webcamBackgroundURL: String,
guest: Boolean, authed: Boolean, guestStatus: String, excludeFromDashboard: Boolean) guest: Boolean, authed: Boolean, guestStatus: String, excludeFromDashboard: Boolean,
userCustomData: Map[String, AnyRef])
object UserRegisteredRespMsg { val NAME = "UserRegisteredRespMsg" } object UserRegisteredRespMsg { val NAME = "UserRegisteredRespMsg" }
case class UserRegisteredRespMsg( case class UserRegisteredRespMsg(
@ -104,8 +105,10 @@ case class UserJoinedMeetingEvtMsgBody(
presenter: Boolean, presenter: Boolean,
locked: Boolean, locked: Boolean,
avatar: String, avatar: String,
webcamBackground: String,
color: String, color: String,
clientType: String clientType: String,
userCustomData: Map[String, String]
) )
/** /**
@ -345,6 +348,20 @@ object UserLockedInMeetingEvtMsg { val NAME = "UserLockedInMeetingEvtMsg" }
case class UserLockedInMeetingEvtMsg(header: BbbClientMsgHeader, body: UserLockedInMeetingEvtMsgBody) extends BbbCoreMsg case class UserLockedInMeetingEvtMsg(header: BbbClientMsgHeader, body: UserLockedInMeetingEvtMsgBody) extends BbbCoreMsg
case class UserLockedInMeetingEvtMsgBody(userId: String, locked: Boolean, lockedBy: String) case class UserLockedInMeetingEvtMsgBody(userId: String, locked: Boolean, lockedBy: String)
/**
* Sent from client to lock user in meeting.
*/
object LockUserChatInMeetingCmdMsg { val NAME = "LockUserChatInMeetingCmdMsg" }
case class LockUserChatInMeetingCmdMsg(header: BbbClientMsgHeader, body: LockUserChatInMeetingCmdMsgBody) extends StandardMsg
case class LockUserChatInMeetingCmdMsgBody(userId: String, isLocked: Boolean, lockedBy: String)
/**
* Send to client that user has been locked.
*/
object LockUserChatInMeetingEvtMsg { val NAME = "LockUserChatInMeetingEvtMsg" }
case class LockUserChatInMeetingEvtMsg(header: BbbClientMsgHeader, body: LockUserChatInMeetingEvtMsgBody) extends BbbCoreMsg
case class LockUserChatInMeetingEvtMsgBody(userId: String, isLocked: Boolean)
/** /**
* Sent by client to lock users. * Sent by client to lock users.
*/ */
@ -531,3 +548,11 @@ case class SetUserSpeechLocaleReqMsgBody(locale: String, provider: String)
object UserSpeechLocaleChangedEvtMsg { val NAME = "UserSpeechLocaleChangedEvtMsg" } object UserSpeechLocaleChangedEvtMsg { val NAME = "UserSpeechLocaleChangedEvtMsg" }
case class UserSpeechLocaleChangedEvtMsg(header: BbbClientMsgHeader, body: UserSpeechLocaleChangedEvtMsgBody) extends BbbCoreMsg case class UserSpeechLocaleChangedEvtMsg(header: BbbClientMsgHeader, body: UserSpeechLocaleChangedEvtMsgBody) extends BbbCoreMsg
case class UserSpeechLocaleChangedEvtMsgBody(locale: String, provider: String) case class UserSpeechLocaleChangedEvtMsgBody(locale: String, provider: String)
object SetUserSpeechOptionsReqMsg { val NAME = "SetUserSpeechOptionsReqMsg" }
case class SetUserSpeechOptionsReqMsg(header: BbbClientMsgHeader, body: SetUserSpeechOptionsReqMsgBody) extends StandardMsg
case class SetUserSpeechOptionsReqMsgBody(partialUtterances: Boolean, minUtteranceLength: Int)
object UserSpeechOptionsChangedEvtMsg { val NAME = "UserSpeechOptionsChangedEvtMsg" }
case class UserSpeechOptionsChangedEvtMsg(header: BbbClientMsgHeader, body: UserSpeechOptionsChangedEvtMsgBody) extends BbbCoreMsg
case class UserSpeechOptionsChangedEvtMsgBody(partialUtterances: Boolean, minUtteranceLength: Int)

View File

@ -555,6 +555,7 @@ case class VoiceConfCallStateEvtMsgBody(
callSession: String, callSession: String,
clientSession: String, clientSession: String,
userId: String, userId: String,
voiceUserId: String,
callerName: String, callerName: String,
callState: String, callState: String,
origCallerIdName: String, origCallerIdName: String,
@ -685,6 +686,7 @@ case class ToggleListenOnlyModeSysMsg(
case class ToggleListenOnlyModeSysMsgBody( case class ToggleListenOnlyModeSysMsgBody(
voiceConf: String, voiceConf: String,
userId: String, userId: String,
callerNum: String,
enabled: Boolean enabled: Boolean
) )
@ -701,5 +703,6 @@ case class ListenOnlyModeToggledInSfuEvtMsgBody(
meetingId: String, meetingId: String,
voiceConf: String, voiceConf: String,
userId: String, userId: String,
callerNum: String,
enabled: Boolean enabled: Boolean
) )

View File

@ -44,6 +44,7 @@ trait TestFixtures {
val keepEvents = false val keepEvents = false
val guestPolicy = "ALWAYS_ASK" val guestPolicy = "ALWAYS_ASK"
val authenticatedGuest = false val authenticatedGuest = false
val allowPromoteGuestToModerator = false
val metadata: collection.immutable.Map[String, String] = Map("foo" -> "bar", "bar" -> "baz", "baz" -> "foo") val metadata: collection.immutable.Map[String, String] = Map("foo" -> "bar", "bar" -> "baz", "baz" -> "foo")
val captureNotesFilename = s"Room 0${sequence} (Notes)" val captureNotesFilename = s"Room 0${sequence} (Notes)"
val captureSlidesFilename = s"Room 0${sequence} (Whiteboard)" val captureSlidesFilename = s"Room 0${sequence} (Whiteboard)"
@ -71,7 +72,8 @@ trait TestFixtures {
val voiceProp = VoiceProp(telVoice = voiceConfId, voiceConf = voiceConfId, dialNumber = dialNumber, muteOnStart = muteOnStart) val voiceProp = VoiceProp(telVoice = voiceConfId, voiceConf = voiceConfId, dialNumber = dialNumber, muteOnStart = muteOnStart)
val usersProp = UsersProp(maxUsers = maxUsers, webcamsOnlyForModerator = webcamsOnlyForModerator, val usersProp = UsersProp(maxUsers = maxUsers, webcamsOnlyForModerator = webcamsOnlyForModerator,
userCameraCap = userCameraCap, userCameraCap = userCameraCap,
guestPolicy = guestPolicy, allowModsToUnmuteUsers = allowModsToUnmuteUsers, allowModsToEjectCameras = allowModsToEjectCameras, authenticatedGuest = authenticatedGuest) guestPolicy = guestPolicy, allowModsToUnmuteUsers = allowModsToUnmuteUsers, allowModsToEjectCameras = allowModsToEjectCameras,
authenticatedGuest = authenticatedGuest, allowPromoteGuestToModerator = allowPromoteGuestToModerator)
val metadataProp = new MetadataProp(metadata) val metadataProp = new MetadataProp(metadata)
val defaultProps = DefaultProps(meetingProp, breakoutProps, durationProps, password, recordProp, welcomeProp, voiceProp, val defaultProps = DefaultProps(meetingProp, breakoutProps, durationProps, password, recordProp, welcomeProp, voiceProp,
usersProp, metadataProp) usersProp, metadataProp)

View File

@ -103,14 +103,16 @@ homepage := Some(url("http://www.bigbluebutton.org"))
libraryDependencies ++= Seq( libraryDependencies ++= Seq(
"javax.validation" % "validation-api" % "2.0.1.Final", "javax.validation" % "validation-api" % "2.0.1.Final",
"org.springframework.boot" % "spring-boot-starter-validation" % "2.7.12", "org.springframework.boot" % "spring-boot-starter-validation" % "2.7.17",
"org.springframework.data" % "spring-data-commons" % "2.7.6", "org.springframework.data" % "spring-data-commons" % "2.7.6",
"org.apache.httpcomponents" % "httpclient" % "4.5.13", "org.apache.httpcomponents" % "httpclient" % "4.5.13",
"org.postgresql" % "postgresql" % "42.4.3", "org.postgresql" % "postgresql" % "42.7.2",
"org.hibernate" % "hibernate-core" % "5.6.1.Final", "org.hibernate" % "hibernate-core" % "5.6.1.Final",
"org.flywaydb" % "flyway-core" % "7.8.2", "org.flywaydb" % "flyway-core" % "7.8.2",
"com.zaxxer" % "HikariCP" % "4.0.3", "com.zaxxer" % "HikariCP" % "4.0.3",
"commons-validator" % "commons-validator" % "1.7", "commons-validator" % "commons-validator" % "1.7",
"org.apache.tika" % "tika-core" % "2.8.0", "org.apache.tika" % "tika-core" % "2.8.0",
"org.apache.tika" % "tika-parsers-standard-package" % "2.8.0" "org.apache.tika" % "tika-parsers-standard-package" % "2.8.0",
"org.scala-lang.modules" %% "scala-xml" % "2.2.0",
"jakarta.ws.rs" % "jakarta.ws.rs-api" % "3.1.0"
) )

View File

@ -33,6 +33,7 @@ public class ApiParams {
public static final String FREE_JOIN = "freeJoin"; public static final String FREE_JOIN = "freeJoin";
public static final String FULL_NAME = "fullName"; public static final String FULL_NAME = "fullName";
public static final String GUEST_POLICY = "guestPolicy"; public static final String GUEST_POLICY = "guestPolicy";
public static final String ALLOW_PROMOTE_GUEST_TO_MODERATOR = "allowPromoteGuestToModerator";
public static final String MEETING_LAYOUT = "meetingLayout"; public static final String MEETING_LAYOUT = "meetingLayout";
public static final String IS_BREAKOUT = "isBreakout"; public static final String IS_BREAKOUT = "isBreakout";
public static final String LOGO = "logo"; public static final String LOGO = "logo";

View File

@ -126,10 +126,10 @@ public class MeetingService implements MessageListener {
public void registerUser(String meetingID, String internalUserId, public void registerUser(String meetingID, String internalUserId,
String fullname, String role, String externUserID, String fullname, String role, String externUserID,
String authToken, String avatarURL, Boolean guest, String authToken, String avatarURL, String webcamBackgroundURL, Boolean guest,
Boolean authed, String guestStatus, Boolean excludeFromDashboard, Boolean leftGuestLobby) { Boolean authed, String guestStatus, Boolean excludeFromDashboard, Boolean leftGuestLobby) {
handle(new RegisterUser(meetingID, internalUserId, fullname, role, handle(new RegisterUser(meetingID, internalUserId, fullname, role,
externUserID, authToken, avatarURL, guest, authed, guestStatus, excludeFromDashboard, leftGuestLobby)); externUserID, authToken, avatarURL, webcamBackgroundURL, guest, authed, guestStatus, excludeFromDashboard, leftGuestLobby));
Meeting m = getMeeting(meetingID); Meeting m = getMeeting(meetingID);
if (m != null) { if (m != null) {
@ -401,10 +401,12 @@ public class MeetingService implements MessageListener {
gw.createMeeting(m.getInternalId(), m.getExternalId(), m.getParentMeetingId(), m.getName(), m.isRecord(), gw.createMeeting(m.getInternalId(), m.getExternalId(), m.getParentMeetingId(), m.getName(), m.isRecord(),
m.getTelVoice(), m.getDuration(), m.getAutoStartRecording(), m.getAllowStartStopRecording(), m.getTelVoice(), m.getDuration(), m.getAutoStartRecording(), m.getAllowStartStopRecording(),
m.getRecordFullDurationMedia(), m.getRecordFullDurationMedia(),
m.getWebcamsOnlyForModerator(), m.getMeetingCameraCap(), m.getUserCameraCap(), m.getMaxPinnedCameras(), m.getModeratorPassword(), m.getViewerPassword(), m.getWebcamsOnlyForModerator(), m.getMeetingCameraCap(), m.getUserCameraCap(), m.getMaxPinnedCameras(),
m.getModeratorPassword(), m.getViewerPassword(),
m.getLearningDashboardAccessToken(), m.getCreateTime(), m.getLearningDashboardAccessToken(), m.getCreateTime(),
formatPrettyDate(m.getCreateTime()), m.isBreakout(), m.getSequence(), m.isFreeJoin(), m.getMetadata(), formatPrettyDate(m.getCreateTime()), m.isBreakout(), m.getSequence(), m.isFreeJoin(), m.getMetadata(),
m.getGuestPolicy(), m.getAuthenticatedGuest(), m.getMeetingLayout(), m.getWelcomeMessageTemplate(), m.getWelcomeMessage(), m.getModeratorOnlyMessage(), m.getGuestPolicy(), m.getAuthenticatedGuest(), m.getAllowPromoteGuestToModerator(), m.getMeetingLayout(),
m.getWelcomeMessageTemplate(), m.getWelcomeMessage(), m.getModeratorOnlyMessage(),
m.getDialNumber(), m.getMaxUsers(), m.getMaxUserConcurrentAccesses(), m.getDialNumber(), m.getMaxUsers(), m.getMaxUserConcurrentAccesses(),
m.getMeetingExpireIfNoUserJoinedInMinutes(), m.getMeetingExpireWhenLastUserLeftInMinutes(), m.getMeetingExpireIfNoUserJoinedInMinutes(), m.getMeetingExpireWhenLastUserLeftInMinutes(),
m.getUserInactivityInspectTimerInMinutes(), m.getUserInactivityThresholdInMinutes(), m.getUserInactivityInspectTimerInMinutes(), m.getUserInactivityThresholdInMinutes(),
@ -424,10 +426,19 @@ public class MeetingService implements MessageListener {
} }
private void processRegisterUser(RegisterUser message) { private void processRegisterUser(RegisterUser message) {
Map<String, Object> userCustomData = null;
Meeting meeting = meetings.get(message.meetingID);
if (meeting != null) {
userCustomData = meeting.getUserCustomData(message.externUserID);
}
if (userCustomData == null) {
userCustomData = new HashMap<>();
}
gw.registerUser(message.meetingID, gw.registerUser(message.meetingID,
message.internalUserId, message.fullname, message.role, message.internalUserId, message.fullname, message.role,
message.externUserID, message.authToken, message.avatarURL, message.guest, message.externUserID, message.authToken, message.avatarURL, message.webcamBackgroundURL, message.guest,
message.authed, message.guestStatus, message.excludeFromDashboard); message.authed, message.guestStatus, message.excludeFromDashboard, userCustomData);
} }
public Meeting getMeeting(String meetingId) { public Meeting getMeeting(String meetingId) {
@ -660,7 +671,9 @@ public class MeetingService implements MessageListener {
presDownloadService.extractPresentationPage(message.parentMeetingId, presDownloadService.extractPresentationPage(message.parentMeetingId,
message.sourcePresentationId, message.sourcePresentationId,
message.sourcePresentationSlide, breakout.getInternalId()); message.sourcePresentationSlide,
breakout.getInternalId(),
message.sourcePresentationFilename);
} else { } else {
Map<String, Object> logData = new HashMap<String, Object>(); Map<String, Object> logData = new HashMap<String, Object>();
logData.put("meetingId", message.meetingId); logData.put("meetingId", message.meetingId);
@ -922,7 +935,7 @@ public class MeetingService implements MessageListener {
} }
User user = new User(message.userId, message.externalUserId, User user = new User(message.userId, message.externalUserId,
message.name, message.role, message.avatarURL, message.guest, message.guestStatus, message.name, message.role, message.avatarURL, message.webcamBackgroundURL, message.guest, message.guestStatus,
message.clientType); message.clientType);
if(m.getMaxUsers() > 0 && m.countUniqueExtIds() >= m.getMaxUsers()) { if(m.getMaxUsers() > 0 && m.countUniqueExtIds() >= m.getMaxUsers()) {
@ -1042,7 +1055,7 @@ public class MeetingService implements MessageListener {
} else { } else {
if (message.userId.startsWith("v_")) { if (message.userId.startsWith("v_")) {
// A dial-in user joined the meeting. Dial-in users by convention has userId that starts with "v_". // A dial-in user joined the meeting. Dial-in users by convention has userId that starts with "v_".
User vuser = new User(message.userId, message.userId, message.name, "DIAL-IN-USER", "", User vuser = new User(message.userId, message.userId, message.name, "DIAL-IN-USER", "", "",
true, GuestPolicy.ALLOW, "DIAL-IN"); true, GuestPolicy.ALLOW, "DIAL-IN");
vuser.setVoiceJoined(true); vuser.setVoiceJoined(true);
m.userJoined(vuser); m.userJoined(vuser);

View File

@ -84,8 +84,11 @@ public class ParamsProcessorUtil {
private Integer defaultHttpSessionTimeout = 14400; private Integer defaultHttpSessionTimeout = 14400;
private Boolean useDefaultAvatar = false; private Boolean useDefaultAvatar = false;
private String defaultAvatarURL; private String defaultAvatarURL;
private Boolean useDefaultWebcamBackground = false;
private String defaultWebcamBackgroundURL;
private String defaultGuestPolicy; private String defaultGuestPolicy;
private Boolean authenticatedGuest; private Boolean authenticatedGuest;
private Boolean defaultAllowPromoteGuestToModerator;
private String defaultMeetingLayout; private String defaultMeetingLayout;
private int defaultMeetingDuration; private int defaultMeetingDuration;
private boolean disableRecordingDefault; private boolean disableRecordingDefault;
@ -678,6 +681,11 @@ public class ParamsProcessorUtil {
guestPolicy = params.get(ApiParams.GUEST_POLICY); guestPolicy = params.get(ApiParams.GUEST_POLICY);
} }
Boolean allowPromoteGuestToModerator = defaultAllowPromoteGuestToModerator;
if (!StringUtils.isEmpty(params.get(ApiParams.ALLOW_PROMOTE_GUEST_TO_MODERATOR))) {
allowPromoteGuestToModerator = Boolean.parseBoolean(params.get(ApiParams.ALLOW_PROMOTE_GUEST_TO_MODERATOR));
}
String presentationUploadExternalDescription = defaultPresentationUploadExternalDescription; String presentationUploadExternalDescription = defaultPresentationUploadExternalDescription;
if (!StringUtils.isEmpty(params.get(ApiParams.PRESENTATION_UPLOAD_EXTERNAL_DESCRIPTION))) { if (!StringUtils.isEmpty(params.get(ApiParams.PRESENTATION_UPLOAD_EXTERNAL_DESCRIPTION))) {
presentationUploadExternalDescription = params.get(ApiParams.PRESENTATION_UPLOAD_EXTERNAL_DESCRIPTION); presentationUploadExternalDescription = params.get(ApiParams.PRESENTATION_UPLOAD_EXTERNAL_DESCRIPTION);
@ -735,6 +743,7 @@ public class ParamsProcessorUtil {
} }
String avatarURL = useDefaultAvatar ? defaultAvatarURL : ""; String avatarURL = useDefaultAvatar ? defaultAvatarURL : "";
String webcamBackgroundURL = useDefaultWebcamBackground ? defaultWebcamBackgroundURL : "";
int html5InstanceId = processHtml5InstanceId(params.get(ApiParams.HTML5_INSTANCE_ID)); int html5InstanceId = processHtml5InstanceId(params.get(ApiParams.HTML5_INSTANCE_ID));
@ -754,6 +763,7 @@ public class ParamsProcessorUtil {
.withTelVoice(telVoice).withWebVoice(webVoice) .withTelVoice(telVoice).withWebVoice(webVoice)
.withDialNumber(dialNumber) .withDialNumber(dialNumber)
.withDefaultAvatarURL(avatarURL) .withDefaultAvatarURL(avatarURL)
.withDefaultWebcamBackgroundURL(webcamBackgroundURL)
.withAutoStartRecording(autoStartRec) .withAutoStartRecording(autoStartRec)
.withAllowStartStopRecording(allowStartStoptRec) .withAllowStartStopRecording(allowStartStoptRec)
.withRecordFullDurationMedia(_recordFullDurationMedia) .withRecordFullDurationMedia(_recordFullDurationMedia)
@ -766,6 +776,7 @@ public class ParamsProcessorUtil {
.withWelcomeMessage(welcomeMessage).isBreakout(isBreakout) .withWelcomeMessage(welcomeMessage).isBreakout(isBreakout)
.withGuestPolicy(guestPolicy) .withGuestPolicy(guestPolicy)
.withAuthenticatedGuest(authenticatedGuest) .withAuthenticatedGuest(authenticatedGuest)
.withAllowPromoteGuestToModerator(allowPromoteGuestToModerator)
.withAllowRequestsWithoutSession(allowRequestsWithoutSession) .withAllowRequestsWithoutSession(allowRequestsWithoutSession)
.withMeetingLayout(meetingLayout) .withMeetingLayout(meetingLayout)
.withBreakoutRoomsParams(breakoutParams) .withBreakoutRoomsParams(breakoutParams)
@ -1156,6 +1167,11 @@ public class ParamsProcessorUtil {
return true; return true;
} }
public boolean parentMeetingExists(String parentMeetingId) {
Meeting meeting = ServiceUtils.findMeetingFromMeetingID(parentMeetingId);
return meeting != null;
}
/************************************************* /*************************************************
* Setters * Setters
************************************************/ ************************************************/
@ -1284,6 +1300,14 @@ public class ParamsProcessorUtil {
this.defaultAvatarURL = url; this.defaultAvatarURL = url;
} }
public void setUseDefaultWebcamBackground(Boolean value) {
this.useDefaultWebcamBackground = value;
}
public void setDefaultWebcamBackgroundURL(String uri) {
this.defaultWebcamBackgroundURL = uri;
}
public void setDefaultGuestPolicy(String guestPolicy) { public void setDefaultGuestPolicy(String guestPolicy) {
this.defaultGuestPolicy = guestPolicy; this.defaultGuestPolicy = guestPolicy;
} }
@ -1292,6 +1316,10 @@ public class ParamsProcessorUtil {
this.authenticatedGuest = value; this.authenticatedGuest = value;
} }
public void setDefaultAllowPromoteGuestToModerator(Boolean value) {
this.defaultAllowPromoteGuestToModerator = value;
}
public void setDefaultMeetingLayout(String meetingLayout) { public void setDefaultMeetingLayout(String meetingLayout) {
this.defaultMeetingLayout = meetingLayout; this.defaultMeetingLayout = meetingLayout;
} }

View File

@ -2,11 +2,14 @@ package org.bigbluebutton.api;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.UUID; import java.util.UUID;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
public final class Util { public final class Util {
@ -50,8 +53,19 @@ public final class Util {
return DigestUtils.sha1Hex(presFilename + uuid) + "-" + timestamp; return DigestUtils.sha1Hex(presFilename + uuid) + "-" + timestamp;
} }
public static String extractFilenameFromUrl(String preUploadedPresentation) throws MalformedURLException {
URL url = new URL(preUploadedPresentation);
String filename = FilenameUtils.getName(url.getPath());
String extension = FilenameUtils.getExtension(url.getPath());
if (extension == null || extension.isEmpty()) return null;
return filename;
}
public static String createNewFilename(String presId, String fileExt) { public static String createNewFilename(String presId, String fileExt) {
if (!fileExt.isEmpty()) {
return presId + "." + fileExt; return presId + "." + fileExt;
} else {
return presId;
}
} }
public static File createPresentationDir(String meetingId, String presentationDir, String presentationId) { public static File createPresentationDir(String meetingId, String presentationDir, String presentationId) {

View File

@ -79,10 +79,12 @@ public class Meeting {
private Integer maxPinnedCameras = 0; private Integer maxPinnedCameras = 0;
private String dialNumber; private String dialNumber;
private String defaultAvatarURL; private String defaultAvatarURL;
private String defaultWebcamBackgroundURL;
private String guestPolicy = GuestPolicy.ASK_MODERATOR; private String guestPolicy = GuestPolicy.ASK_MODERATOR;
private String guestLobbyMessage = ""; private String guestLobbyMessage = "";
private Map<String,String> usersWithGuestLobbyMessages; private Map<String,String> usersWithGuestLobbyMessages;
private Boolean authenticatedGuest = false; private Boolean authenticatedGuest = false;
private Boolean allowPromoteGuestToModerator = false;
private String meetingLayout = MeetingLayout.SMART_LAYOUT; private String meetingLayout = MeetingLayout.SMART_LAYOUT;
private boolean userHasJoined = false; private boolean userHasJoined = false;
private Map<String, String> guestUsersWithPositionInWaitingLine; private Map<String, String> guestUsersWithPositionInWaitingLine;
@ -147,6 +149,7 @@ public class Meeting {
logoutUrl = builder.logoutUrl; logoutUrl = builder.logoutUrl;
logoutTimer = builder.logoutTimer; logoutTimer = builder.logoutTimer;
defaultAvatarURL = builder.defaultAvatarURL; defaultAvatarURL = builder.defaultAvatarURL;
defaultWebcamBackgroundURL = builder.defaultWebcamBackgroundURL;
record = builder.record; record = builder.record;
autoStartRecording = builder.autoStartRecording; autoStartRecording = builder.autoStartRecording;
allowStartStopRecording = builder.allowStartStopRecording; allowStartStopRecording = builder.allowStartStopRecording;
@ -166,6 +169,7 @@ public class Meeting {
isBreakout = builder.isBreakout; isBreakout = builder.isBreakout;
guestPolicy = builder.guestPolicy; guestPolicy = builder.guestPolicy;
authenticatedGuest = builder.authenticatedGuest; authenticatedGuest = builder.authenticatedGuest;
allowPromoteGuestToModerator = builder.allowPromoteGuestToModerator;
meetingLayout = builder.meetingLayout; meetingLayout = builder.meetingLayout;
allowRequestsWithoutSession = builder.allowRequestsWithoutSession; allowRequestsWithoutSession = builder.allowRequestsWithoutSession;
breakoutRoomsParams = builder.breakoutRoomsParams; breakoutRoomsParams = builder.breakoutRoomsParams;
@ -460,6 +464,10 @@ public class Meeting {
return defaultAvatarURL; return defaultAvatarURL;
} }
public String getDefaultWebcamBackgroundURL() {
return defaultWebcamBackgroundURL;
}
public void setWaitingPositionsInWaitingQueue(HashMap<String, String> guestUsersWithPositionInWaitingLine) { public void setWaitingPositionsInWaitingQueue(HashMap<String, String> guestUsersWithPositionInWaitingLine) {
this.guestUsersWithPositionInWaitingLine = guestUsersWithPositionInWaitingLine; this.guestUsersWithPositionInWaitingLine = guestUsersWithPositionInWaitingLine;
} }
@ -499,6 +507,14 @@ public class Meeting {
return authenticatedGuest; return authenticatedGuest;
} }
public void setAllowPromoteGuestToModerator(Boolean value) {
allowPromoteGuestToModerator = value;
}
public Boolean getAllowPromoteGuestToModerator() {
return allowPromoteGuestToModerator;
}
public void setMeetingLayout(String layout) { public void setMeetingLayout(String layout) {
meetingLayout = layout; meetingLayout = layout;
} }
@ -899,10 +915,12 @@ public class Meeting {
private Map<String, String> metadata; private Map<String, String> metadata;
private String dialNumber; private String dialNumber;
private String defaultAvatarURL; private String defaultAvatarURL;
private String defaultWebcamBackgroundURL;
private long createdTime; private long createdTime;
private boolean isBreakout; private boolean isBreakout;
private String guestPolicy; private String guestPolicy;
private Boolean authenticatedGuest; private Boolean authenticatedGuest;
private Boolean allowPromoteGuestToModerator;
private Boolean allowRequestsWithoutSession; private Boolean allowRequestsWithoutSession;
private String meetingLayout; private String meetingLayout;
private BreakoutRoomsParams breakoutRoomsParams; private BreakoutRoomsParams breakoutRoomsParams;
@ -1045,6 +1063,11 @@ public class Meeting {
return this; return this;
} }
public Builder withDefaultWebcamBackgroundURL(String w) {
defaultWebcamBackgroundURL = w;
return this;
}
public Builder isBreakout(Boolean b) { public Builder isBreakout(Boolean b) {
isBreakout = b; isBreakout = b;
return this; return this;
@ -1085,6 +1108,11 @@ public class Meeting {
return this; return this;
} }
public Builder withAllowPromoteGuestToModerator(Boolean value) {
allowPromoteGuestToModerator = value;
return this;
}
public Builder withAllowRequestsWithoutSession(Boolean value) { public Builder withAllowRequestsWithoutSession(Boolean value) {
allowRequestsWithoutSession = value; allowRequestsWithoutSession = value;
return this; return this;

View File

@ -31,6 +31,7 @@ public class User {
private String fullname; private String fullname;
private String role; private String role;
private String avatarURL; private String avatarURL;
private String webcamBackgroundURL;
private Map<String,String> status; private Map<String,String> status;
private Boolean guest; private Boolean guest;
private String guestStatus; private String guestStatus;
@ -45,6 +46,7 @@ public class User {
String fullname, String fullname,
String role, String role,
String avatarURL, String avatarURL,
String webcamBackgroundURL,
Boolean guest, Boolean guest,
String guestStatus, String guestStatus,
String clientType) { String clientType) {
@ -53,6 +55,7 @@ public class User {
this.fullname = fullname; this.fullname = fullname;
this.role = role; this.role = role;
this.avatarURL = avatarURL; this.avatarURL = avatarURL;
this.webcamBackgroundURL = webcamBackgroundURL;
this.guest = guest; this.guest = guest;
this.guestStatus = guestStatus; this.guestStatus = guestStatus;
this.status = new ConcurrentHashMap<>(); this.status = new ConcurrentHashMap<>();
@ -128,6 +131,14 @@ public class User {
this.avatarURL = avatarURL; this.avatarURL = avatarURL;
} }
public String getWebcamBackgroundUrl() {
return webcamBackgroundURL;
}
public void setWebcamBackgroundUrl(String webcamBackgroundURL) {
this.webcamBackgroundURL = webcamBackgroundURL;
}
public boolean isModerator() { public boolean isModerator() {
return "MODERATOR".equalsIgnoreCase(this.role); return "MODERATOR".equalsIgnoreCase(this.role);
} }

View File

@ -42,6 +42,7 @@ public class UserSession {
public String logoutUrl = null; public String logoutUrl = null;
public String defaultLayout = "NOLAYOUT"; public String defaultLayout = "NOLAYOUT";
public String avatarURL; public String avatarURL;
public String webcamBackgroundURL;
public String guestStatus = GuestPolicy.ALLOW; public String guestStatus = GuestPolicy.ALLOW;
public String clientUrl = null; public String clientUrl = null;
public Boolean excludeFromDashboard = false; public Boolean excludeFromDashboard = false;
@ -134,6 +135,10 @@ public class UserSession {
return avatarURL; return avatarURL;
} }
public String getWebcamBackgroundURL() {
return webcamBackgroundURL;
}
public String getGuestStatus() { public String getGuestStatus() {
return guestStatus; return guestStatus;
} }

View File

@ -17,6 +17,7 @@ public class CreateBreakoutRoom implements IMessage {
public final Integer durationInMinutes; // The duration of the breakout room public final Integer durationInMinutes; // The duration of the breakout room
public final String sourcePresentationId; public final String sourcePresentationId;
public final Integer sourcePresentationSlide; public final Integer sourcePresentationSlide;
public final String sourcePresentationFilename;
public final Boolean record; public final Boolean record;
public final Boolean privateChatEnabled; public final Boolean privateChatEnabled;
public final Boolean captureNotes; // Upload shared notes to main room after breakout room end public final Boolean captureNotes; // Upload shared notes to main room after breakout room end
@ -38,6 +39,7 @@ public class CreateBreakoutRoom implements IMessage {
Integer duration, Integer duration,
String sourcePresentationId, String sourcePresentationId,
Integer sourcePresentationSlide, Integer sourcePresentationSlide,
String sourcePresentationFilename,
Boolean record, Boolean record,
Boolean privateChatEnabled, Boolean privateChatEnabled,
Boolean captureNotes, Boolean captureNotes,
@ -58,6 +60,7 @@ public class CreateBreakoutRoom implements IMessage {
this.durationInMinutes = duration; this.durationInMinutes = duration;
this.sourcePresentationId = sourcePresentationId; this.sourcePresentationId = sourcePresentationId;
this.sourcePresentationSlide = sourcePresentationSlide; this.sourcePresentationSlide = sourcePresentationSlide;
this.sourcePresentationFilename = sourcePresentationFilename;
this.record = record; this.record = record;
this.privateChatEnabled = privateChatEnabled; this.privateChatEnabled = privateChatEnabled;
this.captureNotes = captureNotes; this.captureNotes = captureNotes;

View File

@ -10,6 +10,7 @@ public class RegisterUser implements IMessage {
public final String externUserID; public final String externUserID;
public final String authToken; public final String authToken;
public final String avatarURL; public final String avatarURL;
public final String webcamBackgroundURL;
public final Boolean guest; public final Boolean guest;
public final Boolean authed; public final Boolean authed;
public final String guestStatus; public final String guestStatus;
@ -17,7 +18,7 @@ public class RegisterUser implements IMessage {
public final Boolean leftGuestLobby; public final Boolean leftGuestLobby;
public RegisterUser(String meetingID, String internalUserId, String fullname, String role, String externUserID, public RegisterUser(String meetingID, String internalUserId, String fullname, String role, String externUserID,
String authToken, String avatarURL, Boolean guest, String authToken, String avatarURL, String webcamBackgroundURL, Boolean guest,
Boolean authed, String guestStatus, Boolean excludeFromDashboard, Boolean leftGuestLobby) { Boolean authed, String guestStatus, Boolean excludeFromDashboard, Boolean leftGuestLobby) {
this.meetingID = meetingID; this.meetingID = meetingID;
this.internalUserId = internalUserId; this.internalUserId = internalUserId;
@ -26,6 +27,7 @@ public class RegisterUser implements IMessage {
this.externUserID = externUserID; this.externUserID = externUserID;
this.authToken = authToken; this.authToken = authToken;
this.avatarURL = avatarURL; this.avatarURL = avatarURL;
this.webcamBackgroundURL = webcamBackgroundURL;
this.guest = guest; this.guest = guest;
this.authed = authed; this.authed = authed;
this.guestStatus = guestStatus; this.guestStatus = guestStatus;

View File

@ -7,6 +7,7 @@ public class UserJoined implements IMessage {
public final String name; public final String name;
public final String role; public final String role;
public final String avatarURL; public final String avatarURL;
public final String webcamBackgroundURL;
public final Boolean guest; public final Boolean guest;
public final String guestStatus; public final String guestStatus;
public final String clientType; public final String clientType;
@ -18,6 +19,7 @@ public class UserJoined implements IMessage {
String name, String name,
String role, String role,
String avatarURL, String avatarURL,
String webcamBackgroundURL,
Boolean guest, Boolean guest,
String guestStatus, String guestStatus,
String clientType) { String clientType) {
@ -27,6 +29,7 @@ public class UserJoined implements IMessage {
this.name = name; this.name = name;
this.role = role; this.role = role;
this.avatarURL = avatarURL; this.avatarURL = avatarURL;
this.webcamBackgroundURL = webcamBackgroundURL;
this.guest = guest; this.guest = guest;
this.guestStatus = guestStatus; this.guestStatus = guestStatus;
this.clientType = clientType; this.clientType = clientType;

View File

@ -1,6 +1,6 @@
package org.bigbluebutton.api.model.constraint; package org.bigbluebutton.api.model.constraint;
import org.bigbluebutton.api.model.validator.PostChecksumValidator; import org.bigbluebutton.api.model.validator.ContentTypeValidator;
import javax.validation.Constraint; import javax.validation.Constraint;
import javax.validation.Payload; import javax.validation.Payload;
@ -10,13 +10,13 @@ import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME; import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Constraint(validatedBy = PostChecksumValidator.class) @Constraint(validatedBy = ContentTypeValidator.class)
@Target(TYPE) @Target(TYPE)
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface PostChecksumConstraint { public @interface ContentTypeConstraint {
String key() default "checksumError"; String key() default "unsupportedContentType";
String message() default "Checksums do not match"; String message() default "POST request Content-Type is missing or unsupported";
Class<?>[] groups() default {}; Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {}; Class<? extends Payload>[] payload() default {};
} }

View File

@ -1,12 +1,16 @@
package org.bigbluebutton.api.model.request; package org.bigbluebutton.api.model.request;
import jakarta.ws.rs.core.MediaType;
import org.bigbluebutton.api.model.constraint.*; import org.bigbluebutton.api.model.constraint.*;
import org.bigbluebutton.api.model.shared.Checksum; import org.bigbluebutton.api.model.shared.Checksum;
import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import java.util.Map; import java.util.Map;
import java.util.Set;
@ContentTypeConstraint
public class CreateMeeting extends RequestWithChecksum<CreateMeeting.Params> { public class CreateMeeting extends RequestWithChecksum<CreateMeeting.Params> {
public enum Params implements RequestParameters { public enum Params implements RequestParameters {
@ -51,8 +55,8 @@ public class CreateMeeting extends RequestWithChecksum<CreateMeeting.Params> {
private String recordString; private String recordString;
private Boolean record; private Boolean record;
public CreateMeeting(Checksum checksum) { public CreateMeeting(Checksum checksum, HttpServletRequest servletRequest) {
super(checksum); super(checksum, servletRequest);
} }
public String getName() { public String getName() {
@ -138,4 +142,9 @@ public class CreateMeeting extends RequestWithChecksum<CreateMeeting.Params> {
isBreakoutRoom = Boolean.parseBoolean(isBreakoutRoomString); isBreakoutRoom = Boolean.parseBoolean(isBreakoutRoomString);
record = Boolean.parseBoolean(recordString); record = Boolean.parseBoolean(recordString);
} }
@Override
public Set<String> getSupportedContentTypes() {
return Set.of(MediaType.APPLICATION_FORM_URLENCODED, MediaType.MULTIPART_FORM_DATA, MediaType.APPLICATION_XML, MediaType.TEXT_XML);
}
} }

View File

@ -1,16 +1,16 @@
package org.bigbluebutton.api.model.request; package org.bigbluebutton.api.model.request;
import org.bigbluebutton.api.model.constraint.MeetingExistsConstraint; import org.bigbluebutton.api.model.constraint.*;
import org.bigbluebutton.api.model.constraint.MeetingIDConstraint;
import org.bigbluebutton.api.model.constraint.NotEmpty;
import org.bigbluebutton.api.model.constraint.PasswordConstraint;
import org.bigbluebutton.api.model.shared.Checksum; import org.bigbluebutton.api.model.shared.Checksum;
import org.bigbluebutton.api.model.shared.ModeratorPassword; import org.bigbluebutton.api.model.shared.ModeratorPassword;
import org.bigbluebutton.api.model.shared.Password; import org.bigbluebutton.api.model.shared.Password;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid; import javax.validation.Valid;
import java.util.Map; import java.util.Map;
import java.util.Set;
@ContentTypeConstraint
public class EndMeeting extends RequestWithChecksum<EndMeeting.Params> { public class EndMeeting extends RequestWithChecksum<EndMeeting.Params> {
public enum Params implements RequestParameters { public enum Params implements RequestParameters {
@ -34,8 +34,8 @@ public class EndMeeting extends RequestWithChecksum<EndMeeting.Params> {
@Valid @Valid
private Password moderatorPassword; private Password moderatorPassword;
public EndMeeting(Checksum checksum) { public EndMeeting(Checksum checksum, HttpServletRequest servletRequest) {
super(checksum); super(checksum, servletRequest);
moderatorPassword = new ModeratorPassword(); moderatorPassword = new ModeratorPassword();
} }

View File

@ -1,11 +1,16 @@
package org.bigbluebutton.api.model.request; package org.bigbluebutton.api.model.request;
import jakarta.ws.rs.core.MediaType;
import org.bigbluebutton.api.model.constraint.*; import org.bigbluebutton.api.model.constraint.*;
import org.bigbluebutton.api.service.SessionService; import org.bigbluebutton.api.service.SessionService;
import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import java.util.Map; import java.util.Map;
import java.util.Set;
public class Enter implements Request<Enter.Params> { @ContentTypeConstraint
public class Enter extends RequestWithSession<Enter.Params>{
public enum Params implements RequestParameters { public enum Params implements RequestParameters {
SESSION_TOKEN("sessionToken"); SESSION_TOKEN("sessionToken");
@ -27,7 +32,8 @@ public class Enter implements Request<Enter.Params> {
private SessionService sessionService; private SessionService sessionService;
public Enter() { public Enter(HttpServletRequest servletRequest) {
super(servletRequest);
sessionService = new SessionService(); sessionService = new SessionService();
} }

View File

@ -2,9 +2,10 @@ package org.bigbluebutton.api.model.request;
import org.bigbluebutton.api.model.constraint.UserSessionConstraint; import org.bigbluebutton.api.model.constraint.UserSessionConstraint;
import javax.servlet.http.HttpServletRequest;
import java.util.Map; import java.util.Map;
public class GetJoinUrl implements Request<GetJoinUrl.Params> { public class GetJoinUrl extends RequestWithSession<GetJoinUrl.Params> {
public enum Params implements RequestParameters { public enum Params implements RequestParameters {
SESSION_TOKEN("sessionToken"); SESSION_TOKEN("sessionToken");
@ -19,6 +20,10 @@ public class GetJoinUrl implements Request<GetJoinUrl.Params> {
@UserSessionConstraint @UserSessionConstraint
private String sessionToken; private String sessionToken;
public GetJoinUrl(HttpServletRequest servletRequest) {
super(servletRequest);
}
public String getSessionToken() { public String getSessionToken() {
return sessionToken; return sessionToken;
} }

View File

@ -1,14 +1,17 @@
package org.bigbluebutton.api.model.request; package org.bigbluebutton.api.model.request;
import org.bigbluebutton.api.model.constraint.ContentTypeConstraint;
import org.bigbluebutton.api.model.constraint.MeetingEndedConstraint; import org.bigbluebutton.api.model.constraint.MeetingEndedConstraint;
import org.bigbluebutton.api.model.constraint.MeetingExistsConstraint; import org.bigbluebutton.api.model.constraint.MeetingExistsConstraint;
import org.bigbluebutton.api.model.constraint.UserSessionConstraint; import org.bigbluebutton.api.model.constraint.UserSessionConstraint;
import org.bigbluebutton.api.service.SessionService; import org.bigbluebutton.api.service.SessionService;
import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import java.util.Map; import java.util.Map;
public class GuestWait implements Request<GuestWait.Params> { @ContentTypeConstraint
public class GuestWait extends RequestWithSession<GuestWait.Params>{
public enum Params implements RequestParameters { public enum Params implements RequestParameters {
SESSION_TOKEN("sessionToken"); SESSION_TOKEN("sessionToken");
@ -29,7 +32,8 @@ public class GuestWait implements Request<GuestWait.Params> {
private SessionService sessionService; private SessionService sessionService;
public GuestWait() { public GuestWait(HttpServletRequest servletRequest) {
super(servletRequest);
sessionService = new SessionService(); sessionService = new SessionService();
} }

View File

@ -1,11 +1,14 @@
package org.bigbluebutton.api.model.request; package org.bigbluebutton.api.model.request;
import jakarta.ws.rs.core.MediaType;
import org.bigbluebutton.api.model.constraint.*; import org.bigbluebutton.api.model.constraint.*;
import org.bigbluebutton.api.model.shared.Checksum; import org.bigbluebutton.api.model.shared.Checksum;
import javax.servlet.http.HttpServletRequest;
import java.util.Map; import java.util.Map;
import java.util.Set;
@ContentTypeConstraint
public class InsertDocument extends RequestWithChecksum<InsertDocument.Params> { public class InsertDocument extends RequestWithChecksum<InsertDocument.Params> {
public enum Params implements RequestParameters { public enum Params implements RequestParameters {
@ -21,8 +24,8 @@ public class InsertDocument extends RequestWithChecksum<InsertDocument.Params> {
@MeetingIDConstraint @MeetingIDConstraint
private String meetingID; private String meetingID;
public InsertDocument(Checksum checksum) { public InsertDocument(Checksum checksum, HttpServletRequest servletRequest) {
super(checksum); super(checksum, servletRequest);
} }
public String getMeetingID() { public String getMeetingID() {
@ -37,4 +40,9 @@ public class InsertDocument extends RequestWithChecksum<InsertDocument.Params> {
public void populateFromParamsMap(Map<String, String[]> params) { public void populateFromParamsMap(Map<String, String[]> params) {
if(params.containsKey(Params.MEETING_ID.getValue())) setMeetingID(params.get(Params.MEETING_ID.getValue())[0]); if(params.containsKey(Params.MEETING_ID.getValue())) setMeetingID(params.get(Params.MEETING_ID.getValue())[0]);
} }
@Override
public Set<String> getSupportedContentTypes() {
return Set.of(MediaType.APPLICATION_XML, MediaType.TEXT_XML);
}
} }

View File

@ -5,9 +5,11 @@ import org.bigbluebutton.api.model.shared.Checksum;
import org.bigbluebutton.api.model.shared.JoinPassword; import org.bigbluebutton.api.model.shared.JoinPassword;
import org.bigbluebutton.api.model.shared.Password; import org.bigbluebutton.api.model.shared.Password;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid; import javax.validation.Valid;
import java.util.Map; import java.util.Map;
@ContentTypeConstraint
public class JoinMeeting extends RequestWithChecksum<JoinMeeting.Params> { public class JoinMeeting extends RequestWithChecksum<JoinMeeting.Params> {
public enum Params implements RequestParameters { public enum Params implements RequestParameters {
@ -57,8 +59,8 @@ public class JoinMeeting extends RequestWithChecksum<JoinMeeting.Params> {
@Valid @Valid
private Password joinPassword; private Password joinPassword;
public JoinMeeting(Checksum checksum) { public JoinMeeting(Checksum checksum, HttpServletRequest servletRequest) {
super(checksum); super(checksum, servletRequest);
joinPassword = new JoinPassword(); joinPassword = new JoinPassword();
} }

View File

@ -2,10 +2,11 @@ package org.bigbluebutton.api.model.request;
import org.bigbluebutton.api.model.constraint.UserSessionConstraint; import org.bigbluebutton.api.model.constraint.UserSessionConstraint;
import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import java.util.Map; import java.util.Map;
public class LearningDashboard implements Request<LearningDashboard.Params> { public class LearningDashboard extends RequestWithSession<LearningDashboard.Params> {
public enum Params implements RequestParameters { public enum Params implements RequestParameters {
SESSION_TOKEN("sessionToken"); SESSION_TOKEN("sessionToken");
@ -20,6 +21,10 @@ public class LearningDashboard implements Request<LearningDashboard.Params> {
@UserSessionConstraint @UserSessionConstraint
private String sessionToken; private String sessionToken;
public LearningDashboard(HttpServletRequest servletRequest) {
super(servletRequest);
}
public String getSessionToken() { public String getSessionToken() {
return sessionToken; return sessionToken;
} }

View File

@ -1,11 +1,14 @@
package org.bigbluebutton.api.model.request; package org.bigbluebutton.api.model.request;
import org.bigbluebutton.api.model.constraint.ContentTypeConstraint;
import org.bigbluebutton.api.model.constraint.MeetingExistsConstraint; import org.bigbluebutton.api.model.constraint.MeetingExistsConstraint;
import org.bigbluebutton.api.model.constraint.MeetingIDConstraint; import org.bigbluebutton.api.model.constraint.MeetingIDConstraint;
import org.bigbluebutton.api.model.shared.Checksum; import org.bigbluebutton.api.model.shared.Checksum;
import javax.servlet.http.HttpServletRequest;
import java.util.Map; import java.util.Map;
@ContentTypeConstraint
public class MeetingInfo extends RequestWithChecksum<MeetingInfo.Params> { public class MeetingInfo extends RequestWithChecksum<MeetingInfo.Params> {
public enum Params implements RequestParameters { public enum Params implements RequestParameters {
@ -22,8 +25,8 @@ public class MeetingInfo extends RequestWithChecksum<MeetingInfo.Params> {
@MeetingExistsConstraint @MeetingExistsConstraint
private String meetingID; private String meetingID;
public MeetingInfo(Checksum checksum) { public MeetingInfo(Checksum checksum, HttpServletRequest servletRequest) {
super(checksum); super(checksum, servletRequest);
} }
public String getMeetingID() { public String getMeetingID() {

View File

@ -1,10 +1,13 @@
package org.bigbluebutton.api.model.request; package org.bigbluebutton.api.model.request;
import org.bigbluebutton.api.model.constraint.ContentTypeConstraint;
import org.bigbluebutton.api.model.constraint.MeetingIDConstraint; import org.bigbluebutton.api.model.constraint.MeetingIDConstraint;
import org.bigbluebutton.api.model.shared.Checksum; import org.bigbluebutton.api.model.shared.Checksum;
import javax.servlet.http.HttpServletRequest;
import java.util.Map; import java.util.Map;
@ContentTypeConstraint
public class MeetingRunning extends RequestWithChecksum<MeetingRunning.Params> { public class MeetingRunning extends RequestWithChecksum<MeetingRunning.Params> {
public enum Params implements RequestParameters { public enum Params implements RequestParameters {
@ -20,8 +23,8 @@ public class MeetingRunning extends RequestWithChecksum<MeetingRunning.Params> {
@MeetingIDConstraint @MeetingIDConstraint
private String meetingID; private String meetingID;
public MeetingRunning(Checksum checksum) { public MeetingRunning(Checksum checksum, HttpServletRequest servletRequest) {
super(checksum); super(checksum, servletRequest);
} }
public String getMeetingID() { public String getMeetingID() {

View File

@ -1,9 +1,13 @@
package org.bigbluebutton.api.model.request; package org.bigbluebutton.api.model.request;
import javax.servlet.http.HttpServletRequest;
import java.util.Map; import java.util.Map;
import java.util.Set;
public interface Request<P extends Enum<P> & RequestParameters> { public interface Request<P extends Enum<P> & RequestParameters> {
void populateFromParamsMap(Map<String, String[]> params); void populateFromParamsMap(Map<String, String[]> params);
void convertParamsFromString(); void convertParamsFromString();
Set<String> getSupportedContentTypes();
HttpServletRequest getServletRequest();
} }

View File

@ -1,17 +1,23 @@
package org.bigbluebutton.api.model.request; package org.bigbluebutton.api.model.request;
import jakarta.ws.rs.core.MediaType;
import org.bigbluebutton.api.model.shared.Checksum; import org.bigbluebutton.api.model.shared.Checksum;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid; import javax.validation.Valid;
import java.util.Map; import java.util.Map;
import java.util.Set;
public abstract class RequestWithChecksum<P extends Enum<P> & RequestParameters> implements Request<P> { public abstract class RequestWithChecksum<P extends Enum<P> & RequestParameters> implements Request<P> {
@Valid @Valid
protected Checksum checksum; protected Checksum checksum;
protected RequestWithChecksum(Checksum checksum) { protected HttpServletRequest servletRequest;
protected RequestWithChecksum(Checksum checksum, HttpServletRequest servletRequest) {
this.checksum = checksum; this.checksum = checksum;
this.servletRequest = servletRequest;
} }
public Checksum getChecksum() { public Checksum getChecksum() {
@ -27,4 +33,14 @@ public abstract class RequestWithChecksum<P extends Enum<P> & RequestParameters>
public void convertParamsFromString() { public void convertParamsFromString() {
} }
@Override
public Set<String> getSupportedContentTypes() {
return Set.of(MediaType.APPLICATION_FORM_URLENCODED, MediaType.MULTIPART_FORM_DATA);
}
@Override
public HttpServletRequest getServletRequest() {
return servletRequest;
}
} }

View File

@ -0,0 +1,25 @@
package org.bigbluebutton.api.model.request;
import jakarta.ws.rs.core.MediaType;
import javax.servlet.http.HttpServletRequest;
import java.util.Set;
public abstract class RequestWithSession<P extends Enum<P> & RequestParameters> implements Request<P> {
protected HttpServletRequest servletRequest;
protected RequestWithSession(HttpServletRequest servletRequest) {
this.servletRequest = servletRequest;
}
@Override
public Set<String> getSupportedContentTypes() {
return Set.of(MediaType.APPLICATION_FORM_URLENCODED, MediaType.MULTIPART_FORM_DATA);
}
@Override
public HttpServletRequest getServletRequest() {
return servletRequest;
}
}

View File

@ -2,10 +2,11 @@ package org.bigbluebutton.api.model.request;
import org.bigbluebutton.api.model.constraint.UserSessionConstraint; import org.bigbluebutton.api.model.constraint.UserSessionConstraint;
import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import java.util.Map; import java.util.Map;
public class SignOut implements Request<SignOut.Params> { public class SignOut extends RequestWithSession<SignOut.Params> {
public enum Params implements RequestParameters { public enum Params implements RequestParameters {
SESSION_TOKEN("sessionToken"); SESSION_TOKEN("sessionToken");
@ -20,6 +21,10 @@ public class SignOut implements Request<SignOut.Params> {
@UserSessionConstraint @UserSessionConstraint
private String sessionToken; private String sessionToken;
public SignOut(HttpServletRequest servletRequest) {
super(servletRequest);
}
public String getSessionToken() { public String getSessionToken() {
return sessionToken; return sessionToken;
} }

View File

@ -1,9 +1,12 @@
package org.bigbluebutton.api.model.request; package org.bigbluebutton.api.model.request;
import org.bigbluebutton.api.model.constraint.ContentTypeConstraint;
import org.bigbluebutton.api.model.shared.Checksum; import org.bigbluebutton.api.model.shared.Checksum;
import javax.servlet.http.HttpServletRequest;
import java.util.Map; import java.util.Map;
@ContentTypeConstraint
public class SimpleRequest extends RequestWithChecksum<SimpleRequest.Params> { public class SimpleRequest extends RequestWithChecksum<SimpleRequest.Params> {
public enum Params implements RequestParameters { public enum Params implements RequestParameters {
@ -16,8 +19,8 @@ public class SimpleRequest extends RequestWithChecksum<SimpleRequest.Params> {
public String getValue() { return value; } public String getValue() { return value; }
} }
public SimpleRequest(Checksum checksum) { public SimpleRequest(Checksum checksum, HttpServletRequest servletRequest) {
super(checksum); super(checksum, servletRequest);
} }
@Override @Override

View File

@ -3,9 +3,11 @@ package org.bigbluebutton.api.model.request;
import org.bigbluebutton.api.model.constraint.*; import org.bigbluebutton.api.model.constraint.*;
import org.bigbluebutton.api.service.SessionService; import org.bigbluebutton.api.service.SessionService;
import javax.servlet.http.HttpServletRequest;
import java.util.Map; import java.util.Map;
public class Stuns implements Request<Stuns.Params> { @ContentTypeConstraint
public class Stuns extends RequestWithSession<Stuns.Params> {
public enum Params implements RequestParameters { public enum Params implements RequestParameters {
SESSION_TOKEN("sessionToken"); SESSION_TOKEN("sessionToken");
@ -26,7 +28,10 @@ public class Stuns implements Request<Stuns.Params> {
private SessionService sessionService; private SessionService sessionService;
public Stuns() { sessionService = new SessionService(); } public Stuns(HttpServletRequest servletRequest) {
super(servletRequest);
sessionService = new SessionService();
}
public String getSessionToken() { public String getSessionToken() {
return sessionToken; return sessionToken;

View File

@ -1,8 +1,11 @@
package org.bigbluebutton.api.model.shared; package org.bigbluebutton.api.model.shared;
import org.bigbluebutton.api.model.constraint.ContentTypeConstraint;
import org.bigbluebutton.api.model.constraint.NotEmpty; import org.bigbluebutton.api.model.constraint.NotEmpty;
import org.bigbluebutton.api.util.ParamsUtil; import org.bigbluebutton.api.util.ParamsUtil;
import javax.servlet.http.HttpServletRequest;
public abstract class Checksum { public abstract class Checksum {
@NotEmpty(message = "You must provide the API call", groups = ChecksumValidationGroup.class) @NotEmpty(message = "You must provide the API call", groups = ChecksumValidationGroup.class)
@ -13,9 +16,12 @@ public abstract class Checksum {
protected String queryStringWithoutChecksum; protected String queryStringWithoutChecksum;
public Checksum(String apiCall, String checksum) { protected HttpServletRequest request;
public Checksum(String apiCall, String checksum, HttpServletRequest request) {
this.apiCall = ParamsUtil.sanitizeString(apiCall); this.apiCall = ParamsUtil.sanitizeString(apiCall);
this.checksum = ParamsUtil.sanitizeString(checksum); this.checksum = ParamsUtil.sanitizeString(checksum);
this.request = request;
} }
public String getApiCall() { public String getApiCall() {
@ -41,4 +47,12 @@ public abstract class Checksum {
public void setQueryStringWithoutChecksum(String queryStringWithoutChecksum) { public void setQueryStringWithoutChecksum(String queryStringWithoutChecksum) {
this.queryStringWithoutChecksum = queryStringWithoutChecksum; this.queryStringWithoutChecksum = queryStringWithoutChecksum;
} }
public void setRequest(HttpServletRequest request) {
this.request = request;
}
public HttpServletRequest getRequest() {
return request;
}
} }

View File

@ -3,16 +3,16 @@ package org.bigbluebutton.api.model.shared;
import org.bigbluebutton.api.model.constraint.GetChecksumConstraint; import org.bigbluebutton.api.model.constraint.GetChecksumConstraint;
import org.bigbluebutton.api.util.ParamsUtil; import org.bigbluebutton.api.util.ParamsUtil;
import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotEmpty;
@GetChecksumConstraint(groups = ChecksumValidationGroup.class) @GetChecksumConstraint(groups = ChecksumValidationGroup.class)
public class GetChecksum extends Checksum { public class GetChecksum extends Checksum {
@NotEmpty(message = "You must provide the query string")
private String queryString; private String queryString;
public GetChecksum(String apiCall, String checksum, String queryString) { public GetChecksum(String apiCall, String checksum, String queryString, HttpServletRequest request) {
super(apiCall, checksum); super(apiCall, checksum, request);
this.queryString = ParamsUtil.sanitizeString(queryString); this.queryString = ParamsUtil.sanitizeString(queryString);
removeChecksumFromQueryString(); removeChecksumFromQueryString();
} }

View File

@ -1,22 +0,0 @@
package org.bigbluebutton.api.model.shared;
import org.bigbluebutton.api.model.constraint.PostChecksumConstraint;
import org.bigbluebutton.api.service.ValidationService;
import java.util.Map;
@PostChecksumConstraint(groups = ChecksumValidationGroup.class)
public class PostChecksum extends Checksum {
Map<String, String[]> params;
public PostChecksum(String apiCall, String checksum, Map<String, String[]> params) {
super(apiCall, checksum);
this.params = params;
queryStringWithoutChecksum = ValidationService.buildQueryStringFromParamsMap(params);
}
public Map<String, String[]> getParams() { return params; }
public void setParams(Map<String, String[]> params) { this.params = params; }
}

View File

@ -0,0 +1,48 @@
package org.bigbluebutton.api.model.validator;
import org.apache.http.entity.ContentType;
import org.bigbluebutton.api.model.constraint.ContentTypeConstraint;
import org.bigbluebutton.api.model.request.Request;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class ContentTypeValidator implements ConstraintValidator<ContentTypeConstraint, Request> {
private static final Logger log = LoggerFactory.getLogger(ContentTypeValidator.class);
@Override
public void initialize(ContentTypeConstraint constraintAnnotation) {}
@Override
public boolean isValid(Request request, ConstraintValidatorContext context) {
HttpServletRequest servletRequest = request.getServletRequest();
String requestMethod = servletRequest.getMethod();
String contentType = servletRequest.getContentType();
String contentTypeHeader = servletRequest.getHeader("Content-Type");
log.info("Validating {} request with content type {}", requestMethod, contentType);
boolean requestBodyPresent = servletRequest.getContentLength() > 0;
if (requestBodyPresent) {
if (contentType == null || contentTypeHeader == null) return false;
else {
try {
ContentType c = ContentType.parse(contentType);
String mimeType = c.getMimeType();
for (Object o: request.getSupportedContentTypes()) {
String supportedContentType = (String) o;
if (mimeType.equalsIgnoreCase(supportedContentType)) return true;
}
} catch (Exception e) {
return false;
}
return false;
}
}
return true;
}
}

View File

@ -1,8 +1,10 @@
package org.bigbluebutton.api.model.validator; package org.bigbluebutton.api.model.validator;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext; import javax.validation.ConstraintValidatorContext;
import jakarta.ws.rs.core.MediaType;
import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.codec.digest.DigestUtils;
import org.bigbluebutton.api.model.constraint.GetChecksumConstraint; import org.bigbluebutton.api.model.constraint.GetChecksumConstraint;
import org.bigbluebutton.api.model.shared.GetChecksum; import org.bigbluebutton.api.model.shared.GetChecksum;

View File

@ -1,53 +0,0 @@
package org.bigbluebutton.api.model.validator;
import org.apache.commons.codec.digest.DigestUtils;
import org.bigbluebutton.api.model.constraint.PostChecksumConstraint;
import org.bigbluebutton.api.model.shared.PostChecksum;
import org.bigbluebutton.api.service.ServiceUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class PostChecksumValidator implements ConstraintValidator<PostChecksumConstraint, PostChecksum> {
private static Logger log = LoggerFactory.getLogger(PostChecksumValidator.class);
@Override
public void initialize(PostChecksumConstraint constraintAnnotation) {}
@Override
public boolean isValid(PostChecksum checksum, ConstraintValidatorContext context) {
String securitySalt = ServiceUtils.getValidationService().getSecuritySalt();
if (securitySalt.isEmpty()) {
log.warn("Security is disabled in this service. Make sure this is intentional.");
return true;
}
String queryStringWithoutChecksum = checksum.getQueryStringWithoutChecksum();
log.info("query string after checksum removed: [{}]", queryStringWithoutChecksum);
if(queryStringWithoutChecksum == null) {
return false;
}
String providedChecksum = checksum.getChecksum();
log.info("CHECKSUM={} length={}", providedChecksum, providedChecksum.length());
if(providedChecksum == null) {
return false;
}
String data = checksum.getApiCall() + queryStringWithoutChecksum + securitySalt;
String createdCheckSum = DigestUtils.sha1Hex(data);
if (createdCheckSum == null || !createdCheckSum.equalsIgnoreCase(providedChecksum)) {
log.info("checksumError: failed checksum. our checksum: [{}], client: [{}]", createdCheckSum, providedChecksum);
return false;
}
return true;
}
}

View File

@ -22,7 +22,7 @@ public interface IPublisherService {
void endMeeting(String meetingId); void endMeeting(String meetingId);
void send(String channel, String message); void send(String channel, String message);
void registerUser(String meetingID, String internalUserId, String fullname, String role, String externUserID, void registerUser(String meetingID, String internalUserId, String fullname, String role, String externUserID,
String authToken, String avatarURL, Boolean guest, Boolean excludeFromDashboard, Boolean authed); String authToken, String avatarURL, String webcamBackgroundURL, Boolean guest, Boolean excludeFromDashboard, Boolean authed);
void sendKeepAlive(String system, Long bbbWebTimestamp, Long akkaAppsTimestamp); void sendKeepAlive(String system, Long bbbWebTimestamp, Long akkaAppsTimestamp);
void sendStunTurnInfo(String meetingId, String internalUserId, Set<StunServer> stuns, Set<TurnEntry> turns); void sendStunTurnInfo(String meetingId, String internalUserId, Set<StunServer> stuns, Set<TurnEntry> turns);
} }

View File

@ -4,16 +4,19 @@ import org.bigbluebutton.api.model.request.*;
import org.bigbluebutton.api.model.shared.Checksum; import org.bigbluebutton.api.model.shared.Checksum;
import org.bigbluebutton.api.model.shared.ChecksumValidationGroup; import org.bigbluebutton.api.model.shared.ChecksumValidationGroup;
import org.bigbluebutton.api.model.shared.GetChecksum; import org.bigbluebutton.api.model.shared.GetChecksum;
import org.bigbluebutton.api.model.shared.PostChecksum;
import org.bigbluebutton.api.util.ParamsUtil; import org.bigbluebutton.api.util.ParamsUtil;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation; import javax.validation.ConstraintViolation;
import javax.validation.Validation; import javax.validation.Validation;
import javax.validation.Validator; import javax.validation.Validator;
import javax.validation.ValidatorFactory; import javax.validation.ValidatorFactory;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.*; import java.util.*;
@ -67,15 +70,22 @@ public class ValidationService {
validator = validatorFactory.getValidator(); validator = validatorFactory.getValidator();
} }
public Map<String, String> validate(ApiCall apiCall, Map<String, String[]> params, String queryString) { public Map<String, String> validate(ApiCall apiCall, HttpServletRequest servletRequest) {
String queryString = servletRequest.getQueryString();
Map<String, String[]> params = servletRequest.getParameterMap();
log.info("Validating {} request with query string {}", apiCall.getName(), queryString); log.info("Validating {} request with query string {}", apiCall.getName(), queryString);
params = sanitizeParams(params); params = sanitizeParams(params);
Request request = initializeRequest(apiCall, params, queryString); Request request = initializeRequest(apiCall, params, queryString, servletRequest);
Map<String,String> violations = new HashMap<>(); Map<String,String> violations = new HashMap<>();
if(request == null) { if(request == null) {
violations.put("validationError", "Request not recognized"); violations.put("validationError", "Request not recognized");
} else if(params.containsKey("presentationUploadExternalUrl")) {
String urlToValidate = params.get("presentationUploadExternalUrl")[0];
if(!this.isValidURL(urlToValidate)) {
violations.put("validationError", "Param 'presentationUploadExternalUrl' is not a valid URL");
}
} else { } else {
request.populateFromParamsMap(params); request.populateFromParamsMap(params);
violations = performValidation(request); violations = performValidation(request);
@ -84,7 +94,16 @@ public class ValidationService {
return violations; return violations;
} }
private Request initializeRequest(ApiCall apiCall, Map<String, String[]> params, String queryString) { boolean isValidURL(String url) {
try {
new URL(url).toURI();
return true;
} catch (MalformedURLException | URISyntaxException e) {
return false;
}
}
private Request initializeRequest(ApiCall apiCall, Map<String, String[]> params, String queryString, HttpServletRequest servletRequest) {
Request request = null; Request request = null;
Checksum checksum; Checksum checksum;
@ -93,55 +112,23 @@ public class ValidationService {
checksumValue = params.get("checksum")[0]; checksumValue = params.get("checksum")[0];
} }
if(queryString == null || queryString.isEmpty()) { if (Objects.requireNonNull(apiCall.requestType) == RequestType.GET) {
queryString = buildQueryStringFromParamsMap(params); checksum = new GetChecksum(apiCall.getName(), checksumValue, queryString, servletRequest);
} request = switch (apiCall) {
case CREATE -> new CreateMeeting(checksum, servletRequest);
switch(apiCall.requestType) { case JOIN -> new JoinMeeting(checksum, servletRequest);
case GET: case MEETING_RUNNING -> new MeetingRunning(checksum, servletRequest);
checksum = new GetChecksum(apiCall.getName(), checksumValue, queryString); case END -> new EndMeeting(checksum, servletRequest);
switch(apiCall) { case GET_MEETING_INFO -> new MeetingInfo(checksum, servletRequest);
case CREATE: case GET_MEETINGS, GET_SESSIONS -> new SimpleRequest(checksum, servletRequest);
request = new CreateMeeting(checksum); case INSERT_DOCUMENT -> new InsertDocument(checksum, servletRequest);
break; case GUEST_WAIT -> new GuestWait(servletRequest);
case JOIN: case ENTER -> new Enter(servletRequest);
request = new JoinMeeting(checksum); case STUNS -> new Stuns(servletRequest);
break; case SIGN_OUT -> new SignOut(servletRequest);
case MEETING_RUNNING: case LEARNING_DASHBOARD -> new LearningDashboard(servletRequest);
request = new MeetingRunning(checksum); case GET_JOIN_URL -> new GetJoinUrl(servletRequest);
break; };
case END:
request = new EndMeeting(checksum);
break;
case GET_MEETING_INFO:
request = new MeetingInfo(checksum);
break;
case GET_MEETINGS:
case GET_SESSIONS:
request = new SimpleRequest(checksum);
break;
case INSERT_DOCUMENT:
request = new InsertDocument(checksum);
break;
case GUEST_WAIT:
request = new GuestWait();
break;
case ENTER:
request = new Enter();
break;
case STUNS:
request = new Stuns();
break;
case SIGN_OUT:
request = new SignOut();
break;
case LEARNING_DASHBOARD:
request = new LearningDashboard();
break;
case GET_JOIN_URL:
request = new GetJoinUrl();
break;
}
} }
return request; return request;

View File

@ -21,6 +21,10 @@ public class ParamsUtil {
return text.replaceAll("\\p{Cc}", "").trim(); return text.replaceAll("\\p{Cc}", "").trim();
} }
public static String stripTags(String text) {
return text.replaceAll("<[^>]*>", "");
}
public static String escapeHTMLTags(String value) { public static String escapeHTMLTags(String value) {
return StringEscapeUtils.escapeHtml4(value); return StringEscapeUtils.escapeHtml4(value);
} }

View File

@ -218,12 +218,13 @@ public class ResponseBuilder {
return xmlText.toString(); return xmlText.toString();
} }
public String buildInsertDocumentResponse(String message, String returnCode) { public String buildInsertDocumentResponse(String messageKey, String message, String returnCode) {
StringWriter xmlText = new StringWriter(); StringWriter xmlText = new StringWriter();
Map<String, Object> data = new HashMap<String, Object>(); Map<String, Object> data = new HashMap<String, Object>();
data.put("returnCode", returnCode); data.put("returnCode", returnCode);
data.put("messageKey", messageKey);
data.put("message", message); data.put("message", message);
processData(getTemplate("insert-document.ftlx"), data, xmlText); processData(getTemplate("insert-document.ftlx"), data, xmlText);

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