Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/spreed.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoas Schilling <213943+nickvergessen@users.noreply.github.com>2022-09-29 20:46:24 +0300
committerGitHub <noreply@github.com>2022-09-29 20:46:24 +0300
commit59a51634ec083e467b7787328f821e513a37e428 (patch)
treea4a58e2948628659a4af34821dbde6c6c3e63f0c
parentf9a24263faab7b4d9ab2adc0500fd30499a31476 (diff)
parentd6a05a4ea81308f2319049e4fa96b341809666e7 (diff)
Merge pull request #8048 from nextcloud/backport/7986/stable25
[stable25] Allow to count the participants per call
-rw-r--r--appinfo/info.xml4
-rw-r--r--lib/Command/Monitor/Calls.php91
-rw-r--r--lib/Command/Monitor/HasActiveCalls.php (renamed from lib/Command/ActiveCalls.php)7
-rw-r--r--lib/Command/Monitor/Room.php139
-rw-r--r--tests/integration/features/bootstrap/CommandLineTrait.php19
-rw-r--r--tests/integration/features/command/active-calls.feature2
-rw-r--r--tests/integration/features/command/monitor-calls.feature61
-rw-r--r--tests/integration/features/command/monitor-room.feature37
-rw-r--r--tests/psalm-baseline.xml27
9 files changed, 371 insertions, 16 deletions
diff --git a/appinfo/info.xml b/appinfo/info.xml
index da07f9264..51a82fc5d 100644
--- a/appinfo/info.xml
+++ b/appinfo/info.xml
@@ -78,12 +78,14 @@ And in the works for the [coming versions](https://github.com/nextcloud/spreed/m
</repair-steps>
<commands>
- <command>OCA\Talk\Command\ActiveCalls</command>
<command>OCA\Talk\Command\Command\Add</command>
<command>OCA\Talk\Command\Command\AddSamples</command>
<command>OCA\Talk\Command\Command\Delete</command>
<command>OCA\Talk\Command\Command\ListCommand</command>
<command>OCA\Talk\Command\Command\Update</command>
+ <command>OCA\Talk\Command\Monitor\Calls</command>
+ <command>OCA\Talk\Command\Monitor\HasActiveCalls</command>
+ <command>OCA\Talk\Command\Monitor\Room</command>
<command>OCA\Talk\Command\Stun\Add</command>
<command>OCA\Talk\Command\Stun\Delete</command>
<command>OCA\Talk\Command\Stun\ListCommand</command>
diff --git a/lib/Command/Monitor/Calls.php b/lib/Command/Monitor/Calls.php
new file mode 100644
index 000000000..25527d058
--- /dev/null
+++ b/lib/Command/Monitor/Calls.php
@@ -0,0 +1,91 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2020 Joas Schilling <coding@schilljs.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\Talk\Command\Monitor;
+
+use OC\Core\Command\Base;
+use OCA\Talk\Participant;
+use OCP\IDBConnection;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class Calls extends Base {
+ protected IDBConnection $connection;
+
+ public function __construct(IDBConnection $connection) {
+ parent::__construct();
+
+ $this->connection = $connection;
+ }
+
+ protected function configure(): void {
+ parent::configure();
+
+ $this
+ ->setName('talk:monitor:calls')
+ ->setDescription('Prints a list with conversations that have an active call as well as their participant count')
+ ;
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output): int {
+ $query = $this->connection->getQueryBuilder();
+ $subQuery = $this->connection->getQueryBuilder();
+ $subQuery->select('attendee_id')
+ ->from('talk_sessions')
+ ->where($subQuery->expr()->gt('in_call', $query->createNamedParameter(Participant::FLAG_DISCONNECTED)))
+ ->andWhere($subQuery->expr()->gt('last_ping', $query->createNamedParameter(time() - 60)))
+ ->groupBy('attendee_id');
+
+ $query->select('r.token', $query->func()->count('*', 'num_attendees'))
+ ->from('talk_attendees', 'a')
+ ->leftJoin('a', 'talk_rooms', 'r', $query->expr()->eq('a.room_id', 'r.id'))
+ ->where($query->expr()->in('a.id', $query->createFunction('(' . $subQuery->getSQL() . ')')))
+ ->groupBy('r.token');
+
+ $data = [];
+ $result = $query->executeQuery();
+ while ($row = $result->fetch()) {
+ $key = (string) $row['token'];
+ if ($input->getOption('output') === Base::OUTPUT_FORMAT_PLAIN) {
+ $key = '"' . $key . '"';
+ }
+
+ $data[$key] = (int) $row['num_attendees'];
+ }
+ $result->closeCursor();
+
+ if ($input->getOption('output') === Base::OUTPUT_FORMAT_PLAIN) {
+ $numCalls = count($data);
+ $numParticipants = array_sum($data);
+
+ if (empty($data)) {
+ $output->writeln('<info>No calls in progress</info>');
+ } else {
+ $output->writeln(sprintf('<error>There are currently %1$d calls in progress with %2$d participants</error>', $numCalls, $numParticipants));
+ }
+ }
+
+ $this->writeArrayInOutputFormat($input, $output, $data);
+ return 0;
+ }
+}
diff --git a/lib/Command/ActiveCalls.php b/lib/Command/Monitor/HasActiveCalls.php
index 48d75c15a..78a271d9d 100644
--- a/lib/Command/ActiveCalls.php
+++ b/lib/Command/Monitor/HasActiveCalls.php
@@ -21,7 +21,7 @@ declare(strict_types=1);
*
*/
-namespace OCA\Talk\Command;
+namespace OCA\Talk\Command\Monitor;
use OC\Core\Command\Base;
use OCA\Talk\Participant;
@@ -29,7 +29,7 @@ use OCP\IDBConnection;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
-class ActiveCalls extends Base {
+class HasActiveCalls extends Base {
protected IDBConnection $connection;
public function __construct(IDBConnection $connection) {
@@ -43,7 +43,8 @@ class ActiveCalls extends Base {
$this
->setName('talk:active-calls')
- ->setDescription('Allows you to check if calls are currently in process') ;
+ ->setDescription('Allows you to check if calls are currently in process')
+ ;
}
protected function execute(InputInterface $input, OutputInterface $output): int {
diff --git a/lib/Command/Monitor/Room.php b/lib/Command/Monitor/Room.php
new file mode 100644
index 000000000..a8f677ba9
--- /dev/null
+++ b/lib/Command/Monitor/Room.php
@@ -0,0 +1,139 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2020 Joas Schilling <coding@schilljs.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\Talk\Command\Monitor;
+
+use OC\Core\Command\Base;
+use OCA\Talk\Participant;
+use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\IDBConnection;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class Room extends Base {
+ protected IDBConnection $connection;
+
+ public function __construct(IDBConnection $connection) {
+ parent::__construct();
+
+ $this->connection = $connection;
+ }
+
+ protected function configure(): void {
+ parent::configure();
+
+ $this
+ ->setName('talk:monitor:room')
+ ->setDescription('Prints a list with conversations that have an active call as well as their participant count')
+ ->addArgument(
+ 'token',
+ InputArgument::REQUIRED,
+ 'Token of the room to monitor'
+ )
+ ->addOption(
+ 'separator',
+ null,
+ InputOption::VALUE_REQUIRED,
+ 'Separator for the CSV list when output=csv is used',
+ ','
+ )
+ ;
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output): int {
+ $token = $input->getArgument('token');
+
+ $query = $this->connection->getQueryBuilder();
+ $query->select('id')
+ ->from('talk_rooms')
+ ->where($query->expr()->eq('token', $query->createNamedParameter($token)));
+
+ $result = $query->executeQuery();
+ $roomId = (int) $result->fetchOne();
+ $result->closeCursor();
+
+ if ($roomId === 0) {
+ if ($input->getOption('output') === Base::OUTPUT_FORMAT_PLAIN) {
+ $output->writeln(sprintf('<error>Room with token %1$s not found</error>', $token));
+ }
+ return 1;
+ }
+
+ $query = $this->connection->getQueryBuilder();
+ $query->select($query->func()->count('*', 'num_attendees'))
+ ->from('talk_attendees')
+ ->where($query->expr()->eq('room_id', $query->createNamedParameter($roomId, IQueryBuilder::PARAM_INT)));
+
+ $result = $query->executeQuery();
+ $numAttendees = (int) $result->fetchOne();
+ $result->closeCursor();
+
+ $numSessions = $numSessionsInCall = 0;
+ $query = $this->connection->getQueryBuilder();
+ $query->select($query->func()->count('s.id', 'num_sessions'))
+ ->from('talk_sessions', 's')
+ ->leftJoin('s', 'talk_attendees', 'a', $query->expr()->eq('a.id', 's.attendee_id'))
+ ->where($query->expr()->eq('a.room_id', $query->createNamedParameter($roomId, IQueryBuilder::PARAM_INT)))
+ ->andWhere($query->expr()->gt('s.last_ping', $query->createNamedParameter(time() - 60, IQueryBuilder::PARAM_INT)));
+
+ $result = $query->executeQuery();
+ $numSessions = (int) $result->fetchOne();
+ $result->closeCursor();
+
+ $query = $this->connection->getQueryBuilder();
+ $query->select($query->func()->count('s.id', 'num_sessions'))
+ ->from('talk_sessions', 's')
+ ->leftJoin('s', 'talk_attendees', 'a', $query->expr()->eq('a.id', 's.attendee_id'))
+ ->where($query->expr()->eq('a.room_id', $query->createNamedParameter($roomId, IQueryBuilder::PARAM_INT)))
+ ->andWhere($query->expr()->gt('s.in_call', $query->createNamedParameter(Participant::FLAG_DISCONNECTED, IQueryBuilder::PARAM_INT)))
+ ->andWhere($query->expr()->gt('s.last_ping', $query->createNamedParameter(time() - 60, IQueryBuilder::PARAM_INT)));
+
+ $result = $query->executeQuery();
+ $numSessionsInCall = (int) $result->fetchOne();
+ $result->closeCursor();
+
+ if ($input->getOption('output') === Base::OUTPUT_FORMAT_PLAIN) {
+ $output->writeln(sprintf(
+ 'The conversation has %1$d attendees with %2$d sessions of which %3$d are in the call.',
+ $numAttendees,
+ $numSessions,
+ $numSessionsInCall
+ ));
+ return 0;
+ }
+ if ($input->getOption('output') === 'csv') {
+ $separator = $input->getOption('separator');
+ $output->writeln($numAttendees . $separator . $numSessions . $separator . $numSessionsInCall);
+ return 0;
+ }
+
+ $this->writeArrayInOutputFormat($input, $output, [
+ 'attendees' => $numAttendees,
+ 'sessions' => $numSessions,
+ 'call' => $numSessionsInCall,
+ ]);
+ return 0;
+ }
+}
diff --git a/tests/integration/features/bootstrap/CommandLineTrait.php b/tests/integration/features/bootstrap/CommandLineTrait.php
index 1f6eff9f7..1c9a3d30b 100644
--- a/tests/integration/features/bootstrap/CommandLineTrait.php
+++ b/tests/integration/features/bootstrap/CommandLineTrait.php
@@ -113,6 +113,8 @@ trait CommandLineTrait {
public function theCommandWasSuccessful() {
$exceptions = $this->findExceptions();
if ($this->lastCode !== 0) {
+ echo $this->lastStdErr;
+
$msg = 'The command was not successful, exit code was ' . $this->lastCode . '.';
if (!empty($exceptions)) {
$msg .= ' Exceptions: ' . implode(', ', $exceptions);
@@ -158,6 +160,23 @@ trait CommandLineTrait {
}
/**
+ * @Then /^the command output contains the list entry '([^']*)' with value '([^']*)'$/
+ */
+ public function theCommandOutputContainsTheListEntry(string $key, string $value): void {
+ if (preg_match('/^"ROOM\(([^"]+)\)"$/', $key, $matches)) {
+ $key = '"' . self::$identifierToToken[$matches[1]] . '"';
+ }
+ $text = '- ' . $key . ': ' . $value;
+
+ if ($this->lastStdOut === '' && $this->lastStdErr !== '') {
+ Assert::assertStringContainsString($text, $this->lastStdErr, 'The command did not output the expected text on stdout');
+ Assert::assertTrue(false, 'The command did not output the expected text on stdout but stderr');
+ }
+
+ Assert::assertStringContainsString($text, $this->lastStdOut, 'The command did not output the expected text on stdout');
+ }
+
+ /**
* @Then /^the command error output contains the text "([^"]*)"$/
*/
public function theCommandErrorOutputContainsTheText($text) {
diff --git a/tests/integration/features/command/active-calls.feature b/tests/integration/features/command/active-calls.feature
index c7ac37f0b..920fa5e69 100644
--- a/tests/integration/features/command/active-calls.feature
+++ b/tests/integration/features/command/active-calls.feature
@@ -1,4 +1,4 @@
-Feature: create
+Feature: command/active-calls
Background:
Given user "participant1" exists
diff --git a/tests/integration/features/command/monitor-calls.feature b/tests/integration/features/command/monitor-calls.feature
new file mode 100644
index 000000000..973a8e04d
--- /dev/null
+++ b/tests/integration/features/command/monitor-calls.feature
@@ -0,0 +1,61 @@
+Feature: command/monitor-calls
+
+ Background:
+ Given user "participant1" exists
+ Given user "participant2" exists
+ Given user "participant3" exists
+
+ Scenario: No call in progress
+ Given invoking occ with "talk:monitor:calls"
+ Then the command was successful
+ And the command output contains the text "No calls in progress"
+
+ Scenario: Users only chatting
+ When user "participant1" creates room "room" (v4)
+ | roomType | 3 |
+ | roomName | room |
+ Then user "participant1" joins room "room" with 200 (v4)
+
+ Given invoking occ with "talk:monitor:calls"
+ Then the command was successful
+ And the command output contains the text "No calls in progress"
+
+ Then user "participant1" leaves room "room" with 200 (v4)
+
+
+ Scenario: Calls in progress
+ When user "participant1" creates room "room" (v4)
+ | roomType | 3 |
+ | roomName | room |
+
+ Then user "participant1" joins room "room" with 200 (v4)
+ And user "participant1" joins call "room" with 200 (v4)
+
+ Given invoking occ with "talk:monitor:calls"
+ Then the command was successful
+ And the command output contains the text "There are currently 1 calls in progress with 1 participants"
+ And the command output contains the list entry '"ROOM(room)"' with value '1'
+
+ When user "participant3" creates room "room2" (v4)
+ | roomType | 1 |
+ | invite | participant2 |
+ And user "participant2" gets room "room2" with 200 (v4)
+
+ And user "participant2" joins room "room2" with 200 (v4)
+ And user "participant3" joins room "room2" with 200 (v4)
+ And user "participant2" joins call "room2" with 200 (v4)
+ And user "participant3" joins call "room2" with 200 (v4)
+
+ Given invoking occ with "talk:monitor:calls"
+ Then the command was successful
+ And the command output contains the text "There are currently 2 calls in progress with 3 participants"
+ And the command output contains the list entry '"ROOM(room)"' with value '1'
+ And the command output contains the list entry '"ROOM(room2)"' with value '2'
+
+ Then user "participant1" leaves call "room" with 200 (v4)
+ And user "participant1" leaves room "room" with 200 (v4)
+
+ Given invoking occ with "talk:monitor:calls"
+ Then the command was successful
+ And the command output contains the text "There are currently 1 calls in progress with 2 participants"
+ And the command output contains the list entry '"ROOM(room2)"' with value '2'
diff --git a/tests/integration/features/command/monitor-room.feature b/tests/integration/features/command/monitor-room.feature
new file mode 100644
index 000000000..fa417dc20
--- /dev/null
+++ b/tests/integration/features/command/monitor-room.feature
@@ -0,0 +1,37 @@
+Feature: command/monitor-room
+
+ Background:
+ Given user "participant1" exists
+ Given user "participant2" exists
+
+ Scenario: No call in progress
+ Given invoking occ with "talk:monitor:room abcdef"
+ Then the command failed with exit code 1
+ And the command output contains the text "Room with token abcdef not found"
+
+ Scenario: From nothing to calling
+ When user "participant1" creates room "room" (v4)
+ | roomType | 3 |
+ | roomName | room |
+ And user "participant1" adds user "participant2" to room "room" with 200 (v4)
+ And user "participant2" gets room "room" with 200 (v4)
+
+ Given invoking occ with "talk:monitor:room room-name:room"
+ Then the command was successful
+ And the command output contains the text "The conversation has 2 attendees with 0 sessions of which 0 are in the call."
+
+ Given user "participant1" joins room "room" with 200 (v4)
+ And invoking occ with "talk:monitor:room room-name:room"
+ Then the command was successful
+ And the command output contains the text "The conversation has 2 attendees with 1 sessions of which 0 are in the call."
+
+ Given user "participant1" joins call "room" with 200 (v4)
+ And invoking occ with "talk:monitor:room room-name:room"
+ Then the command was successful
+ And the command output contains the text "The conversation has 2 attendees with 1 sessions of which 1 are in the call."
+
+ Given user "participant2" joins room "room" with 200 (v4)
+ And user "participant2" joins call "room" with 200 (v4)
+ And invoking occ with "talk:monitor:room room-name:room"
+ Then the command was successful
+ And the command output contains the text "The conversation has 2 attendees with 2 sessions of which 2 are in the call."
diff --git a/tests/psalm-baseline.xml b/tests/psalm-baseline.xml
index 0b509c127..bbcd46119 100644
--- a/tests/psalm-baseline.xml
+++ b/tests/psalm-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<files psalm-version="4.23.0@f1fe6ff483bf325c803df9f510d09a03fd796f88">
+<files psalm-version="4.27.0@faf106e717c37b8c81721845dba9de3d8deed8ff">
<file src="lib/AppInfo/Application.php">
<UndefinedClass occurrences="2">
<code>BeforeTemplateRenderedEvent</code>
@@ -37,11 +37,6 @@
<code>getById</code>
</UndefinedInterfaceMethod>
</file>
- <file src="lib/Command/ActiveCalls.php">
- <UndefinedClass occurrences="1">
- <code>Base</code>
- </UndefinedClass>
- </file>
<file src="lib/Command/Command/Add.php">
<UndefinedClass occurrences="1">
<code>Base</code>
@@ -67,6 +62,21 @@
<code>Base</code>
</UndefinedClass>
</file>
+ <file src="lib/Command/Monitor/Calls.php">
+ <UndefinedClass occurrences="1">
+ <code>Base</code>
+ </UndefinedClass>
+ </file>
+ <file src="lib/Command/Monitor/HasActiveCalls.php">
+ <UndefinedClass occurrences="1">
+ <code>Base</code>
+ </UndefinedClass>
+ </file>
+ <file src="lib/Command/Monitor/Room.php">
+ <UndefinedClass occurrences="1">
+ <code>Base</code>
+ </UndefinedClass>
+ </file>
<file src="lib/Command/Room/Add.php">
<UndefinedClass occurrences="1">
<code>Base</code>
@@ -178,11 +188,6 @@
<code>IRootFolder</code>
</MissingDependency>
</file>
- <file src="lib/Controller/SignalingController.php">
- <UndefinedClass occurrences="1">
- <code>ConnectException</code>
- </UndefinedClass>
- </file>
<file src="lib/Controller/TempAvatarController.php">
<UndefinedClass occurrences="1">
<code>Filesystem</code>