Compare commits
615 Commits
develop
...
snyk-fix-4
Author | SHA1 | Date | |
---|---|---|---|
|
dffea814d4 | ||
|
6f08344a70 | ||
|
1484f516d0 | ||
|
8be32a7bf3 | ||
|
f66f07d177 | ||
|
7a8abd0127 | ||
|
3dd588d704 | ||
|
ff0b2f33b6 | ||
|
7371aa6c18 | ||
|
36b5a16c15 | ||
|
562a13f527 | ||
|
cf6202c572 | ||
|
e6e1f28036 | ||
|
b4a11facd4 | ||
|
ea7867340f | ||
|
07c0433ba0 | ||
|
a642391caf | ||
|
656cdb44cf | ||
|
352f3ebd58 | ||
|
565a8bfcd4 | ||
|
cf966e396b | ||
|
466e328477 | ||
|
06d1a74cdc | ||
|
2c6de02f1c | ||
|
d4ee755a2d | ||
|
3eb3e345af | ||
|
ca18587289 | ||
|
f85bc7f976 | ||
|
6ec1272a2b | ||
|
894515ddb6 | ||
|
450a36d244 | ||
|
3282f230a9 | ||
|
20d4944ce6 | ||
|
80780ddde1 | ||
|
31ac4e7b52 | ||
|
0ea1d8894f | ||
|
dc11f2977b | ||
|
8287fe04d7 | ||
|
4f193ba67a | ||
|
7274fd90da | ||
|
c441b8531a | ||
|
99d1262ff1 | ||
|
59deebdbcb | ||
|
1e2731ef63 | ||
|
565f8a14c7 | ||
|
6cd9d0513e | ||
|
e28a595b52 | ||
|
027115aa14 | ||
|
e1eabefc56 | ||
|
c35580ece4 | ||
|
3b8e7e1968 | ||
|
06c5a2eece | ||
|
290b03e35f | ||
|
4f9ca0e7a3 | ||
|
d0c28c84ec | ||
|
2c20dc3329 | ||
|
2beb822cbe | ||
|
91b39664f9 | ||
|
8b0175e67b | ||
|
5f26293cb2 | ||
|
d9cf1a07d9 | ||
|
9d3b6f0b6c | ||
|
31336c8290 | ||
|
fff955b211 | ||
|
5387fef101 | ||
|
b248143cae | ||
|
437c684423 | ||
|
6918d4e090 | ||
|
1c57db94bb | ||
|
631d5186e5 | ||
|
d3e2d3965c | ||
|
025942de5b | ||
|
623c90b19f | ||
|
4ccc883437 | ||
|
3648748ce0 | ||
|
baa62ab1ef | ||
|
9377121704 | ||
|
7fbf51054b | ||
|
8b6cdc6edf | ||
|
f390049fea | ||
|
610f9a2650 | ||
|
4c6e0289d4 | ||
|
fa0ad14c35 | ||
|
2317d2f98f | ||
|
358a5bd901 | ||
|
15525a6936 | ||
|
bfae93eb0e | ||
|
864e63ffcc | ||
|
f460d54a4e | ||
|
cf8f7528d0 | ||
|
6dc88facd9 | ||
|
a46e38fbbe | ||
|
da3d8140da | ||
|
f5665f3bc4 | ||
|
0c9e11c0e7 | ||
|
fe3b81628f | ||
|
ce8bb567a0 | ||
|
a86bdc9f1e | ||
|
2ef8b4649f | ||
|
a71527a825 | ||
|
59e2609ffa | ||
|
063b77a0fc | ||
|
a4756314a7 | ||
|
de018453f6 | ||
|
9539ad09c0 | ||
|
65ebaecc9a | ||
|
c662a08d12 | ||
|
91762178b9 | ||
|
fd929a1508 | ||
|
b697667364 | ||
|
aeaf206f33 | ||
|
7b42421f41 | ||
|
6588537bf4 | ||
|
e8a361f11c | ||
|
61b94e149d | ||
|
677177b72b | ||
|
7cab994333 | ||
|
77d6f77452 | ||
|
885ba839c6 | ||
|
ed929295f4 | ||
|
a9cd4718ba | ||
|
9080d2e42a | ||
|
d966ea759a | ||
|
b7d2ceff58 | ||
|
7911978d58 | ||
|
a239384c39 | ||
|
89cf90b2cb | ||
|
8efbde2bc5 | ||
|
859cfc1f85 | ||
|
37d6aa0140 | ||
|
496a42ff90 | ||
|
c0caafd2e6 | ||
|
d42861dff9 | ||
|
443b80904b | ||
|
25147a5719 | ||
|
4bab8cf0ca | ||
|
ae70940d0e | ||
|
fe5b15ee5b | ||
|
9b60e6ae5a | ||
|
81e025b3d9 | ||
|
fdb95bb693 | ||
|
acc8ea4809 | ||
|
8bfe0a9b99 | ||
|
fc33fa599d | ||
|
ee873794e9 | ||
|
109317f3e5 | ||
|
285ad950a4 | ||
|
1f774ce888 | ||
|
a3a0bba93a | ||
|
45352c7721 | ||
|
9e2ea86c3d | ||
|
c697caf00c | ||
|
e28b29bd0c | ||
|
ab5dd32744 | ||
|
6021da1004 | ||
|
d6f22c2cd7 | ||
|
f57a1d07de | ||
|
04e916798b | ||
|
d3e78e7d1e | ||
|
ea6e9461dc | ||
|
62eb2c53cf | ||
|
63e59ede1e | ||
|
301cf342a9 | ||
|
ee8b1021b9 | ||
|
220b0a9040 | ||
|
5bc104fbf8 | ||
|
376037c31e | ||
|
a943717c26 | ||
|
cc53fb58f2 | ||
|
2b6d313c80 | ||
|
aebb693379 | ||
|
122b706035 | ||
|
e757cf15ee | ||
|
7a1081a974 | ||
|
06b7628f61 | ||
|
b2b57aca03 | ||
|
4a1c81fa76 | ||
|
6ea1559ced | ||
|
c6b9364204 | ||
|
b2a08bfaff | ||
|
0f691e8968 | ||
|
4c4fc491d3 | ||
|
b6087ab8cb | ||
|
d749a2af08 | ||
|
5810f8b662 | ||
|
fc6f2581c6 | ||
|
0dc21a34d6 | ||
|
15e857abe5 | ||
|
d30974c771 | ||
|
4d9e20891d | ||
|
eb29634a87 | ||
|
4e7d7dd452 | ||
|
8dad2db2e2 | ||
|
41c58d2466 | ||
|
356f6331c1 | ||
|
64d5afc864 | ||
|
13f66bddda | ||
|
6b4f2de798 | ||
|
e5a9ce705f | ||
|
1fc488bfea | ||
|
6a146c0548 | ||
|
400fff96c9 | ||
|
d4ce0b26b1 | ||
|
013ba50137 | ||
|
b81d624c66 | ||
|
54403fb587 | ||
|
d0307e6f21 | ||
|
850e8af19a | ||
|
d484867c99 | ||
|
403959bc34 | ||
|
8bf56ccad9 | ||
|
5f59453548 | ||
|
2084392ac7 | ||
|
141c553b17 | ||
|
9956af9aa1 | ||
|
f91402bc4a | ||
|
a2e22fffb3 | ||
|
698a736d58 | ||
|
da60b246d0 | ||
|
fd6bd798f8 | ||
|
fa38c7747e | ||
|
7d156e8828 | ||
|
be96230894 | ||
|
c83999dd46 | ||
|
de83c75716 | ||
|
ebe0488aa6 | ||
|
35c2370aca | ||
|
ea21caec53 | ||
|
4cb07ad7e7 | ||
|
0a0e8ef773 | ||
|
503e7420a2 | ||
|
0eae452d25 | ||
|
3c2d89280b | ||
|
1b481a9500 | ||
|
5f1c07f4c0 | ||
|
ffe42d1b10 | ||
|
b4158cbf14 | ||
|
b5fe0ac64c | ||
|
304c3136be | ||
|
e24e358ddd | ||
|
a184c67e44 | ||
|
c6ad69f292 | ||
|
3b3e7d840a | ||
|
f5be95da32 | ||
|
49c33b4eea | ||
|
45e1724954 | ||
|
31537b1910 | ||
|
8e40d91877 | ||
|
183983be7f | ||
|
1e9e461f50 | ||
|
916d601d2b | ||
|
85b5e83bd5 | ||
|
6eaf8cd44d | ||
|
b98340bd27 | ||
|
10cb2f3875 | ||
|
2f3e709324 | ||
|
711487c2c9 | ||
|
e511535adc | ||
|
fda4a5a2ff | ||
|
72032f2397 | ||
|
6cb0e914ab | ||
|
68f66a1fbb | ||
|
501d627392 | ||
|
610f3b165b | ||
|
10a6a840b5 | ||
|
71f958ca47 | ||
|
555a8f6522 | ||
|
66788e9697 | ||
|
4e93a4de72 | ||
|
29ea5c3e07 | ||
|
3e845076cb | ||
|
e4cced4b92 | ||
|
9676afceaf | ||
|
f1bad0257d | ||
|
33a704981e | ||
|
fcbfcb1bbc | ||
|
8374e8b21a | ||
|
8502b50d1b | ||
|
7bf1cdd028 | ||
|
c7006d8d3f | ||
|
efa3ca0245 | ||
|
6f4cb742d8 | ||
|
3359289e1a | ||
|
fdae7b48f4 | ||
|
07db720f3e | ||
|
2c2d2186ea | ||
|
990daeeb07 | ||
|
ae9a601660 | ||
|
daf03638ae | ||
|
2fc3119c14 | ||
|
2466bb289e | ||
|
a0733d2c5b | ||
|
882ce76d75 | ||
|
9ada7458d3 | ||
|
766f5e3af7 | ||
|
f41aec10d4 | ||
|
1b84bb318a | ||
|
ac8acfe507 | ||
|
64c4567d06 | ||
|
2c3939d147 | ||
|
578daa130a | ||
|
c69b79872b | ||
|
e1e00ea24d | ||
|
7b34845c0b | ||
|
fe76d76913 | ||
|
8e067c4eef | ||
|
980056a2e8 | ||
|
d90caf77dc | ||
|
2d66db96a1 | ||
|
b418f115fe | ||
|
4e8a708c95 | ||
|
6e9fbfb216 | ||
|
4b469f03c5 | ||
|
fdbab50205 | ||
|
2fec7076b6 | ||
|
70be65b20a | ||
|
3466f41fbf | ||
|
a6c8012277 | ||
|
1f8ca310f1 | ||
|
9506144857 | ||
|
83f75cc727 | ||
|
b26e32d519 | ||
|
6635b0ec14 | ||
|
361717c69a | ||
|
ca7c2d1589 | ||
|
3390d30fc8 | ||
|
f6b2d276a7 | ||
|
25e619a4f6 | ||
|
abea38e718 | ||
|
6cf3cd47fb | ||
|
4879d3e688 | ||
|
f255f4b69e | ||
|
80d4bdbfef | ||
|
95d013d645 | ||
|
a4c6f98d59 | ||
|
1ed6d0fdd2 | ||
|
78ece5f05c | ||
|
96a583b3e5 | ||
|
fbf5cfa7d2 | ||
|
2f091ffd3d | ||
|
5f0eb9ecb9 | ||
|
51519e9c7a | ||
|
1f97a6f253 | ||
|
95c945f4b3 | ||
|
fa872e2b55 | ||
|
04714848cf | ||
|
08a50f8c01 | ||
|
17c132376a | ||
|
22be736c88 | ||
|
aca3730d9f | ||
|
388858000c | ||
|
a744193536 | ||
|
8d741fa016 | ||
|
0e38681e32 | ||
|
5d6c066acb | ||
|
5f963c4465 | ||
|
34f8cf30ba | ||
|
b22a9d0c8b | ||
|
b4528a0032 | ||
|
d924e23069 | ||
|
aa1af6b83f | ||
|
5cf2b78d22 | ||
|
8d3473cd4d | ||
|
e13fc75f6d | ||
|
4ede1a1218 | ||
|
5398df1a8a | ||
|
22efe4647f | ||
|
1babc38e7e | ||
|
e1dc4b55e4 | ||
|
262cd0b735 | ||
|
55238d0b50 | ||
|
afe30cf678 | ||
|
d54fd57c00 | ||
|
551028ba51 | ||
|
75af5c03e7 | ||
|
792add0a3d | ||
|
e59d6dcea8 | ||
|
8495777d5b | ||
|
7551eaebb0 | ||
|
fd8c927140 | ||
|
59cdb136ad | ||
|
f50e10b5ea | ||
|
35bf9b537c | ||
|
45585215cc | ||
|
bb2ecb7c66 | ||
|
aadb5f688f | ||
|
b8c2f3f774 | ||
|
e64ab86dd7 | ||
|
47c5a04e21 | ||
|
d4cea455c1 | ||
|
e778f5857c | ||
|
fe6993d699 | ||
|
e7840e19c5 | ||
|
86caf70e3b | ||
|
bb126a953f | ||
|
98a62c0fab | ||
|
3da6812407 | ||
|
66b3f00e4b | ||
|
d5f7e7d0e4 | ||
|
dedd455863 | ||
|
999ed90a56 | ||
|
5db198e6a5 | ||
|
54bcd9076e | ||
|
ddb7fb77f5 | ||
|
94534455b8 | ||
|
d0a703e734 | ||
|
14b8603164 | ||
|
59a23ed98d | ||
|
a8d2307b9a | ||
|
333b6727b9 | ||
|
13e27ab154 | ||
|
5f7c747698 | ||
|
a9f68154cf | ||
|
4f8fa07702 | ||
|
62c7f5a35a | ||
|
125d70699b | ||
|
c88c23302e | ||
|
2a38249ddf | ||
|
453bb8fe73 | ||
|
283a029e6c | ||
|
08115a93a6 | ||
|
630c79e5c7 | ||
|
742733f7a8 | ||
|
2ac1e7cb97 | ||
|
f19aac1895 | ||
|
409cf1decb | ||
|
5a9c3a140a | ||
|
e15f50e7a8 | ||
|
a8495c8433 | ||
|
8eb425b4bc | ||
|
d683ab2240 | ||
|
3daf0ba7d3 | ||
|
44d655523f | ||
|
cd21fffaaa | ||
|
9e8acbe007 | ||
|
c541c2fdc2 | ||
|
78f26fd599 | ||
|
ae2fb8ba78 | ||
|
5a24e9a520 | ||
|
8b7cfdb54f | ||
|
d041fe660b | ||
|
2282b6220a | ||
|
70cccbe9b7 | ||
|
41348a1767 | ||
|
374ad5045d | ||
|
b61ceb2883 | ||
|
cfa15e8b60 | ||
|
bde7fe7dba | ||
|
5063cb5dfa | ||
|
15b70514fb | ||
|
74c2a259ba | ||
|
5f45e8b2fc | ||
|
32d24e564c | ||
|
229fb4ad09 | ||
|
af05863ad3 | ||
|
db8452f3f1 | ||
|
6f86883324 | ||
|
2471174b51 | ||
|
852b80850f | ||
|
9dd0bb56e2 | ||
|
6a3323ea3a | ||
|
1724f9fce2 | ||
|
92df679e2c | ||
|
5d671b3b50 | ||
|
31d2bf798e | ||
|
bb1a0b75d7 | ||
|
bba51c38fa | ||
|
d71202c195 | ||
|
f314aaf046 | ||
|
8b4b226603 | ||
|
686903a529 | ||
|
c7149c931b | ||
|
d72e8d98d7 | ||
|
c6ccb19fdc | ||
|
2f12992c20 | ||
|
2f8daf34fa | ||
|
c594be415a | ||
|
1b61900548 | ||
|
72029590e5 | ||
|
fd8f0bddab | ||
|
3de1cfed29 | ||
|
0970160ede | ||
|
301b7cd0f2 | ||
|
37870bb1d2 | ||
|
8db78c7200 | ||
|
80b6251c09 | ||
|
bedef5bf89 | ||
|
fbe79a07d7 | ||
|
b9c619a4a6 | ||
|
49864dc6e6 | ||
|
b8e1656d14 | ||
|
ab64a9e265 | ||
|
96b6d02768 | ||
|
64a0d73812 | ||
|
188894612d | ||
|
221327e4c5 | ||
|
07f6edd515 | ||
|
17427fbd9b | ||
|
cc1caf443f | ||
|
42b7905065 | ||
|
b5e6f528fc | ||
|
a8488ac841 | ||
|
7b9e3e09cd | ||
|
1b65c36743 | ||
|
0688cba0b4 | ||
|
b9ebd45ac3 | ||
|
e5b8b2f7d9 | ||
|
06262e309a | ||
|
34c3918e20 | ||
|
72eb50860c | ||
|
bd4edcf726 | ||
|
f910c6ff0f | ||
|
decfd3335b | ||
|
e9f1d76330 | ||
|
dca4f734ff | ||
|
f71e3f8965 | ||
|
a7e5df126f | ||
|
684d54da66 | ||
|
7021d3fa8d | ||
|
bd967e8193 | ||
|
7a26d761b0 | ||
|
54d56524c9 | ||
|
1571573fee | ||
|
a9973d3cff | ||
|
4a44e37d93 | ||
|
a1dd1371e8 | ||
|
ed44b33b15 | ||
|
281308ba4a | ||
|
371378cca8 | ||
|
39de071ab2 | ||
|
545712db34 | ||
|
ce883f8678 | ||
|
4e1e5e361e | ||
|
730803cc20 | ||
|
d33a1c028a | ||
|
3dc4cb28d9 | ||
|
bc7c3143ba | ||
|
ab370872bf | ||
|
f2dbd891cd | ||
|
65b4c5d5d7 | ||
|
d24cdfde6f | ||
|
eb82bbb6de | ||
|
134fe725de | ||
|
f5175d0b71 | ||
|
33f44e1dca | ||
|
c026ecc727 | ||
|
73b7bded08 | ||
|
423bf8ab28 | ||
|
44bb3a67de | ||
|
a2d7743773 | ||
|
df6da10cea | ||
|
77b29d745a | ||
|
0693103e14 | ||
|
94347949d9 | ||
|
c14b1510c2 | ||
|
76fd4508c9 | ||
|
d6670a4145 | ||
|
520668632f | ||
|
c125cbc720 | ||
|
c89154d2a8 | ||
|
82b9b1f408 | ||
|
f230fea85a | ||
|
b994e45f67 | ||
|
01c3f6fb45 | ||
|
577ed647d9 | ||
|
20b4ffe7dd | ||
|
cb075137b3 | ||
|
b2f25decd6 | ||
|
cb744adf52 | ||
|
5f1bed6d44 | ||
|
a22068be18 | ||
|
d7d228d047 | ||
|
2e980ca5d4 | ||
|
6283c856fb | ||
|
11f5481b5a | ||
|
ac3c7790d4 | ||
|
09687431b7 | ||
|
f046ec20af | ||
|
f327c988b9 | ||
|
693183291d | ||
|
c4e24e93bf | ||
|
ea2b855bf7 | ||
|
31db461114 | ||
|
1dc942243b | ||
|
898d6a6156 | ||
|
f7a77beb61 | ||
|
6129314a33 | ||
|
fd1a27fe21 | ||
|
fb0b98a6af | ||
|
8388d55f80 | ||
|
5cd379910f | ||
|
c390799eab | ||
|
d22c9568b8 | ||
|
791074819d | ||
|
f0e5d8aa9d | ||
|
f63bbdceed | ||
|
756499bbb0 | ||
|
2d23f82e55 | ||
|
d402f519c6 | ||
|
1dac6867d9 | ||
|
f7b16ac973 | ||
|
ea301da3a3 | ||
|
56edf23a1f | ||
|
97c5c79772 | ||
|
ef0b78ce30 | ||
|
fde37f08c9 | ||
|
27efad9fc2 | ||
|
61df5319e5 | ||
|
32d6532308 | ||
|
410ca25d01 | ||
|
f1dbc8a8eb | ||
|
f92d3a1ca5 | ||
|
7bce5cf45a | ||
|
c8668bcfe2 | ||
|
66902996dc |
2
.github/ISSUE_TEMPLATE/docs-issue.md
vendored
2
.github/ISSUE_TEMPLATE/docs-issue.md
vendored
@ -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.
|
||||||
|
10
.github/workflows/automated-tests.yml
vendored
10
.github/workflows/automated-tests.yml
vendored
@ -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
|
||||||
|
@ -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")
|
||||||
|
@ -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"
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
@ -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 = {
|
||||||
|
@ -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,
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 _ =>
|
||||||
|
@ -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) {
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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(
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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(
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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 =>
|
||||||
|
@ -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 {
|
||||||
|
|
||||||
}
|
}
|
@ -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
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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()
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
@ -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"
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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" }
|
||||||
|
@ -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" }
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
)
|
)
|
||||||
|
@ -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)
|
||||||
|
@ -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"
|
||||||
)
|
)
|
||||||
|
@ -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";
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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 {};
|
||||||
}
|
}
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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() {
|
||||||
|
@ -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() {
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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; }
|
|
||||||
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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
Loading…
Reference in New Issue
Block a user