diff --git a/docs/capabilities.md b/docs/capabilities.md index fc3e0d55d..ef882095d 100644 --- a/docs/capabilities.md +++ b/docs/capabilities.md @@ -96,3 +96,4 @@ title: Capabilities ## 15 * `chat-permission` - When permission 128 is required to post chat messages, reaction or share items to the conversation * `sip-support-nopin` - Whether SIP can be configured to not require a custom attendee PIN +* `config => call => enabled` - Whether calling is enabled on the instance or not diff --git a/lib/Capabilities.php b/lib/Capabilities.php index 2ba3c5d24..3b1433f22 100644 --- a/lib/Capabilities.php +++ b/lib/Capabilities.php @@ -108,6 +108,9 @@ class Capabilities implements IPublicCapability { 'attachments' => [ 'allowed' => $user instanceof IUser, ], + 'call' => [ + 'enabled' => ((int) $this->serverConfig->getAppValue('spreed', 'start_calls', Room::START_CALL_EVERYONE)) !== Room::START_CALL_NOONE, + ], 'chat' => [ 'max-length' => ChatManager::MAX_CHAT_LENGTH, 'read-privacy' => Participant::PRIVACY_PUBLIC, diff --git a/lib/Controller/CallController.php b/lib/Controller/CallController.php index 8de7b4120..6b967a0c8 100644 --- a/lib/Controller/CallController.php +++ b/lib/Controller/CallController.php @@ -60,6 +60,7 @@ class CallController extends AEnvironmentAwareController { /** * @PublicPage + * @RequireCallEnabled * @RequireParticipant * @RequireReadWriteConversation * @RequireModeratorOrNoLobby @@ -101,6 +102,7 @@ class CallController extends AEnvironmentAwareController { /** * @PublicPage + * @RequireCallEnabled * @RequireParticipant * @RequireReadWriteConversation * @RequireModeratorOrNoLobby @@ -133,6 +135,7 @@ class CallController extends AEnvironmentAwareController { /** * @PublicPage + * @RequireCallEnabled * @RequireParticipant * * @param int flags diff --git a/lib/Controller/RoomController.php b/lib/Controller/RoomController.php index a6355617f..e4dcf08b2 100644 --- a/lib/Controller/RoomController.php +++ b/lib/Controller/RoomController.php @@ -149,6 +149,7 @@ class RoomController extends AEnvironmentAwareController { $this->config->getAppValue('spreed', 'signaling_servers', '') . '#' . $this->config->getAppValue('spreed', 'signaling_mode', '') . '#' . $this->config->getAppValue('spreed', 'allowed_groups', '') . '#' . + $this->config->getAppValue('spreed', 'start_calls', '') . '#' . $this->config->getAppValue('spreed', 'start_conversations', '') . '#' . $this->config->getAppValue('spreed', 'has_reference_id', '') . '#' . $this->config->getAppValue('spreed', 'sip_bridge_groups', '[]') . '#' . diff --git a/lib/Middleware/CanUseTalkMiddleware.php b/lib/Middleware/CanUseTalkMiddleware.php index 0638f01c5..482fbe57f 100644 --- a/lib/Middleware/CanUseTalkMiddleware.php +++ b/lib/Middleware/CanUseTalkMiddleware.php @@ -26,6 +26,7 @@ namespace OCA\Talk\Middleware; use OCA\Talk\Config; use OCA\Talk\Exceptions\ForbiddenException; use OCA\Talk\Middleware\Exceptions\CanNotUseTalkException; +use OCA\Talk\Room; use OCP\AppFramework\Controller; use OCP\AppFramework\Http; use OCP\AppFramework\Http\Response; @@ -33,17 +34,25 @@ use OCP\AppFramework\Http\RedirectToDefaultAppResponse; use OCP\AppFramework\Middleware; use OCP\AppFramework\OCS\OCSException; use OCP\AppFramework\OCSController; +use OCP\AppFramework\Utility\IControllerMethodReflector; +use OCP\IConfig; use OCP\IUser; use OCP\IUserSession; class CanUseTalkMiddleware extends Middleware { private IUserSession $userSession; - private Config $config; + private IControllerMethodReflector $reflector; + private Config $talkConfig; + private IConfig $serverConfig; public function __construct(IUserSession $userSession, - Config $config) { + IControllerMethodReflector $reflector, + Config $talkConfig, + IConfig $serverConfig) { $this->userSession = $userSession; - $this->config = $config; + $this->reflector = $reflector; + $this->talkConfig = $talkConfig; + $this->serverConfig = $serverConfig; } /** @@ -54,7 +63,12 @@ class CanUseTalkMiddleware extends Middleware { */ public function beforeController($controller, $methodName): void { $user = $this->userSession->getUser(); - if ($user instanceof IUser && $this->config->isDisabledForUser($user)) { + if ($user instanceof IUser && $this->talkConfig->isDisabledForUser($user)) { + throw new CanNotUseTalkException(); + } + + if ($this->reflector->hasAnnotation('RequireCallEnabled') + && ((int) $this->serverConfig->getAppValue('spreed', 'start_calls')) === Room::START_CALL_NOONE) { throw new CanNotUseTalkException(); } } diff --git a/lib/Participant.php b/lib/Participant.php index c28d76ca0..019841bbd 100644 --- a/lib/Participant.php +++ b/lib/Participant.php @@ -95,6 +95,10 @@ class Participant { public function canStartCall(IConfig $config): bool { $defaultStartCall = (int) $config->getAppValue('spreed', 'start_calls', Room::START_CALL_EVERYONE); + if ($defaultStartCall === Room::START_CALL_NOONE) { + return false; + } + if (!($this->getPermissions() & Attendee::PERMISSIONS_CALL_START)) { return false; } diff --git a/lib/Room.php b/lib/Room.php index 562884ee7..0d323678c 100644 --- a/lib/Room.php +++ b/lib/Room.php @@ -93,6 +93,7 @@ class Room { public const START_CALL_EVERYONE = 0; public const START_CALL_USERS = 1; public const START_CALL_MODERATORS = 2; + public const START_CALL_NOONE = 3; public const PARTICIPANT_REMOVED = 'remove'; public const PARTICIPANT_LEFT = 'leave'; diff --git a/lib/TInitialState.php b/lib/TInitialState.php index dbd819893..ae31078e1 100644 --- a/lib/TInitialState.php +++ b/lib/TInitialState.php @@ -59,6 +59,11 @@ trait TInitialState { ); } + $this->initialState->provideInitialState( + 'call_enabled', + ((int) $this->serverConfig->getAppValue('spreed', 'start_calls')) !== Room::START_CALL_NOONE + ); + $this->initialState->provideInitialState( 'signaling_mode', $this->talkConfig->getSignalingMode() diff --git a/src/components/AdminSettings/AllowedGroups.vue b/src/components/AdminSettings/AllowedGroups.vue index cc3a34620..4a5aeb568 100644 --- a/src/components/AdminSettings/AllowedGroups.vue +++ b/src/components/AdminSettings/AllowedGroups.vue @@ -109,6 +109,7 @@ const startCallOptions = [ { value: 0, label: t('spreed', 'Everyone') }, { value: 1, label: t('spreed', 'Users and moderators') }, { value: 2, label: t('spreed', 'Moderators only') }, + { value: 3, label: t('spreed', 'Disable calls') }, ] export default { diff --git a/src/components/TopBar/CallButton.vue b/src/components/TopBar/CallButton.vue index 800df5d19..d34da718b 100644 --- a/src/components/TopBar/CallButton.vue +++ b/src/components/TopBar/CallButton.vue @@ -83,12 +83,14 @@ import isInLobby from '../../mixins/isInLobby' import participant from '../../mixins/participant' import Tooltip from '@nextcloud/vue/dist/Directives/Tooltip' import { emit } from '@nextcloud/event-bus' +import { loadState } from '@nextcloud/initial-state' import BrowserStorage from '../../services/BrowserStorage' import Actions from '@nextcloud/vue/dist/Components/Actions' import ActionButton from '@nextcloud/vue/dist/Components/ActionButton' import VideoOff from 'vue-material-design-icons/VideoOff' import MenuDown from 'vue-material-design-icons/MenuDown' import Button from '@nextcloud/vue/dist/Components/Button' + export default { name: 'CallButton', @@ -125,6 +127,7 @@ export default { data() { return { loading: false, + callEnabled: false, } }, @@ -227,7 +230,8 @@ export default { }, showStartCallButton() { - return this.conversation.readOnly === CONVERSATION.STATE.READ_WRITE + return this.callEnabled + && this.conversation.readOnly === CONVERSATION.STATE.READ_WRITE && !this.isInCall }, @@ -241,6 +245,10 @@ export default { }, }, + mounted() { + this.callEnabled = loadState('spreed', 'call_enabled') + }, + methods: { isParticipantTypeModerator(participantType) { return [PARTICIPANT.TYPE.OWNER, PARTICIPANT.TYPE.MODERATOR, PARTICIPANT.TYPE.GUEST_MODERATOR].indexOf(participantType) !== -1 diff --git a/tests/php/CapabilitiesTest.php b/tests/php/CapabilitiesTest.php index d7d635198..e64a66c9d 100644 --- a/tests/php/CapabilitiesTest.php +++ b/tests/php/CapabilitiesTest.php @@ -29,6 +29,7 @@ use OCA\Talk\Capabilities; use OCA\Talk\Chat\CommentsManager; use OCA\Talk\Config; use OCA\Talk\Participant; +use OCA\Talk\Room; use OCP\Capabilities\IPublicCapability; use OCP\IConfig; use OCP\IUser; @@ -130,6 +131,7 @@ class CapabilitiesTest extends TestCase { ->willReturnMap([ ['spreed', 'has_reference_id', 'no', 'no'], ['spreed', 'max-gif-size', '3145728', '200000'], + ['spreed', 'start_calls', Room::START_CALL_EVERYONE, Room::START_CALL_EVERYONE], ]); $this->assertInstanceOf(IPublicCapability::class, $capabilities); @@ -140,6 +142,9 @@ class CapabilitiesTest extends TestCase { 'attachments' => [ 'allowed' => false, ], + 'call' => [ + 'enabled' => true, + ], 'chat' => [ 'max-length' => 32000, 'read-privacy' => 0, @@ -209,6 +214,7 @@ class CapabilitiesTest extends TestCase { ->willReturnMap([ ['spreed', 'has_reference_id', 'no', 'yes'], ['spreed', 'max-gif-size', '3145728', '200000'], + ['spreed', 'start_calls', Room::START_CALL_EVERYONE, Room::START_CALL_NOONE], ]); $this->assertInstanceOf(IPublicCapability::class, $capabilities); @@ -225,6 +231,9 @@ class CapabilitiesTest extends TestCase { 'allowed' => true, 'folder' => '/Talk', ], + 'call' => [ + 'enabled' => false, + ], 'chat' => [ 'max-length' => 32000, 'read-privacy' => $readPrivacy,