Compare commits

..

14 Commits

Author SHA1 Message Date
Klaus c1e42a836e
Merge pull request #200 from sualko/feat-filelist-dialog
feat: use modal to send file
2022-03-16 15:21:55 +01:00
sualko 525d3fa525 feat: use modal to send file
fix #5
2022-03-16 15:11:31 +01:00
Klaus 9a974fcd47
Merge pull request #195 from SpechtD/feat-send-all-users-to-lobby-issue192
feat: send all users to lobby
2022-03-16 13:42:16 +01:00
Klaus dade62576e
Merge pull request #198 from sualko/dependabot/npm_and_yarn/node-fetch-2.6.7
chore(deps): bump node-fetch from 2.6.6 to 2.6.7
2022-03-16 12:03:22 +01:00
sualko 4cbb88cb64 Merge pull request #197 from arawa/cloud_bbb/arawa-master 2022-03-16 11:59:54 +01:00
Thierry Kauffmann 0f4c1682f5 feat: add support for analytics callback url
fix #194
2022-03-16 11:58:38 +01:00
Klaus 96a3a4527d
Merge pull request #199 from sualko/chore-upgrade-dependencies
upgrade required Node version and dependencies
2022-03-16 11:44:08 +01:00
sualko 02168650a4 chore: upgrade required Node version and deps 2022-03-16 11:27:11 +01:00
dependabot[bot] a3b01dbc64
chore(deps): bump node-fetch from 2.6.6 to 2.6.7
Bumps [node-fetch](https://github.com/node-fetch/node-fetch) from 2.6.6 to 2.6.7.
- [Release notes](https://github.com/node-fetch/node-fetch/releases)
- [Commits](https://github.com/node-fetch/node-fetch/compare/v2.6.6...v2.6.7)

---
updated-dependencies:
- dependency-name: node-fetch
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-16 09:36:34 +00:00
Klaus a28ab208ef
Merge pull request #190 from sualko/dependabot/npm_and_yarn/follow-redirects-1.14.8
chore(deps): bump follow-redirects from 1.14.7 to 1.14.8
2022-03-16 10:36:00 +01:00
Klaus c926cc63d7
Merge pull request #189 from sualko/dependabot/npm_and_yarn/node-sass-7.0.0
chore(deps-dev): bump node-sass from 4.14.1 to 7.0.0
2022-03-16 10:35:51 +01:00
Specht, David b7aee468b2 feat: send all users to lobby
closes #192
2022-03-08 15:09:18 +01:00
dependabot[bot] 48f0995b21
chore(deps): bump follow-redirects from 1.14.7 to 1.14.8
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.7 to 1.14.8.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.7...v1.14.8)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-13 11:48:06 +00:00
dependabot[bot] 07611b2a7b
chore(deps-dev): bump node-sass from 4.14.1 to 7.0.0
Bumps [node-sass](https://github.com/sass/node-sass) from 4.14.1 to 7.0.0.
- [Release notes](https://github.com/sass/node-sass/releases)
- [Changelog](https://github.com/sass/node-sass/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sass/node-sass/compare/v4.14.1...v7.0.0)

---
updated-dependencies:
- dependency-name: node-sass
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-10 22:13:00 +00:00
12 changed files with 2685 additions and 4206 deletions

View File

@ -28,7 +28,8 @@ module.exports = {
'comma-dangle': ['error', 'always-multiline'],
'array-bracket-newline': ['error', 'consistent'],
'quote-props': ['error', 'as-needed'],
'indent': ['warn', 'tab'],
semi: ["error", "always"],
indent: ['warn', 'tab'],
semi: ['error', 'always'],
'@typescript-eslint/ban-types': 'off',
},
}

View File

@ -69,15 +69,16 @@ used configuration keys in the list below. Please beware that there will be no
check if those values are correct. Therefore this is not the recommended way.
The syntax to set all settings is `occ config:app:set bbb KEY --value "VALUE"`.
Key | Description
--------------------- | ------------------------------------------------------------------------------------
`app.navigation` | Set to `true` to show navigation entry
`app.navigation.name` | Defines the navigation label. Default "BigBlueButton".
`api.url` | URL to your BBB server. Should start with `https://`
`api.secret` | Secret of your BBB server
`app.shortener` | Value of your shortener service. Should start with `https://` and contain `{token}`.
`avatar.path` | Absolute path to an optional avatar cache directory.
`avatar.url` | URL which serves `avatar.path` to be used as avatar cache.
Key | Description
--------------------------------- | ------------------------------------------------------------------------------------
`app.navigation` | Set to `true` to show navigation entry
`app.navigation.name` | Defines the navigation label. Default "BigBlueButton".
`api.url` | URL to your BBB server. Should start with `https://`
`api.secret` | Secret of your BBB server
`api.meta_analytics-callback-url` | URL which gets called after meetings ends to generate statistics. See [bbb-analytics](https://github.com/betagouv/bbb-analytics).
`app.shortener` | Value of your shortener service. Should start with `https://` and contain `{token}`.
`avatar.path` | Absolute path to an optional avatar cache directory.
`avatar.url` | URL which serves `avatar.path` to be used as avatar cache.
### Avatar cache (v2.2+)
The generation of avatars puts a high load on your Nextcloud instance, since the

View File

@ -106,7 +106,9 @@ class API {
$joinMeetingParams->setCreateTime(sprintf("%.0f", $creationTime));
$joinMeetingParams->setJoinViaHtml5(true);
$joinMeetingParams->setRedirect(true);
$joinMeetingParams->setGuest($uid === null);
// set the guest parameter for everyone but moderators to send all users to the waiting room if setting is selected
$joinMeetingParams->setGuest((($room->access === Room::ACCESS_WAITING_ROOM_ALL) && !$isModerator) || $uid === null);
$joinMeetingParams->addUserData('bbb_listen_only_mode', $room->getListenOnly());
@ -175,6 +177,13 @@ class API {
$createMeetingParams->addMeta('bbb-origin', \method_exists($this->defaults, 'getProductName') ? $this->defaults->getProductName() : 'Nextcloud');
$createMeetingParams->addMeta('bbb-origin-server-name', $this->request->getServerHost());
$analyticsCallbackUrl = $this->config->getAppValue('bbb', 'api.meta_analytics-callback-url');
if (!empty($analyticsCallbackUrl)) {
// For more details: https://github.com/bigbluebutton/bigbluebutton/blob/develop/record-and-playback/core/scripts/post_events/post_events_analytics_callback.rb
$createMeetingParams->addMeta('analytics-callback-url', $analyticsCallbackUrl);
$createMeetingParams->setMeetingKeepEvents(true);
}
$mac = $this->crypto->calculateHMAC($room->uid);
$endMeetingUrl = $this->urlGenerator->linkToRouteAbsolute('bbb.hook.meetingEnded', ['token' => $room->uid, 'mac' => $mac]);
@ -199,7 +208,7 @@ class API {
$createMeetingParams->addPresentation($presentation->getUrl(), null, $presentation->getFilename());
}
if ($room->access === Room::ACCESS_WAITING_ROOM) {
if ($room->access === Room::ACCESS_WAITING_ROOM || $room->access === Room::ACCESS_WAITING_ROOM_ALL) {
$createMeetingParams->setGuestPolicyAskModerator();
}

View File

@ -47,10 +47,11 @@ class Room extends Entity implements JsonSerializable {
public const ACCESS_PUBLIC = 'public';
public const ACCESS_PASSWORD = 'password';
public const ACCESS_WAITING_ROOM = 'waiting_room';
public const ACCESS_WAITING_ROOM_ALL = 'waiting_room_all';
public const ACCESS_INTERNAL = 'internal';
public const ACCESS_INTERNAL_RESTRICTED = 'internal_restricted';
public const ACCESS = [self::ACCESS_PUBLIC, self::ACCESS_PASSWORD, self::ACCESS_WAITING_ROOM, self::ACCESS_INTERNAL, self::ACCESS_INTERNAL_RESTRICTED];
public const ACCESS = [self::ACCESS_PUBLIC, self::ACCESS_PASSWORD, self::ACCESS_WAITING_ROOM, self::ACCESS_WAITING_ROOM_ALL, self::ACCESS_INTERNAL, self::ACCESS_INTERNAL_RESTRICTED];
public $uid;
public $name;

View File

@ -14,7 +14,7 @@
"license": "agpl",
"private": true,
"scripts": {
"build": "NODE_ENV=production webpack --progress --hide-modules --config webpack.prod.js",
"build": "NODE_ENV=production webpack --progress --config webpack.prod.js",
"dev": "NODE_ENV=development webpack --progress --config webpack.dev.js",
"watch": "NODE_ENV=development webpack --progress --watch --config webpack.dev.js",
"test": "run-s --continue-on-error --print-label test:**",
@ -34,20 +34,20 @@
"release:publish": "node scripts/publish-release.js"
},
"dependencies": {
"@commitlint/cli": "^9.1.2",
"@commitlint/config-conventional": "^9.1.2",
"@commitlint/travis-cli": "^9.1.2",
"@commitlint/cli": "^16.2.3",
"@commitlint/config-conventional": "^16.2.1",
"@commitlint/travis-cli": "^16.2.3",
"@nextcloud/axios": "^1.3.2",
"@nextcloud/router": "^1.0.2",
"@nextcloud/router": "^2.0.0",
"@octokit/rest": "^18.0.4",
"archiver": "^5.0.0",
"colors": "^1.4.0",
"dotenv": "^8.2.0",
"execa": "^4.0.0",
"dotenv": "^16.0.0",
"execa": "^6.1.0",
"libxmljs": "^0.19.7",
"qrcode.react": "^1.0.1",
"qrcode.react": "^2.0.0",
"react-copy-to-clipboard": "^5.0.2",
"simple-git": "^2.20.1"
"simple-git": "^3.3.0"
},
"husky": {
"hooks": {
@ -60,58 +60,59 @@
"extends @nextcloud/browserslist-config"
],
"engines": {
"node": ">=10.0.0"
"node": ">=14.0.0"
},
"devDependencies": {
"@babel/core": "^7.9.0",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/preset-env": "^7.9.0",
"@nextcloud/browserslist-config": "^1.0.0",
"@nextcloud/browserslist-config": "^2.2.0",
"@nextcloud/eslint-plugin": "^2.0.0",
"@nextcloud/files": "^1.0.1",
"@types/bootstrap": "^4.3.2",
"@types/inquirer": "^7.3.1",
"@nextcloud/files": "^2.1.0",
"@types/bootstrap": "^5.1.9",
"@types/inquirer": "^8.2.0",
"@types/jquery": "^3.3.35",
"@types/node": "^14.6.2",
"@types/react": "^16.9.34",
"@types/webpack": "^4.41.12",
"@types/node": "^17.0.21",
"@types/react": "^17.0.40",
"@types/webpack": "^5.28.0",
"@types/webpack-env": "^1.15.2",
"@typescript-eslint/eslint-plugin": "^4.0.1",
"@typescript-eslint/parser": "^4.0.1",
"@typescript-eslint/eslint-plugin": "^5.15.0",
"@typescript-eslint/parser": "^5.15.0",
"babel-eslint": "^10.1.0",
"babel-loader": "^8.1.0",
"css-loader": "^4.2.2",
"dotenv-cli": "^3.1.0",
"eslint": "^7.8.0",
"eslint-config-standard": "^14.1.1",
"eslint-import-resolver-webpack": "^0.12.1",
"eslint-loader": "^4.0.2",
"css-loader": "^6.7.1",
"dotenv-cli": "^5.0.0",
"eslint": "^8.11.0",
"eslint-config-standard": "^16.0.3",
"eslint-import-resolver-webpack": "^0.13.2",
"eslint-plugin-import": "^2.20.2",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-promise": "^6.0.0",
"eslint-plugin-react": "^7.19.0",
"eslint-plugin-standard": "^4.0.1",
"eslint-plugin-standard": "^5.0.0",
"eslint-webpack-plugin": "^3.1.1",
"file-loader": "^6.0.0",
"husky": "^4.2.5",
"inquirer": "^7.1.0",
"node-sass": "^4.13.1",
"inquirer": "^8.2.1",
"install": "^0.13.0",
"node-sass": "^7.0.0",
"npm-run-all": "^4.1.5",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-flip-move": "^3.0.4",
"react-hot-loader": "^4.12.20",
"react-select": "^3.1.0",
"sass-loader": "^10.0.1",
"style-loader": "^1.2.0",
"stylelint": "^13.7.0",
"stylelint-config-recommended-scss": "^4.2.0",
"stylelint-scss": "^3.16.0",
"ts-loader": "^8.0.3",
"react-select": "^5.2.2",
"sass-loader": "^12.6.0",
"style-loader": "^3.3.1",
"stylelint": "^14.5.3",
"stylelint-config-recommended-scss": "^5.0.2",
"stylelint-scss": "^4.2.0",
"ts-loader": "^9.2.8",
"typescript": "^4.0.2",
"url-loader": "^4.0.0",
"webpack": "^4.42.1",
"webpack-cli": "^3.3.11",
"webpack": "^5.70.0",
"webpack-cli": "^4.9.2",
"webpack-merge": "^5.1.3",
"webpack-node-externals": "^2.5.2"
"webpack-node-externals": "^3.0.0"
}
}

View File

@ -12,6 +12,7 @@ export enum Access {
Public = 'public',
Password = 'password',
WaitingRoom = 'waiting_room',
WaitingRoomAll = 'waiting_room_all',
Internal = 'internal',
InternalRestricted = 'internal_restricted',
}

View File

@ -4,6 +4,7 @@ export const AccessOptions = {
[Access.Public]: t('bbb', 'Public'),
[Access.Password]: t('bbb', 'Internal + Password protection for guests'),
[Access.WaitingRoom]: t('bbb', 'Internal + Waiting room for guests'),
[Access.WaitingRoomAll]: t('bbb', 'Waiting room for all users'),
[Access.Internal]: t('bbb', 'Internal'),
[Access.InternalRestricted]: t('bbb', 'Internal restricted'),
};

View File

@ -2,6 +2,9 @@ import axios from '@nextcloud/axios';
import { generateOcsUrl, generateUrl } from '@nextcloud/router';
import { api } from './Common/Api';
type OC_Dialogs_Message = (content: string, title: string, dialogType: 'notice' | 'alert' | 'warn' | 'none', buttons?: number, callback?: () => void, modal?: boolean, allowHtml?: boolean) => Promise<void>;
type ExtendedDialogs = typeof OC.dialogs & { message: OC_Dialogs_Message };
const mimeTypes = [
'application/pdf',
'application/vnd.oasis.opendocument.presentation',
@ -18,10 +21,16 @@ const mimeTypes = [
'image/png',
'text/plain',
'text/rtf',
];
] as const;
type MimeTypes = typeof mimeTypes[number];
async function createDirectShare(fileId: number): Promise<string> {
const url = generateOcsUrl('apps/dav/api/v1', 1) + 'direct';
const url = generateOcsUrl('apps/dav/api/v1/', undefined, {
ocsVersion: 1,
escape: true,
noRewrite: true,
}) + 'direct';
const createResponse = await axios.post(url, {
fileId,
});
@ -29,7 +38,7 @@ async function createDirectShare(fileId: number): Promise<string> {
return createResponse.data?.ocs?.data?.url;
}
async function share(fileId: number, filename: string, roomUid) {
async function share(fileId: number, filename: string, roomUid: string) {
const shareUrl = await createDirectShare(fileId);
const joinUrl = generateUrl('/apps/bbb/b/{uid}?u={url}&filename={filename}', {
uid: roomUid,
@ -40,15 +49,59 @@ async function share(fileId: number, filename: string, roomUid) {
window.open(joinUrl, '_blank', 'noopener,noreferrer');
}
function registerFileAction(fileActions, mime, id, uid, name) {
async function openDialog(fileId: number, filename: string) {
const initContent = '<div id="bbb-file-action"><span className="icon icon-loading-small icon-visible"></span></div>';
const title = t('bbb', 'Send file to BBB');
await (OC.dialogs as ExtendedDialogs).message(initContent, title, 'none', -1, undefined, true, true);
const rooms = await api.getRooms();
const container = $('#bbb-file-action').empty();
const table = $('<table>').appendTo(container);
table.attr('style', 'margin-top: 1em; width: 100%;');
for (const room of rooms) {
const row = $('<tr>');
const button = $('<button>');
button.text(t('bbb', 'Start'));
button.addClass('primary');
button.attr('type', 'button');
button.on('click', (ev) => {
ev.preventDefault();
share(fileId, filename, room.uid);
container.parents('.oc-dialog').find('.oc-dialog-close').trigger('click');
});
row.append($('<td>').append(button));
row.append($('<td>').attr('style', 'width: 100%;').text(room.name));
row.appendTo(table);
}
if (rooms.length > 0) {
const description = t('bbb', 'Please select the room in which you like to use the file "{filename}".', { filename });
container.append(description);
container.append(table);
} else {
container.append($('p').text(t('bbb', 'No rooms available!')));
}
}
function registerFileAction(fileActions: any, mime: MimeTypes) {
fileActions.registerAction({
name: 'bbb-' + id,
displayName: name,
name: 'bbb',
displayName: t('bbb', 'Send to BBB'),
mime,
permissions: OC.PERMISSION_SHARE,
icon: OC.imagePath('bbb', 'app-dark.svg'),
actionHandler: (fileName, context) => {
share(context.fileInfoModel.id, fileName, uid);
console.log('Action handler');
openDialog(context.fileInfoModel.id, fileName);
},
});
}
@ -63,11 +116,7 @@ const BBBFileListPlugin = {
return;
}
api.getRooms().then(rooms => {
rooms.forEach(room => {
mimeTypes.forEach(mime => registerFileAction(fileList.fileActions, mime, room.id, room.uid, room.name));
});
});
mimeTypes.forEach(mime => registerFileAction(fileList.fileActions, mime));
},
};

View File

@ -1,4 +1,6 @@
const path = require('path')
/* eslint-disable @typescript-eslint/no-var-requires */
const path = require('path');
const ESLintPlugin = require('eslint-webpack-plugin');
module.exports = {
entry: {
@ -19,7 +21,7 @@ module.exports = {
],
waiting: [
path.join(__dirname, 'ts', 'waiting.ts'),
]
],
},
output: {
path: path.resolve(__dirname, './js'),
@ -50,11 +52,6 @@ module.exports = {
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader'],
},
{
test: /\.(js)$/,
use: 'eslint-loader',
enforce: 'pre',
},
{
test: /\.js$/,
loader: 'babel-loader',
@ -71,9 +68,10 @@ module.exports = {
],
},
plugins: [
new ESLintPlugin(),
],
resolve: {
extensions: ['*', '.tsx', '.ts', '.js', '.scss'],
symlinks: false,
},
}
};

View File

@ -1,7 +1,8 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'development',
devtool: '#cheap-source-map',
})
mode: 'development',
devtool: 'cheap-source-map',
});

View File

@ -1,7 +1,8 @@
const { merge } = require('webpack-merge')
const common = require('./webpack.common.js')
/* eslint-disable @typescript-eslint/no-var-requires */
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'production',
devtool: '#source-map'
})
devtool: 'source-map',
});

6663
yarn.lock

File diff suppressed because it is too large Load Diff