mirror of
https://github.com/nextcloud/spreed.git
synced 2025-12-18 05:20:50 +01:00
fix(chat): Remove commands
Signed-off-by: Joas Schilling <coding@schilljs.com>
This commit is contained in:
parent
a2bc199716
commit
cc4e29258c
38 changed files with 40 additions and 2244 deletions
|
|
@ -73,13 +73,9 @@ And in the works for the [coming versions](https://github.com/nextcloud/spreed/m
|
|||
<step>OCA\Talk\Migration\FixNamespaceInDatabaseTables</step>
|
||||
</pre-migration>
|
||||
<post-migration>
|
||||
<step>OCA\Talk\Migration\CreateHelpCommand</step>
|
||||
<step>OCA\Talk\Migration\ClearResourceAccessCache</step>
|
||||
<step>OCA\Talk\Migration\CacheUserDisplayNames</step>
|
||||
</post-migration>
|
||||
<install>
|
||||
<step>OCA\Talk\Migration\CreateHelpCommand</step>
|
||||
</install>
|
||||
</repair-steps>
|
||||
|
||||
<commands>
|
||||
|
|
@ -89,11 +85,6 @@ And in the works for the [coming versions](https://github.com/nextcloud/spreed/m
|
|||
<command>OCA\Talk\Command\Bot\State</command>
|
||||
<command>OCA\Talk\Command\Bot\Setup</command>
|
||||
<command>OCA\Talk\Command\Bot\Uninstall</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\Developer\UpdateDocs</command>
|
||||
<command>OCA\Talk\Command\Monitor\Calls</command>
|
||||
<command>OCA\Talk\Command\Monitor\HasActiveCalls</command>
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ return array_merge_recursive(
|
|||
include(__DIR__ . '/routes/routesCallController.php'),
|
||||
include(__DIR__ . '/routes/routesCertificateController.php'),
|
||||
include(__DIR__ . '/routes/routesChatController.php'),
|
||||
include(__DIR__ . '/routes/routesCommandController.php'),
|
||||
include(__DIR__ . '/routes/routesFederationController.php'),
|
||||
include(__DIR__ . '/routes/routesFilesIntegrationController.php'),
|
||||
include(__DIR__ . '/routes/routesGuestController.php'),
|
||||
|
|
|
|||
|
|
@ -1,35 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch>
|
||||
*
|
||||
* @author Lukas Reschke <lukas@statuscode.ch>
|
||||
*
|
||||
* @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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
$requirements = [
|
||||
'apiVersion' => '(v1)',
|
||||
];
|
||||
|
||||
return [
|
||||
'ocs' => [
|
||||
/** @see \OCA\Talk\Controller\CommandController::index() */
|
||||
['name' => 'Command#index', 'url' => '/api/{apiVersion}/command', 'verb' => 'GET', 'requirements' => $requirements],
|
||||
],
|
||||
];
|
||||
|
|
@ -2,101 +2,4 @@
|
|||
|
||||
!!! warning
|
||||
|
||||
**Deprecation:** Commands are deprecated in favor of [Bots](bots.md).
|
||||
|
||||
---
|
||||
|
||||
!!! note
|
||||
|
||||
For security reasons commands can only be added via the
|
||||
command line. `./occ talk:command:add --help` gives you
|
||||
a short overview of the required arguments, but they are
|
||||
explained here in more depth.
|
||||
|
||||
---
|
||||
|
||||
## "Add command" arguments
|
||||
|
||||
| Argument | Allowed chars | Description |
|
||||
|------------|---------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `cmd` | [a-z0-9] | The keyword the user has to type to run this command (min. 1, max. 64 characters) |
|
||||
| `name` | * | The author name of the response that is posted by the command (min. 1, max. 64 characters) |
|
||||
| `script` | * | Actual command that is being ran. The script must be executable by the user of your webserver and has to use absolute paths only! See the parameter table below for options. The script is invoked with `--help` as argument on set up, to check if it can be executed correctly. |
|
||||
| `response` | 0-2 | Who should see the response: 0 - No one, 1 - User who executed the command, 2 - Everyone |
|
||||
| `enabled` | 0-3 | Who can use the command: 0 - No one, 1 - Moderators of the room, 2 - Logged in users, 3 - Everyone |
|
||||
|
||||
## Script parameter
|
||||
|
||||
| Parameter | Description |
|
||||
|---------------|----------------------------------------------------|
|
||||
| `{ROOM}` | The token of the room the command was used in |
|
||||
| `{USER}` | ID of the user that called the command |
|
||||
| `{ARGUMENTS}` | Everything the user write after the actual command |
|
||||
|
||||
## Example
|
||||
|
||||
### Create `/path/to/calc.sh`
|
||||
|
||||
```
|
||||
while test $# -gt 0; do
|
||||
case "$1" in
|
||||
--help)
|
||||
echo "/calc - A Nextcloud Talk chat wrapper for gnome-calculator"
|
||||
echo " "
|
||||
echo "Simple equations: /calc 3 + 4 * 5"
|
||||
echo "Complex equations: /calc sin(3) + 3^3 * sqrt(5)"
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
set -f
|
||||
echo "$@ ="
|
||||
echo $(gnome-calculator --solve="$@")
|
||||
```
|
||||
|
||||
Please note, that your command should also understand the argument `--help`.
|
||||
It should return a useful description, the first line is also displayed in a list of all commands when the user just types `/help`.
|
||||
|
||||
### Register command
|
||||
|
||||
|
||||
Make sure to use the absolute path to your script when registering the command:
|
||||
|
||||
```
|
||||
./occ talk:command:add calculator calculator "/path/to/calc.sh {ARGUMENTS} {ROOM} {USER}" 1 3
|
||||
```
|
||||
|
||||
### Explanation
|
||||
* User input by user `my user id` in the chat of room `index.php/call/4tf349j`:
|
||||
|
||||
```
|
||||
/calculator 1 + 2 + 3 + "hello"
|
||||
```
|
||||
|
||||
|
||||
* Executed shell command:
|
||||
|
||||
```
|
||||
/path/to/calc.sh '1 + 2 + 3 + "hello"' '4tf349j' 'my user id'
|
||||
```
|
||||
|
||||
## Aliases
|
||||
|
||||
It is also possible to define an alias for a command. This allows e.g. to get the `/help` command also with the german word `/hilfe`.
|
||||
|
||||
An alias for the `/calculator` command from above could be created using the following command:
|
||||
|
||||
```
|
||||
./occ talk:command:add calc calculator "alias:calculator" 1 3
|
||||
```
|
||||
|
||||
Now `/calculator 1 + 2 + 3` and `/calc 1 + 2 + 3` result in the same message.
|
||||
|
||||
|
||||
!!! note
|
||||
|
||||
The enabled and response flag of the alias are ignored and the flags of the original command will be used and respected.
|
||||
**Deprecation:** Commands have been removed in favor of [Bots](bots.md).
|
||||
|
|
|
|||
|
|
@ -156,17 +156,6 @@ listen to the `OCA\Talk\Events\SystemMessagesMultipleSentEvent` event instead.
|
|||
* Since: 18.0.0
|
||||
* Since: 19.0.0 - Method `getParent()` was added
|
||||
|
||||
### Deprecated events
|
||||
|
||||
These events were not using the typed-event mechanism and are therefore deprecated and will be removed in a future version.
|
||||
|
||||
#### Command execution for apps
|
||||
|
||||
* Event class: `OCA\Talk\Events\CommandEvent`
|
||||
* Event name: `OCA\Talk\Chat\Command\Executor::EVENT_APP_EXECUTE`
|
||||
* Since: 8.0.0
|
||||
* Deprecated: 17.0.0 - Commands are deprecated, please migrate to bots instead
|
||||
|
||||
## Other events
|
||||
|
||||
### Turn servers get
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
* [Call experience](call-experience.md)
|
||||
* [Occ commands](occ.md)
|
||||
* [Bots](bot-list.md)
|
||||
* [Commands (deprecated)](commands.md)
|
||||
* [Matterbridge integration](matterbridge.md)
|
||||
|
||||
## Developer documentation
|
||||
|
|
|
|||
77
docs/occ.md
77
docs/occ.md
|
|
@ -106,83 +106,6 @@ Uninstall a bot from the server
|
|||
| `--output` | Output format (plain, json or json_pretty, default is plain) | yes | no | no | `'plain'` |
|
||||
| `--url` | The URL of the bot (required when no ID is given, ignored otherwise) | yes | yes | no | *Required* |
|
||||
|
||||
## talk:command:add
|
||||
|
||||
Add a new command
|
||||
|
||||
### Usage
|
||||
|
||||
* `talk:command:add [--output [OUTPUT]] [--] <cmd> <name> <script> <response> <enabled>`
|
||||
|
||||
| Arguments | Description | Is required | Is array | Default |
|
||||
|---|---|---|---|---|
|
||||
| `cmd` | The command as used in the chat "/help" => "help" | yes | no | *Required* |
|
||||
| `name` | Name of the user posting the response | yes | no | *Required* |
|
||||
| `script` | Script to execute (Must be using absolute paths only) | yes | no | *Required* |
|
||||
| `response` | Who should see the response: 0 - No one, 1 - User, 2 - All | yes | no | *Required* |
|
||||
| `enabled` | Who can use this command: 0 - Disabled, 1 - Moderators, 2 - Users, 3 - Guests | yes | no | *Required* |
|
||||
|
||||
| Options | Description | Accept value | Is value required | Is multiple | Default |
|
||||
|---|---|---|---|---|---|
|
||||
| `--output` | Output format (plain, json or json_pretty, default is plain) | yes | no | no | `'plain'` |
|
||||
|
||||
## talk:command:add-samples
|
||||
|
||||
Adds some sample commands: /wiki, …
|
||||
|
||||
### Usage
|
||||
|
||||
* `talk:command:add-samples`
|
||||
|
||||
## talk:command:delete
|
||||
|
||||
Remove an existing command
|
||||
|
||||
### Usage
|
||||
|
||||
* `talk:command:delete <command-id>`
|
||||
|
||||
| Arguments | Description | Is required | Is array | Default |
|
||||
|---|---|---|---|---|
|
||||
| `command-id` | | yes | no | *Required* |
|
||||
|
||||
## talk:command:list
|
||||
|
||||
List all available commands
|
||||
|
||||
### Usage
|
||||
|
||||
* `talk:command:list [--output [OUTPUT]] [--] [<app>]`
|
||||
|
||||
| Arguments | Description | Is required | Is array | Default |
|
||||
|---|---|---|---|---|
|
||||
| `app` | Only list the commands of a specific app, "custom" to list all custom commands | no | no | `NULL` |
|
||||
|
||||
| Options | Description | Accept value | Is value required | Is multiple | Default |
|
||||
|---|---|---|---|---|---|
|
||||
| `--output` | Output format (plain, json or json_pretty, default is plain) | yes | no | no | `'plain'` |
|
||||
|
||||
## talk:command:update
|
||||
|
||||
Add a new command
|
||||
|
||||
### Usage
|
||||
|
||||
* `talk:command:update [--output [OUTPUT]] [--] <command-id> <cmd> <name> <script> <response> <enabled>`
|
||||
|
||||
| Arguments | Description | Is required | Is array | Default |
|
||||
|---|---|---|---|---|
|
||||
| `command-id` | | yes | no | *Required* |
|
||||
| `cmd` | The command as used in the chat "/help" => "help" | yes | no | *Required* |
|
||||
| `name` | Name of the user posting the response | yes | no | *Required* |
|
||||
| `script` | Script to execute (Must be using absolute paths only) | yes | no | *Required* |
|
||||
| `response` | Who should see the response: 0 - No one, 1 - User, 2 - All | yes | no | *Required* |
|
||||
| `enabled` | Who can use this command: 0 - Disabled, 1 - Moderators, 2 - Users, 3 - Guests | yes | no | *Required* |
|
||||
|
||||
| Options | Description | Accept value | Is value required | Is multiple | Default |
|
||||
|---|---|---|---|---|---|
|
||||
| `--output` | Output format (plain, json or json_pretty, default is plain) | yes | no | no | `'plain'` |
|
||||
|
||||
## talk:monitor:calls
|
||||
|
||||
Prints a list with conversations that have an active call as well as their participant count
|
||||
|
|
|
|||
|
|
@ -35,10 +35,8 @@ use OCA\Files_Sharing\Event\BeforeTemplateRenderedEvent;
|
|||
use OCA\Talk\Activity\Listener as ActivityListener;
|
||||
use OCA\Talk\Capabilities;
|
||||
use OCA\Talk\Chat\Changelog\Listener as ChangelogListener;
|
||||
use OCA\Talk\Chat\Command\Listener as CommandListener;
|
||||
use OCA\Talk\Chat\Listener as ChatListener;
|
||||
use OCA\Talk\Chat\Parser\Changelog;
|
||||
use OCA\Talk\Chat\Parser\Command;
|
||||
use OCA\Talk\Chat\Parser\ReactionParser;
|
||||
use OCA\Talk\Chat\Parser\SystemMessage;
|
||||
use OCA\Talk\Chat\Parser\UserMention;
|
||||
|
|
@ -57,7 +55,6 @@ use OCA\Talk\Events\AttendeesRemovedEvent;
|
|||
use OCA\Talk\Events\BeforeAttendeeRemovedEvent;
|
||||
use OCA\Talk\Events\BeforeAttendeesAddedEvent;
|
||||
use OCA\Talk\Events\BeforeCallEndedForEveryoneEvent;
|
||||
use OCA\Talk\Events\BeforeChatMessageSentEvent;
|
||||
use OCA\Talk\Events\BeforeDuplicateShareSentEvent;
|
||||
use OCA\Talk\Events\BeforeGuestJoinedRoomEvent;
|
||||
use OCA\Talk\Events\BeforeParticipantModifiedEvent;
|
||||
|
|
@ -219,15 +216,11 @@ class Application extends App implements IBootstrap {
|
|||
|
||||
// Chat parser
|
||||
$context->registerEventListener(MessageParseEvent::class, Changelog::class, -75);
|
||||
$context->registerEventListener(MessageParseEvent::class, Command::class);
|
||||
$context->registerEventListener(MessageParseEvent::class, ReactionParser::class);
|
||||
$context->registerEventListener(MessageParseEvent::class, SystemMessage::class);
|
||||
$context->registerEventListener(MessageParseEvent::class, SystemMessage::class, 9999);
|
||||
$context->registerEventListener(MessageParseEvent::class, UserMention::class, -100);
|
||||
|
||||
// Command listener
|
||||
$context->registerEventListener(BeforeChatMessageSentEvent::class, CommandListener::class);
|
||||
|
||||
// Files integration listeners
|
||||
$context->registerEventListener(BeforeGuestJoinedRoomEvent::class, FilesListener::class);
|
||||
$context->registerEventListener(BeforeUserJoinedRoomEvent::class, FilesListener::class);
|
||||
|
|
|
|||
|
|
@ -300,7 +300,6 @@ class ChatManager {
|
|||
string $referenceId = '',
|
||||
bool $silent = false,
|
||||
bool $rateLimitGuestMentions = true,
|
||||
bool $forceLastMessageUpdate = false, // Remove when dropping commands
|
||||
): IComment {
|
||||
if ($chat->isFederatedConversation()) {
|
||||
$e = new MessagingNotAllowedException();
|
||||
|
|
@ -354,10 +353,9 @@ class ChatManager {
|
|||
$this->participantService->updateLastReadMessage($participant, (int) $comment->getId());
|
||||
}
|
||||
|
||||
// Update last_message (not for commands)
|
||||
// Update last_message
|
||||
if ($comment->getActorType() !== Attendee::ACTOR_BOTS
|
||||
|| $comment->getActorId() === Attendee::ACTOR_ID_CHANGELOG
|
||||
|| $forceLastMessageUpdate
|
||||
|| str_starts_with($comment->getActorId(), Attendee::ACTOR_BOT_PREFIX)) {
|
||||
$this->roomService->setLastMessage($chat, $comment);
|
||||
$this->unreadCountCache->clear($chat->getId() . '-');
|
||||
|
|
|
|||
|
|
@ -1,200 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* @copyright Copyright (c) 2019 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\Chat\Command;
|
||||
|
||||
use OCA\Talk\Chat\ChatManager;
|
||||
use OCA\Talk\Events\CommandEvent;
|
||||
use OCA\Talk\Model\Attendee;
|
||||
use OCA\Talk\Model\Command;
|
||||
use OCA\Talk\Participant;
|
||||
use OCA\Talk\Room;
|
||||
use OCA\Talk\Service\CommandService;
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
use OCP\Comments\IComment;
|
||||
use OCP\EventDispatcher\IEventDispatcher;
|
||||
use OCP\IL10N;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class Executor {
|
||||
/** @deprecated Commands are deprecated, please switch to Nextcloud Talk bots */
|
||||
public const EVENT_APP_EXECUTE = self::class . '::execApp';
|
||||
|
||||
public const PLACEHOLDER_ROOM = '{ROOM}';
|
||||
public const PLACEHOLDER_USER = '{USER}';
|
||||
public const PLACEHOLDER_ARGUMENTS = '{ARGUMENTS}';
|
||||
public const PLACEHOLDER_ARGUMENTS_DOUBLEQUOTE_ESCAPED = '{ARGUMENTS_DOUBLEQUOTE_ESCAPED}';
|
||||
|
||||
public function __construct(
|
||||
protected IEventDispatcher $dispatcher,
|
||||
protected ShellExecutor $shellExecutor,
|
||||
protected CommandService $commandService,
|
||||
protected LoggerInterface $logger,
|
||||
protected IL10N $l,
|
||||
) {
|
||||
}
|
||||
|
||||
public function isCommandAvailableForParticipant(Command $command, Participant $participant): bool {
|
||||
if ($command->getEnabled() === Command::ENABLED_OFF) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($command->getEnabled() === Command::ENABLED_MODERATOR && !$participant->hasModeratorPermissions()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($command->getEnabled() === Command::ENABLED_USERS && $participant->isGuest()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function exec(Room $room, IComment $message, Command $command, string $arguments, Participant $participant): void {
|
||||
try {
|
||||
$command = $this->commandService->resolveAlias($command);
|
||||
} catch (DoesNotExistException $e) {
|
||||
$user = $message->getActorType() === Attendee::ACTOR_USERS ? $message->getActorId() : '';
|
||||
$message->setMessage(json_encode([
|
||||
'user' => $user,
|
||||
'visibility' => $command->getResponse(),
|
||||
'output' => $e->getMessage(),
|
||||
]), ChatManager::MAX_CHAT_LENGTH);
|
||||
$message->setActor('bots', $command->getName());
|
||||
$message->setVerb(ChatManager::VERB_COMMAND);
|
||||
return;
|
||||
}
|
||||
|
||||
if (($command->getApp() === '' || $command->getApp() === null) && $command->getCommand() === 'help') {
|
||||
$output = $this->execHelp($room, $message, $arguments, $participant);
|
||||
} elseif ($command->getApp() !== '' && $command->getApp() !== null) {
|
||||
$output = $this->execApp($room, $message, $command, $arguments);
|
||||
} else {
|
||||
$output = $this->execShell($room, $message, $command, $arguments);
|
||||
}
|
||||
|
||||
$user = $message->getActorType() === Attendee::ACTOR_USERS ? $message->getActorId() : '';
|
||||
$message->setMessage(json_encode([
|
||||
'user' => $user,
|
||||
'visibility' => $command->getResponse(),
|
||||
'output' => $output,
|
||||
]), ChatManager::MAX_CHAT_LENGTH);
|
||||
$message->setActor('bots', $command->getName());
|
||||
$message->setVerb(ChatManager::VERB_COMMAND);
|
||||
}
|
||||
|
||||
protected function execHelp(Room $room, IComment $message, string $arguments, Participant $participant): string {
|
||||
if ($arguments !== '' && $arguments !== 'help') {
|
||||
return $this->execHelpSingleCommand($room, $message, $arguments);
|
||||
}
|
||||
|
||||
$helps = [];
|
||||
$commands = $this->commandService->findAll();
|
||||
|
||||
foreach ($commands as $command) {
|
||||
if ($command->getApp() !== '' && $command->getApp() !== null) {
|
||||
$response = $this->execHelpSingleCommand($room, $message, $command->getApp() . ' ' . $command->getCommand());
|
||||
} else {
|
||||
if ($command->getCommand() === 'help' || str_contains($command->getScript(), 'alias:') ||
|
||||
!$this->isCommandAvailableForParticipant($command, $participant)) {
|
||||
continue;
|
||||
}
|
||||
$response = $this->execHelpSingleCommand($room, $message, $command->getCommand());
|
||||
}
|
||||
|
||||
$response = trim($response);
|
||||
$newLinePosition = strpos($response, "\n");
|
||||
if ($newLinePosition !== false) {
|
||||
$tempHelp = substr($response, 0, $newLinePosition);
|
||||
if ($tempHelp === 'Description:') {
|
||||
$hasHelpSection = strpos($response, "\nHelp:\n");
|
||||
if ($hasHelpSection !== false) {
|
||||
// Symfony console command with --help detected
|
||||
$tempHelp = substr($response, $hasHelpSection + 7);
|
||||
$tempHelp = substr($tempHelp, 0, strpos($tempHelp, "\n"));
|
||||
}
|
||||
}
|
||||
$helps[] = $tempHelp;
|
||||
} else {
|
||||
$helps[] = $response;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($helps)) {
|
||||
return $this->l->t('There are currently no commands available.');
|
||||
}
|
||||
|
||||
// FIXME Implement a useful help
|
||||
return implode("\n", $helps);
|
||||
}
|
||||
|
||||
protected function execHelpSingleCommand(Room $room, IComment $message, string $arguments): string {
|
||||
try {
|
||||
$input = explode(' ', $arguments, 2);
|
||||
if (count($input) === 1) {
|
||||
$command = $this->commandService->find('', $arguments);
|
||||
$response = $this->execShell($room, $message, $command, '--help');
|
||||
|
||||
if (str_starts_with($response, 'Description:')) {
|
||||
$hasHelpSection = strpos($response, "\nHelp:\n");
|
||||
if ($hasHelpSection !== false) {
|
||||
// Symfony console command with --help detected
|
||||
$response = substr($response, $hasHelpSection + 7);
|
||||
}
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
[$app, $cmd] = $input;
|
||||
$command = $this->commandService->find($app, $cmd);
|
||||
return $this->execApp($room, $message, $command, '--help');
|
||||
} catch (DoesNotExistException $e) {
|
||||
return $this->l->t('The command does not exist');
|
||||
}
|
||||
}
|
||||
|
||||
protected function execApp(Room $room, IComment $message, Command $command, string $arguments): string {
|
||||
$event = $this->createEvent($room, $message, $command, $arguments);
|
||||
$this->dispatcher->dispatch(self::EVENT_APP_EXECUTE, $event);
|
||||
return $event->getOutput();
|
||||
}
|
||||
|
||||
protected function createEvent(Room $room, IComment $message, Command $command, string $arguments): CommandEvent {
|
||||
return new CommandEvent($room, $message, $command, $arguments);
|
||||
}
|
||||
|
||||
public function execShell(Room $room, IComment $message, Command $command, string $arguments): string {
|
||||
try {
|
||||
return $this->shellExecutor->execShell(
|
||||
$command->getScript(),
|
||||
$arguments,
|
||||
$room->getToken(),
|
||||
$message->getActorType() === Attendee::ACTOR_USERS ? $message->getActorId() : ''
|
||||
);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$this->logger->error($e->getMessage(), ['exception' => $e]);
|
||||
return $this->l->t('An error occurred while running the command. Please ask an administrator to check the logs.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,117 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* @copyright Copyright (c) 2019 Joas Schilling <coding@schilljs.com>
|
||||
*
|
||||
* @author 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\Chat\Command;
|
||||
|
||||
use OCA\Talk\Events\BeforeChatMessageSentEvent;
|
||||
use OCA\Talk\Model\Command;
|
||||
use OCA\Talk\Participant;
|
||||
use OCA\Talk\Service\CommandService;
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
use OCP\EventDispatcher\Event;
|
||||
use OCP\EventDispatcher\IEventListener;
|
||||
|
||||
/**
|
||||
* @template-implements IEventListener<Event>
|
||||
*/
|
||||
class Listener implements IEventListener {
|
||||
|
||||
public function __construct(
|
||||
protected CommandService $commandService,
|
||||
protected Executor $executor,
|
||||
) {
|
||||
}
|
||||
|
||||
public function handle(Event $event): void {
|
||||
if ($event instanceof BeforeChatMessageSentEvent) {
|
||||
$this->executeCommand($event);
|
||||
}
|
||||
}
|
||||
|
||||
public function executeCommand(BeforeChatMessageSentEvent $event): void {
|
||||
$participant = $event->getParticipant();
|
||||
if (!$participant instanceof Participant) {
|
||||
// No commands for bots 🚓
|
||||
return;
|
||||
}
|
||||
|
||||
$message = $event->getComment();
|
||||
if (str_starts_with($message->getMessage(), '//')) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
[$command, $arguments] = $this->getCommand($message->getMessage());
|
||||
$command = $this->commandService->resolveAlias($command);
|
||||
} catch (DoesNotExistException) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$this->executor->isCommandAvailableForParticipant($command, $participant)) {
|
||||
$command = $this->commandService->find('', 'help');
|
||||
$arguments = trim($message->getMessage());
|
||||
}
|
||||
|
||||
$this->executor->exec($event->getRoom(), $message, $command, $arguments, $participant);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @return array{0: Command, 1: string}
|
||||
* @throws DoesNotExistException
|
||||
*/
|
||||
protected function getCommand(string $message): array {
|
||||
[$app, $cmd, $arguments] = $this->matchesCommand($message);
|
||||
|
||||
if ($app === '') {
|
||||
throw new DoesNotExistException('No command found');
|
||||
}
|
||||
|
||||
try {
|
||||
return [$this->commandService->find($app, $cmd), trim($arguments)];
|
||||
} catch (DoesNotExistException) {
|
||||
}
|
||||
|
||||
try {
|
||||
return [$this->commandService->find('', $app), trim($cmd . ' ' . $arguments)];
|
||||
} catch (DoesNotExistException) {
|
||||
}
|
||||
|
||||
return [$this->commandService->find('', 'help'), trim($message)];
|
||||
}
|
||||
|
||||
protected function matchesCommand(string $message): array {
|
||||
if (!str_starts_with($message, '/')) {
|
||||
return ['', '', ''];
|
||||
}
|
||||
|
||||
$cmd = explode(' ', substr($message, 1), 3);
|
||||
return [
|
||||
$cmd[0],
|
||||
$cmd[1] ?? '',
|
||||
$cmd[2] ?? '',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* @copyright Copyright (c) 2019 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\Chat\Command;
|
||||
|
||||
class ShellExecutor {
|
||||
public const PLACEHOLDER_ROOM = '{ROOM}';
|
||||
public const PLACEHOLDER_USER = '{USER}';
|
||||
public const PLACEHOLDER_ARGUMENTS = '{ARGUMENTS}';
|
||||
|
||||
// Legacy placeholder just returning the --help nowadays
|
||||
public const PLACEHOLDER_ARGUMENTS_DOUBLEQUOTE_ESCAPED = '{ARGUMENTS_DOUBLEQUOTE_ESCAPED}';
|
||||
|
||||
/**
|
||||
* @param string $cmd
|
||||
* @param string $arguments
|
||||
* @param string $room
|
||||
* @param string $user
|
||||
* @return string
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function execShell(string $cmd, string $arguments, string $room = '', string $user = ''): string {
|
||||
if (str_contains($cmd, self::PLACEHOLDER_ARGUMENTS_DOUBLEQUOTE_ESCAPED)) {
|
||||
throw new \InvalidArgumentException('Talk commands using the {ARGUMENTS_DOUBLEQUOTE_ESCAPED} are not supported anymore.');
|
||||
}
|
||||
|
||||
$cmd = str_replace([
|
||||
self::PLACEHOLDER_ROOM,
|
||||
self::PLACEHOLDER_USER,
|
||||
self::PLACEHOLDER_ARGUMENTS,
|
||||
], [
|
||||
escapeshellarg($room),
|
||||
escapeshellarg($user),
|
||||
escapeshellarg($arguments),
|
||||
], $cmd);
|
||||
|
||||
return $this->wrapExec($cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $cmd
|
||||
* @return string
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
protected function wrapExec(string $cmd): string {
|
||||
$output = [];
|
||||
$returnCode = 0;
|
||||
@exec($cmd, $output, $returnCode);
|
||||
|
||||
if ($returnCode) {
|
||||
throw new \InvalidArgumentException('Chat command failed [Code: ' . $returnCode . ']: ' . $cmd);
|
||||
}
|
||||
|
||||
return implode("\n", $output);
|
||||
}
|
||||
}
|
||||
|
|
@ -35,6 +35,10 @@ use OCP\EventDispatcher\IEventListener;
|
|||
* @template-implements IEventListener<Event>
|
||||
*/
|
||||
class Command implements IEventListener {
|
||||
public const RESPONSE_NONE = 0;
|
||||
public const RESPONSE_USER = 1;
|
||||
public const RESPONSE_ALL = 2;
|
||||
|
||||
public function handle(Event $event): void {
|
||||
if (!$event instanceof MessageParseEvent) {
|
||||
return;
|
||||
|
|
@ -46,6 +50,8 @@ class Command implements IEventListener {
|
|||
return;
|
||||
}
|
||||
|
||||
$message->setVisibility(false);
|
||||
|
||||
$comment = $message->getComment();
|
||||
$data = json_decode($comment->getMessage(), true);
|
||||
if (!\is_array($data)) {
|
||||
|
|
@ -54,13 +60,13 @@ class Command implements IEventListener {
|
|||
|
||||
$event->stopPropagation();
|
||||
|
||||
if ($data['visibility'] === \OCA\Talk\Model\Command::RESPONSE_NONE) {
|
||||
if ($data['visibility'] === self::RESPONSE_NONE) {
|
||||
$message->setVisibility(false);
|
||||
return;
|
||||
}
|
||||
|
||||
$participant = $message->getParticipant();
|
||||
if ($data['visibility'] !== \OCA\Talk\Model\Command::RESPONSE_ALL &&
|
||||
if ($data['visibility'] !== self::RESPONSE_ALL &&
|
||||
$participant !== null &&
|
||||
($participant->getAttendee()->getActorType() !== Attendee::ACTOR_USERS
|
||||
|| $data['user'] !== $participant->getAttendee()->getActorId())) {
|
||||
|
|
|
|||
|
|
@ -1,119 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* @copyright Copyright (c) 2019 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\Command;
|
||||
|
||||
use OC\Core\Command\Base;
|
||||
use OCA\Talk\Service\CommandService;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class Add extends Base {
|
||||
use TRenderCommand;
|
||||
|
||||
public function __construct(
|
||||
private CommandService $service,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void {
|
||||
parent::configure();
|
||||
$this
|
||||
->setName('talk:command:add')
|
||||
->setDescription('Add a new command')
|
||||
->addArgument(
|
||||
'cmd',
|
||||
InputArgument::REQUIRED,
|
||||
'The command as used in the chat "/help" => "help"'
|
||||
)
|
||||
->addArgument(
|
||||
'name',
|
||||
InputArgument::REQUIRED,
|
||||
'Name of the user posting the response'
|
||||
)
|
||||
->addArgument(
|
||||
'script',
|
||||
InputArgument::REQUIRED,
|
||||
'Script to execute (Must be using absolute paths only)'
|
||||
)
|
||||
->addArgument(
|
||||
'response',
|
||||
InputArgument::REQUIRED,
|
||||
'Who should see the response: 0 - No one, 1 - User, 2 - All'
|
||||
)
|
||||
->addArgument(
|
||||
'enabled',
|
||||
InputArgument::REQUIRED,
|
||||
'Who can use this command: 0 - Disabled, 1 - Moderators, 2 - Users, 3 - Guests'
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int {
|
||||
$cmd = $input->getArgument('cmd');
|
||||
$name = $input->getArgument('name');
|
||||
$script = $input->getArgument('script');
|
||||
$response = (int) $input->getArgument('response');
|
||||
$enabled = (int) $input->getArgument('enabled');
|
||||
|
||||
try {
|
||||
$command = $this->service->create('', $cmd, $name, $script, $response, $enabled);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
switch ($e->getCode()) {
|
||||
case 1:
|
||||
$output->writeln('<error>The command already exists or is invalid</error>');
|
||||
break;
|
||||
case 2:
|
||||
$output->writeln('<error>The name is invalid</error>');
|
||||
break;
|
||||
case 3:
|
||||
$output->writeln('<error>The script is invalid</error>');
|
||||
break;
|
||||
case 4:
|
||||
$output->writeln('<error>The response value is invalid</error>');
|
||||
break;
|
||||
case 5:
|
||||
$output->writeln('<error>The enabled value is invalid</error>');
|
||||
break;
|
||||
case 6:
|
||||
$output->writeln('<error>The placeholders {ROOM}, {USER} and {ARGUMENTS} must not be used inside quotes</error>');
|
||||
break;
|
||||
default:
|
||||
$output->writeln('<error>The command could not be added</error>');
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
$output->writeln('<info>Command added</info>');
|
||||
$output->writeln('');
|
||||
$this->renderCommands($input, $output, [$command]);
|
||||
|
||||
$output->writeln('');
|
||||
$output->writeln("<comment>If you think your command makes sense for other users as well, feel free to share it in the following github issue:\n https://github.com/nextcloud/spreed/issues/1566</comment>");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,130 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* @copyright Copyright (c) 2019 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\Command;
|
||||
|
||||
use OC\Core\Command\Base;
|
||||
use OCA\Talk\Model\Command;
|
||||
use OCA\Talk\Service\CommandService;
|
||||
use OCP\App\AppPathNotFoundException;
|
||||
use OCP\App\IAppManager;
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class AddSamples extends Base {
|
||||
use TRenderCommand;
|
||||
|
||||
protected array $commands = [];
|
||||
|
||||
public function __construct(
|
||||
private CommandService $service,
|
||||
protected IAppManager $appManager,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void {
|
||||
$this
|
||||
->setName('talk:command:add-samples')
|
||||
->setDescription('Adds some sample commands: /wiki, …')
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int {
|
||||
try {
|
||||
$appPath = $this->appManager->getAppPath('spreed');
|
||||
} catch (AppPathNotFoundException $e) {
|
||||
$output->writeln('<error>Could not determine the spreed/ app directory.</error>');
|
||||
return 1;
|
||||
}
|
||||
|
||||
$this->installCommand(
|
||||
$output,
|
||||
'wiki',
|
||||
'Wikipedia',
|
||||
'php ' . $appPath . '/sample-commands/wikipedia.php {ARGUMENTS}'
|
||||
);
|
||||
|
||||
$chmod = fileperms($appPath . '/sample-commands/calc.sh');
|
||||
if (!($chmod & 0x0040 || $chmod & 0x0008 || $chmod & 0x0001)) {
|
||||
$output->writeln('<error>sample-commands/calc.sh is not executable</error>');
|
||||
} elseif (!shell_exec('which bc')) {
|
||||
$output->writeln('<error>Can not add calculator command, because Basic calculator package (bc - https://www.gnu.org/software/bc/) is missing</error>');
|
||||
} else {
|
||||
$this->installCommand(
|
||||
$output,
|
||||
'calculator',
|
||||
'Calculator',
|
||||
$appPath . '/sample-commands/calc.sh {ARGUMENTS}',
|
||||
Command::RESPONSE_USER
|
||||
);
|
||||
|
||||
$this->installCommand(
|
||||
$output,
|
||||
'calc',
|
||||
'Calculator',
|
||||
'alias:calculator'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
$this->installCommand(
|
||||
$output,
|
||||
'hackernews',
|
||||
'Hacker News',
|
||||
'php ' . $appPath . '/sample-commands/hackernews.php {ARGUMENTS}'
|
||||
);
|
||||
|
||||
if (empty($this->commands)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
$output->writeln('<info>Commands added</info>');
|
||||
$output->writeln('');
|
||||
$this->renderCommands($input, $output, $this->commands);
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected function installCommand(OutputInterface $output, string $command, string $name, string $script, int $resonse = Command::RESPONSE_ALL, int $enable = Command::ENABLED_ALL): void {
|
||||
try {
|
||||
$this->service->find('', $command);
|
||||
$output->writeln('<comment>Command ' . $command . ' already exists</comment>');
|
||||
return;
|
||||
} catch (DoesNotExistException $e) {
|
||||
}
|
||||
|
||||
try {
|
||||
$this->commands[] = $this->service->create(
|
||||
'',
|
||||
$command,
|
||||
$name,
|
||||
$script,
|
||||
$resonse,
|
||||
$enable
|
||||
);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$output->writeln('<error>An error occured while setting up the ' . $command . ' command</error>');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* @copyright Copyright (c) 2019 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\Command;
|
||||
|
||||
use OC\Core\Command\Base;
|
||||
use OCA\Talk\Service\CommandService;
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class Delete extends Base {
|
||||
|
||||
public function __construct(
|
||||
private CommandService $service,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure():void {
|
||||
$this
|
||||
->setName('talk:command:delete')
|
||||
->setDescription('Remove an existing command')
|
||||
->addArgument(
|
||||
'command-id',
|
||||
InputArgument::REQUIRED
|
||||
);
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int {
|
||||
$id = (int) $input->getArgument('command-id');
|
||||
|
||||
try {
|
||||
$this->service->delete($id);
|
||||
} catch (DoesNotExistException $e) {
|
||||
$output->writeln('<error>The given command ID does not exist</error>');
|
||||
return 1;
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$output->writeln('<error>The help command cannot be deleted</error>');
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* @copyright Copyright (c) 2019 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\Command;
|
||||
|
||||
use OC\Core\Command\Base;
|
||||
use OCA\Talk\Service\CommandService;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class ListCommand extends Base {
|
||||
use TRenderCommand;
|
||||
|
||||
public function __construct(
|
||||
private CommandService $service,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void {
|
||||
parent::configure();
|
||||
|
||||
$this
|
||||
->setName('talk:command:list')
|
||||
->setDescription('List all available commands')
|
||||
->addArgument('app', InputArgument::OPTIONAL, 'Only list the commands of a specific app, "custom" to list all custom commands')
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int {
|
||||
$app = $input->getArgument('app');
|
||||
if ($app === null) {
|
||||
$commands = $this->service->findAll();
|
||||
} else {
|
||||
$commands = $this->service->findByApp($app === 'custom' ? '' : $app);
|
||||
}
|
||||
|
||||
$this->renderCommands($input, $output, $commands, true);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* @copyright Copyright (c) 2019 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\Command;
|
||||
|
||||
use OC\Core\Command\Base;
|
||||
use OCA\Talk\Model\Command;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
trait TRenderCommand {
|
||||
protected function renderCommands(InputInterface $input, OutputInterface $output, array $commands, bool $showHelp = false): void {
|
||||
$result = array_map(function (Command $command) {
|
||||
return $command->asArray();
|
||||
}, $commands);
|
||||
|
||||
$plainText = $input->getOption('output') ?? Base::OUTPUT_FORMAT_PLAIN;
|
||||
if ($plainText === Base::OUTPUT_FORMAT_PLAIN) {
|
||||
if ($showHelp) {
|
||||
$output->writeln('Response values: 0 - No one, 1 - User, 2 - All');
|
||||
$output->writeln('Enabled values: 0 - Disabled, 1 - Moderators, 2 - Users, 3 - Guests');
|
||||
$output->writeln('');
|
||||
}
|
||||
|
||||
$table = new Table($output);
|
||||
if (isset($result[0])) {
|
||||
$table->setHeaders(array_keys($result[0]));
|
||||
}
|
||||
$table->addRows($result);
|
||||
$table->render();
|
||||
} else {
|
||||
$this->writeMixedInOutputFormat($input, $output, $result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,125 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* @copyright Copyright (c) 2019 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\Command;
|
||||
|
||||
use OC\Core\Command\Base;
|
||||
use OCA\Talk\Service\CommandService;
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class Update extends Base {
|
||||
use TRenderCommand;
|
||||
|
||||
public function __construct(
|
||||
private CommandService $service,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void {
|
||||
parent::configure();
|
||||
$this
|
||||
->setName('talk:command:update')
|
||||
->setDescription('Add a new command')
|
||||
->addArgument(
|
||||
'command-id',
|
||||
InputArgument::REQUIRED
|
||||
)
|
||||
->addArgument(
|
||||
'cmd',
|
||||
InputArgument::REQUIRED,
|
||||
'The command as used in the chat "/help" => "help"'
|
||||
)
|
||||
->addArgument(
|
||||
'name',
|
||||
InputArgument::REQUIRED,
|
||||
'Name of the user posting the response'
|
||||
)
|
||||
->addArgument(
|
||||
'script',
|
||||
InputArgument::REQUIRED,
|
||||
'Script to execute (Must be using absolute paths only)'
|
||||
)
|
||||
->addArgument(
|
||||
'response',
|
||||
InputArgument::REQUIRED,
|
||||
'Who should see the response: 0 - No one, 1 - User, 2 - All'
|
||||
)
|
||||
->addArgument(
|
||||
'enabled',
|
||||
InputArgument::REQUIRED,
|
||||
'Who can use this command: 0 - Disabled, 1 - Moderators, 2 - Users, 3 - Guests'
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int {
|
||||
$id = (int) $input->getArgument('command-id');
|
||||
$cmd = $input->getArgument('cmd');
|
||||
$name = $input->getArgument('name');
|
||||
$script = $input->getArgument('script');
|
||||
$response = (int) $input->getArgument('response');
|
||||
$enabled = (int) $input->getArgument('enabled');
|
||||
|
||||
try {
|
||||
$command = $this->service->update($id, $cmd, $name, $script, $response, $enabled);
|
||||
} catch (DoesNotExistException $e) {
|
||||
$output->writeln('<error>The given command ID does not exist</error>');
|
||||
return 1;
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
switch ($e->getCode()) {
|
||||
case 0:
|
||||
$output->writeln('<error>The help command and predefined commands cannot be updated</error>');
|
||||
break;
|
||||
case 1:
|
||||
$output->writeln('<error>The command already exists or is invalid</error>');
|
||||
break;
|
||||
case 2:
|
||||
$output->writeln('<error>The name is invalid</error>');
|
||||
break;
|
||||
case 3:
|
||||
$output->writeln('<error>The script is invalid</error>');
|
||||
break;
|
||||
case 4:
|
||||
$output->writeln('<error>The response value is invalid</error>');
|
||||
break;
|
||||
case 5:
|
||||
$output->writeln('<error>The enabled value is invalid</error>');
|
||||
break;
|
||||
default:
|
||||
$output->writeln('<error>The command could not be updated</error>');
|
||||
break;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
$output->writeln('<info>Command updated</info>');
|
||||
$output->writeln('');
|
||||
$this->renderCommands($input, $output, [$command]);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @copyright Copyright (c) 2019 Joas Schilling <coding@schilljs.com>
|
||||
*
|
||||
* @author 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\Controller;
|
||||
|
||||
use OCA\Talk\Model\Command;
|
||||
use OCA\Talk\Service\CommandService;
|
||||
use OCP\AppFramework\Http\Attribute\OpenAPI;
|
||||
use OCP\AppFramework\Http\DataResponse;
|
||||
use OCP\AppFramework\OCSController;
|
||||
use OCP\IRequest;
|
||||
|
||||
class CommandController extends OCSController {
|
||||
|
||||
public function __construct(
|
||||
string $appName,
|
||||
IRequest $request,
|
||||
protected CommandService $commandService,
|
||||
) {
|
||||
parent::__construct($appName, $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Commands are deprecated in favor of Bots
|
||||
*/
|
||||
#[OpenAPI(scope: OpenAPI::SCOPE_IGNORE)]
|
||||
public function index(): DataResponse {
|
||||
$commands = $this->commandService->findAll();
|
||||
|
||||
$result = array_map(static function (Command $command) {
|
||||
return $command->asArray();
|
||||
}, $commands);
|
||||
|
||||
return new DataResponse($result);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* @copyright Copyright (c) 2019 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\Events;
|
||||
|
||||
use OCA\Talk\Model\Command;
|
||||
use OCA\Talk\Room;
|
||||
use OCP\Comments\IComment;
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
class CommandEvent extends ARoomEvent {
|
||||
protected string $output = '';
|
||||
|
||||
public function __construct(
|
||||
Room $room,
|
||||
protected IComment $message,
|
||||
protected Command $command,
|
||||
protected string $arguments,
|
||||
) {
|
||||
parent::__construct($room);
|
||||
}
|
||||
|
||||
public function getComment(): IComment {
|
||||
return $this->message;
|
||||
}
|
||||
|
||||
public function shouldSkipLastActivityUpdate(): bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isSilentMessage(): bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getCommand(): Command {
|
||||
return $this->command;
|
||||
}
|
||||
|
||||
public function getArguments(): string {
|
||||
return $this->arguments;
|
||||
}
|
||||
|
||||
public function setOutput(string $output): void {
|
||||
$this->output = $output;
|
||||
}
|
||||
|
||||
public function getOutput(): string {
|
||||
return $this->output;
|
||||
}
|
||||
}
|
||||
|
|
@ -132,7 +132,6 @@ class Operation implements IOperation {
|
|||
$this->prepareMention($mode, $participant) . $message,
|
||||
new \DateTime(),
|
||||
rateLimitGuestMentions: false,
|
||||
forceLastMessageUpdate: true,
|
||||
);
|
||||
} catch (UnexpectedValueException|ParticipantNotFoundException|RoomNotFoundException) {
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -1,68 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @copyright Copyright (c) 2019, Joas Schilling <coding@schilljs.com>
|
||||
*
|
||||
* @author 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\Migration;
|
||||
|
||||
use OCA\Talk\Model\Command;
|
||||
use OCA\Talk\Service\CommandService;
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
use OCP\Migration\IOutput;
|
||||
use OCP\Migration\IRepairStep;
|
||||
|
||||
class CreateHelpCommand implements IRepairStep {
|
||||
|
||||
public function __construct(
|
||||
protected CommandService $service,
|
||||
) {
|
||||
}
|
||||
|
||||
public function getName(): string {
|
||||
return 'Create help command';
|
||||
}
|
||||
|
||||
public function run(IOutput $output): void {
|
||||
try {
|
||||
$command = $this->service->find('', 'help');
|
||||
$this->service->update(
|
||||
$command->getId(),
|
||||
'help',
|
||||
'talk',
|
||||
'help',
|
||||
Command::RESPONSE_USER,
|
||||
Command::ENABLED_ALL
|
||||
);
|
||||
} catch (DoesNotExistException $e) {
|
||||
$this->service->create(
|
||||
'',
|
||||
'help',
|
||||
'talk',
|
||||
'help',
|
||||
Command::RESPONSE_USER,
|
||||
Command::ENABLED_ALL
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* @copyright Copyright (c) 2019 Joas Schilling <coding@schilljs.com>
|
||||
*
|
||||
* @author Kate Döen <kate.doeen@nextcloud.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\Model;
|
||||
|
||||
use OCP\AppFramework\Db\Entity;
|
||||
|
||||
/**
|
||||
* @method void setApp(string $app)
|
||||
* @method string getApp()
|
||||
* @method void setName(string $name)
|
||||
* @method string getName()
|
||||
* @method void setCommand(string $command)
|
||||
* @method string getCommand()
|
||||
* @method void setScript(string $name)
|
||||
* @method string getScript()
|
||||
* @method void setResponse(int $response)
|
||||
* @method int getResponse()
|
||||
* @method void setEnabled(int $enabled)
|
||||
* @method int getEnabled()
|
||||
*/
|
||||
class Command extends Entity {
|
||||
public const RESPONSE_NONE = 0;
|
||||
public const RESPONSE_USER = 1;
|
||||
public const RESPONSE_ALL = 2;
|
||||
|
||||
public const ENABLED_OFF = 0;
|
||||
public const ENABLED_MODERATOR = 1;
|
||||
public const ENABLED_USERS = 2;
|
||||
public const ENABLED_ALL = 3;
|
||||
|
||||
/** @var string */
|
||||
protected $app;
|
||||
|
||||
/** @var string */
|
||||
protected $name;
|
||||
|
||||
/** @var string */
|
||||
protected $command;
|
||||
|
||||
/** @var string */
|
||||
protected $script;
|
||||
|
||||
/** @var int */
|
||||
protected $response;
|
||||
|
||||
/** @var int */
|
||||
protected $enabled;
|
||||
|
||||
public function __construct() {
|
||||
$this->addType('app', 'string');
|
||||
$this->addType('name', 'string');
|
||||
$this->addType('command', 'string');
|
||||
$this->addType('script', 'string');
|
||||
$this->addType('response', 'int');
|
||||
$this->addType('enabled', 'int');
|
||||
}
|
||||
|
||||
public function asArray(): array {
|
||||
return [
|
||||
'id' => $this->getId(),
|
||||
'app' => $this->getApp(),
|
||||
'name' => $this->getName(),
|
||||
'command' => $this->getCommand(),
|
||||
'script' => $this->getScript(),
|
||||
'response' => $this->getResponse(),
|
||||
'enabled' => $this->getEnabled(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -1,100 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* @copyright Copyright (c) 2019 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\Model;
|
||||
|
||||
use OCP\AppFramework\Db\QBMapper;
|
||||
use OCP\IDBConnection;
|
||||
|
||||
/**
|
||||
* @template-extends QBMapper<Command>
|
||||
*/
|
||||
class CommandMapper extends QBMapper {
|
||||
/**
|
||||
* @param IDBConnection $db
|
||||
*/
|
||||
public function __construct(IDBConnection $db) {
|
||||
parent::__construct($db, 'talk_commands', Command::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Command[]
|
||||
*/
|
||||
public function findAll(): array {
|
||||
$query = $this->db->getQueryBuilder();
|
||||
$query->select('*')
|
||||
->from($this->getTableName())
|
||||
->orderBy('id', 'ASC');
|
||||
|
||||
return $this->findEntities($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @return Command
|
||||
* @throws \OCP\AppFramework\Db\DoesNotExistException
|
||||
*/
|
||||
public function findById(int $id): Command {
|
||||
$query = $this->db->getQueryBuilder();
|
||||
$query->select('*')
|
||||
->from($this->getTableName())
|
||||
->where($query->expr()->eq('id', $query->createNamedParameter($id)));
|
||||
|
||||
return $this->findEntity($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $app
|
||||
* @return Command[]
|
||||
*/
|
||||
public function findByApp(string $app): array {
|
||||
$query = $this->db->getQueryBuilder();
|
||||
$query->select('*')
|
||||
->from($this->getTableName())
|
||||
->where($query->expr()->eq('app', $query->createNamedParameter($app)))
|
||||
->orderBy('id', 'ASC');
|
||||
|
||||
return $this->findEntities($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $app
|
||||
* @param string $cmd
|
||||
* @return Command
|
||||
* @throws \OCP\AppFramework\Db\DoesNotExistException
|
||||
*/
|
||||
public function find(string $app, string $cmd): Command {
|
||||
$query = $this->db->getQueryBuilder();
|
||||
$query->select('*')
|
||||
->from($this->getTableName())
|
||||
->where($query->expr()->eq('command', $query->createNamedParameter($cmd)));
|
||||
|
||||
if ($app === '') {
|
||||
$query->andWhere($query->expr()->emptyString('app'));
|
||||
} else {
|
||||
$query->andWhere($query->expr()->eq('app', $query->createNamedParameter($app)));
|
||||
}
|
||||
|
||||
return $this->findEntity($query);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,240 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* @copyright Copyright (c) 2019 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\Service;
|
||||
|
||||
use OCA\Talk\Chat\Command\ShellExecutor;
|
||||
use OCA\Talk\Model\Command;
|
||||
use OCA\Talk\Model\CommandMapper;
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
|
||||
class CommandService {
|
||||
|
||||
public function __construct(
|
||||
protected CommandMapper $mapper,
|
||||
protected ShellExecutor $shellExecutor,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $app
|
||||
* @param string $cmd
|
||||
* @param string $name
|
||||
* @param string $script
|
||||
* @param int $response
|
||||
* @param int $enabled
|
||||
* @return Command
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function create(string $app, string $cmd, string $name, string $script, int $response, int $enabled): Command {
|
||||
try {
|
||||
$this->mapper->find($app, $cmd);
|
||||
throw new \InvalidArgumentException('command', 1);
|
||||
} catch (DoesNotExistException $e) {
|
||||
}
|
||||
|
||||
$command = new Command();
|
||||
$command->setApp($app);
|
||||
$command->setCommand($cmd);
|
||||
$command->setName($name);
|
||||
$command->setScript($script);
|
||||
$command->setResponse($response);
|
||||
$command->setEnabled($enabled);
|
||||
|
||||
$this->validateCommand($command);
|
||||
|
||||
return $this->mapper->insert($command);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @param int $response
|
||||
* @param int $enabled
|
||||
* @return Command
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws DoesNotExistException
|
||||
*/
|
||||
public function updateFromWeb(int $id, int $response, int $enabled): Command {
|
||||
$command = $this->mapper->findById($id);
|
||||
return $this->update($id, $command->getCommand(), $command->getName(), $command->getScript(), $response, $enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @param string $cmd
|
||||
* @param string $name
|
||||
* @param string $script
|
||||
* @param int $response
|
||||
* @param int $enabled
|
||||
* @return Command
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws DoesNotExistException
|
||||
*/
|
||||
public function update(int $id, string $cmd, string $name, string $script, int $response, int $enabled): Command {
|
||||
$command = $this->mapper->findById($id);
|
||||
|
||||
$command->setName($name);
|
||||
$command->setScript($script);
|
||||
$command->setResponse($response);
|
||||
$command->setEnabled($enabled);
|
||||
|
||||
if ($cmd !== $command->getCommand()) {
|
||||
try {
|
||||
$this->mapper->find('', $cmd);
|
||||
throw new \InvalidArgumentException('command', 1);
|
||||
} catch (DoesNotExistException $e) {
|
||||
$command->setCommand($cmd);
|
||||
}
|
||||
}
|
||||
|
||||
$this->validateCommand($command);
|
||||
|
||||
return $this->mapper->update($command);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Command $command
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
protected function validateCommand(Command $command): void {
|
||||
if (preg_match('/^[a-z0-9]{1..64}$/', $command->getCommand())) {
|
||||
throw new \InvalidArgumentException('command', 1);
|
||||
}
|
||||
|
||||
if (preg_match('/^.{1..64}$/', $command->getName())) {
|
||||
throw new \InvalidArgumentException('name', 2);
|
||||
}
|
||||
|
||||
if ($command->getApp() === '' || $command->getApp() === null) {
|
||||
$script = $command->getScript();
|
||||
if (str_starts_with($script, 'alias:')) {
|
||||
try {
|
||||
$this->resolveAlias($command);
|
||||
} catch (DoesNotExistException $e) {
|
||||
throw new \InvalidArgumentException('script', 3);
|
||||
}
|
||||
} elseif ($script !== 'help') {
|
||||
if (preg_match('/[`\'"]{(?:ARGUMENTS|ROOM|USER)}[`\'"]/i', $script)) {
|
||||
throw new \InvalidArgumentException('script-parameters', 6);
|
||||
}
|
||||
if (str_contains($script, '{ARGUMENTS_DOUBLEQUOTE_ESCAPED}')) {
|
||||
throw new \InvalidArgumentException('script-parameters', 6);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->shellExecutor->execShell($script, '--help');
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
throw new \InvalidArgumentException('script', 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!\in_array($command->getResponse(), [Command::RESPONSE_NONE, Command::RESPONSE_USER, Command::RESPONSE_ALL], true)) {
|
||||
throw new \InvalidArgumentException('response', 4);
|
||||
}
|
||||
|
||||
if (!\in_array($command->getEnabled(), [Command::ENABLED_OFF, Command::ENABLED_MODERATOR, Command::ENABLED_USERS, Command::ENABLED_ALL], true)) {
|
||||
throw new \InvalidArgumentException('enabled', 5);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Command $command
|
||||
* @return Command
|
||||
* @throws DoesNotExistException
|
||||
*/
|
||||
public function resolveAlias(Command $command): Command {
|
||||
$script = $command->getScript();
|
||||
if (str_starts_with($script, 'alias:')) {
|
||||
$alias = explode(':', $script, 3);
|
||||
if (isset($alias[2])) {
|
||||
[, $app, $cmd] = $alias;
|
||||
} else {
|
||||
$app = '';
|
||||
$cmd = $alias[1];
|
||||
}
|
||||
|
||||
if ($app === $command->getApp() && $cmd === $command->getCommand()) {
|
||||
throw new DoesNotExistException('The command is an alias for itself');
|
||||
}
|
||||
|
||||
try {
|
||||
return $this->find($app, $cmd);
|
||||
} catch (DoesNotExistException $e) {
|
||||
throw new DoesNotExistException('The command for ' . $command->getCommand() . ' does not exist');
|
||||
}
|
||||
}
|
||||
|
||||
return $command;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @return Command
|
||||
* @throws DoesNotExistException
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function delete(int $id): Command {
|
||||
$command = $this->mapper->findById($id);
|
||||
|
||||
if (($command->getApp() !== '' && $command->getApp() !== null) || $command->getCommand() === 'help') {
|
||||
throw new \InvalidArgumentException('app', 0);
|
||||
}
|
||||
|
||||
return $this->mapper->delete($command);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $app
|
||||
* @param string $cmd
|
||||
* @return Command
|
||||
* @throws DoesNotExistException
|
||||
*/
|
||||
public function find(string $app, string $cmd): Command {
|
||||
return $this->mapper->find($app, $cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $app
|
||||
* @return Command[]
|
||||
*/
|
||||
public function findByApp(string $app): array {
|
||||
return $this->mapper->findByApp($app);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @return Command
|
||||
* @throws DoesNotExistException
|
||||
*/
|
||||
public function findById(int $id): Command {
|
||||
return $this->mapper->findById($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Command[]
|
||||
*/
|
||||
public function findAll(): array {
|
||||
return $this->mapper->findAll();
|
||||
}
|
||||
}
|
||||
|
|
@ -26,10 +26,8 @@ namespace OCA\Talk\Settings\Admin;
|
|||
use OCA\Talk\Config;
|
||||
use OCA\Talk\Exceptions\WrongPermissionsException;
|
||||
use OCA\Talk\MatterbridgeManager;
|
||||
use OCA\Talk\Model\Command;
|
||||
use OCA\Talk\Participant;
|
||||
use OCA\Talk\Room;
|
||||
use OCA\Talk\Service\CommandService;
|
||||
use OCP\AppFramework\Http\TemplateResponse;
|
||||
use OCP\AppFramework\Services\IAppConfig;
|
||||
use OCP\AppFramework\Services\IInitialState;
|
||||
|
|
@ -51,7 +49,6 @@ class AdminSettings implements ISettings {
|
|||
private Config $talkConfig,
|
||||
private IConfig $serverConfig,
|
||||
private IAppConfig $appConfig,
|
||||
private CommandService $commandService,
|
||||
private IInitialState $initialState,
|
||||
private ICacheFactory $memcacheFactory,
|
||||
private IGroupManager $groupManager,
|
||||
|
|
@ -69,7 +66,6 @@ class AdminSettings implements ISettings {
|
|||
public function getForm(): TemplateResponse {
|
||||
$this->initGeneralSettings();
|
||||
$this->initAllowedGroups();
|
||||
$this->initCommands();
|
||||
$this->initFederation();
|
||||
$this->initMatterbridge();
|
||||
$this->initStunServers();
|
||||
|
|
@ -102,16 +98,6 @@ class AdminSettings implements ISettings {
|
|||
$this->initialState->provideInitialState('allowed_groups', $groups);
|
||||
}
|
||||
|
||||
protected function initCommands(): void {
|
||||
$commands = $this->commandService->findAll();
|
||||
|
||||
$result = array_map(function (Command $command) {
|
||||
return $command->asArray();
|
||||
}, $commands);
|
||||
|
||||
$this->initialState->provideInitialState('commands', $result);
|
||||
}
|
||||
|
||||
protected function initFederation(): void {
|
||||
$this->initialState->provideInitialState('federation_enabled', $this->talkConfig->isFederationEnabled());
|
||||
$this->initialState->provideInitialState('federation_incoming_enabled', $this->appConfig->getAppValueBool('federation_incoming_enabled', true));
|
||||
|
|
|
|||
|
|
@ -52,3 +52,5 @@ nav:
|
|||
- 'Overview': 'TURN.md'
|
||||
- 'coTURN': 'coturn.md'
|
||||
- 'eturnal': 'eturnal.md'
|
||||
- 'Removed features':
|
||||
- 'Commands': 'commands.md'
|
||||
|
|
|
|||
|
|
@ -1,28 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
CALCULATOR=$(which "bc")
|
||||
if ! [ -x "$CALCULATOR" ]; then
|
||||
echo "Basic calculator package (bc - https://www.gnu.org/software/bc/) not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
while test $# -gt 0; do
|
||||
case "$1" in
|
||||
--help)
|
||||
echo "/calc - A basic calculator for Nextcloud Talk based on gnu BC"
|
||||
echo "See the official documentation for more information:"
|
||||
echo "https://www.gnu.org/software/bc/manual/html_mono/bc.html"
|
||||
echo " "
|
||||
echo "Simple equations: /calc 3 + 4 * 5"
|
||||
echo "Complex equations: /calc sin(3) + 3^3 * sqrt(5)"
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
set -f
|
||||
echo "$@ ="
|
||||
echo $(echo "$@" | bc)
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* @copyright Copyright (c) 2019 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
if (PHP_SAPI !== 'cli') {
|
||||
// Only allow access via the console
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($argc < 2) {
|
||||
echo 'Missing search term in call to hackernews.php';
|
||||
return 1;
|
||||
}
|
||||
|
||||
$mode = $argv[1];
|
||||
|
||||
if ($mode === '--help' || !in_array($mode, ['top', 'new', 'best', ''], true)) {
|
||||
echo '/hackernews - A simple command to list the Top 5 top, new or best stories' . "\n";
|
||||
echo "\n";
|
||||
echo 'Example: /hackernews top' . "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
$mode = $mode ?: 'top';
|
||||
$endpoint = 'https://hacker-news.firebaseio.com/v0/' . $mode . 'stories.json';
|
||||
$content = file_get_contents($endpoint);
|
||||
$results = json_decode($content, true);
|
||||
$stories = array_slice($results, 0, 5);
|
||||
|
||||
$response = 'Hackernews ' . ucfirst($mode) . ' 5:' . "\n";
|
||||
$length = 120;
|
||||
|
||||
foreach ($stories as $storyId) {
|
||||
$endpoint = 'https://hacker-news.firebaseio.com/v0/item/' . $storyId . '.json';
|
||||
$content = file_get_contents($endpoint);
|
||||
$result = json_decode($content, true);
|
||||
|
||||
$link = " - {$result['url']}\n";
|
||||
$remainingLength = max(strlen($result['title']), $length - strlen($link));
|
||||
if ($remainingLength < strlen('* ' . $result['title'])) {
|
||||
$response .= substr('* ' . $result['title'], 0, $remainingLength) . '…' . $link;
|
||||
} else {
|
||||
$response .= '* ' . $result['title'] . $link;
|
||||
}
|
||||
}
|
||||
|
||||
$page = 'news';
|
||||
if ($mode === 'new') {
|
||||
$page = 'newest';
|
||||
} elseif ($mode === 'best') {
|
||||
$page = 'best';
|
||||
}
|
||||
|
||||
$response .= "Find more at https://news.ycombinator.com/$page";
|
||||
|
||||
echo($response);
|
||||
|
|
@ -1,87 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* @copyright Copyright (c) 2019 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
if (PHP_SAPI !== 'cli') {
|
||||
// Only allow access via the console
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($argc < 2) {
|
||||
echo 'Missing search term in call to wikipedia.php';
|
||||
return 1;
|
||||
}
|
||||
|
||||
$searchTerm = $argv[1];
|
||||
|
||||
if ($searchTerm === '--help') {
|
||||
echo '/wiki - A simple command to find wikipedia articles for a term' . "\n";
|
||||
echo "\n";
|
||||
echo 'Example: /wiki Nextcloud' . "\n";
|
||||
$searchTerm = 'Nextcloud';
|
||||
}
|
||||
|
||||
|
||||
$endpoint = 'https://en.wikipedia.org/w/api.php';
|
||||
$parameters = [
|
||||
'action' => 'query',
|
||||
'generator' => 'prefixsearch',
|
||||
'gpssearch' => $searchTerm,
|
||||
'prop' => 'description|info',
|
||||
'format' => 'json',
|
||||
'formatversion' => 2,
|
||||
'inprop' => 'url',
|
||||
];
|
||||
$content = file_get_contents($endpoint . '?' . http_build_query($parameters));
|
||||
$results = json_decode($content, true);
|
||||
|
||||
if (empty($results['query']['pages'])) {
|
||||
echo 'Wikipedia did not have any results for "' . $searchTerm . '" :(' . "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
$pages = $results['query']['pages'];
|
||||
$numArticles = count($pages);
|
||||
|
||||
$response = 'Wikipedia search results for "' . $searchTerm . '":' . "\n";
|
||||
$maxArticles = $numArticles > 7 ? 5 : $numArticles;
|
||||
$length = (int) ((800 - strlen($response)) / $maxArticles);
|
||||
|
||||
foreach ($pages as $key => $page) {
|
||||
if ($key >= $maxArticles) {
|
||||
break;
|
||||
}
|
||||
|
||||
$link = " - {$page['canonicalurl']}\n";
|
||||
$remainingLength = max(strlen($page['title']), $length - strlen($link));
|
||||
if ($remainingLength < strlen("* {$page['title']} - {$page['description']}")) {
|
||||
$response .= substr("* {$page['title']} - {$page['description']}", 0, $remainingLength) . '…' . $link;
|
||||
} else {
|
||||
$response .= "* {$page['title']} - {$page['description']}" . $link;
|
||||
}
|
||||
}
|
||||
|
||||
if ($maxArticles < $numArticles) {
|
||||
$response .= '* and ' . ($numArticles - $maxArticles) ." more articles found\n";
|
||||
}
|
||||
|
||||
echo($response);
|
||||
|
|
@ -1,144 +0,0 @@
|
|||
<!--
|
||||
- @copyright Copyright (c) 2019 Joas Schilling <coding@schilljs.com>
|
||||
-
|
||||
- @author Joas Schilling <coding@schilljs.com>
|
||||
-
|
||||
- @license AGPL-3.0-or-later
|
||||
-
|
||||
- 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/>.
|
||||
-
|
||||
-->
|
||||
|
||||
<template>
|
||||
<section id="chat_commands" class="commands section">
|
||||
<h2>
|
||||
{{ t('spreed', 'Commands') }}
|
||||
<small>{{ t('spreed', 'Deprecated') }}</small>
|
||||
</h2>
|
||||
|
||||
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||
<p class="settings-hint" v-html="commandHint" />
|
||||
|
||||
<div id="commands_list">
|
||||
<div class="head name">
|
||||
{{ t('spreed', 'Name') }}
|
||||
</div>
|
||||
<div class="head command">
|
||||
{{ t('spreed', 'Command') }}
|
||||
</div>
|
||||
<div class="head script">
|
||||
{{ t('spreed', 'Script') }}
|
||||
</div>
|
||||
<div class="head response">
|
||||
{{ t('spreed', 'Response to') }}
|
||||
</div>
|
||||
<div class="head enabled">
|
||||
{{ t('spreed', 'Enabled for') }}
|
||||
</div>
|
||||
|
||||
<template v-for="command in commands">
|
||||
<div :key="`${command.id}_name`" class="name">
|
||||
{{ command.name }}
|
||||
</div>
|
||||
<div :key="`${command.id}_command`" class="command">
|
||||
{{ command.command }}
|
||||
</div>
|
||||
<div :key="`${command.id}_script`" class="script">
|
||||
{{ command.script }}
|
||||
</div>
|
||||
<div :key="`${command.id}_response`" class="response">
|
||||
{{ translateResponse(command.response) }}
|
||||
</div>
|
||||
<div :key="`${command.id}_enabled`" class="enabled">
|
||||
{{ translateEnabled(command.enabled) }}
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { loadState } from '@nextcloud/initial-state'
|
||||
|
||||
export default {
|
||||
name: 'Commands',
|
||||
|
||||
data() {
|
||||
return {
|
||||
commands: {},
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
commandHint() {
|
||||
return t('spreed', 'Commands are a new beta feature in Nextcloud Talk. They allow you to run scripts on your Nextcloud server. You can define them with our command line interface. An example of a calculator script can be found in our {linkstart}documentation{linkend}.')
|
||||
.replace('{linkstart}', '<a target="_blank" rel="noreferrer nofollow" class="external" href="https://nextcloud-talk.readthedocs.io/en/latest/commands/">')
|
||||
.replace('{linkend}', ' ↗</a>')
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.commands = loadState('spreed', 'commands')
|
||||
},
|
||||
|
||||
methods: {
|
||||
translateResponse(response) {
|
||||
switch (response) {
|
||||
case 0:
|
||||
return t('spreed', 'None')
|
||||
case 1:
|
||||
return t('spreed', 'User')
|
||||
default:
|
||||
return t('spreed', 'Everyone')
|
||||
}
|
||||
},
|
||||
translateEnabled(enabled) {
|
||||
switch (enabled) {
|
||||
case 0:
|
||||
return t('spreed', 'Disabled')
|
||||
case 1:
|
||||
return t('spreed', 'Moderators')
|
||||
case 2:
|
||||
return t('spreed', 'Users')
|
||||
default:
|
||||
return t('spreed', 'Everyone')
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.commands.section {
|
||||
#commands_list {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(100px, 200px) minmax(100px, 200px) 1fr minmax(100px, 200px) minmax(100px, 200px);
|
||||
grid-column-gap: 5px;
|
||||
grid-row-gap: 10px;
|
||||
|
||||
.head {
|
||||
padding-bottom: 5px;
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
small {
|
||||
color: var(--color-warning);
|
||||
border: 1px solid var(--color-warning);
|
||||
border-radius: 16px;
|
||||
padding: 0 9px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -499,7 +499,7 @@ export default {
|
|||
return false // Edited messages are not grouped
|
||||
}
|
||||
|
||||
if (message1.actorType === ATTENDEE.ACTOR_TYPE.BOTS // Don't group messages of commands and bots
|
||||
if (message1.actorType === ATTENDEE.ACTOR_TYPE.BOTS // Don't group messages of bots
|
||||
&& message1.actorId !== ATTENDEE.CHANGELOG_BOT_ID) { // Apart from the changelog bot
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -693,8 +693,7 @@ const actions = {
|
|||
/**
|
||||
* Only use the last message as lastMessage when:
|
||||
* 1. It's not a command reply
|
||||
* 2. It's not a temporary message starting with "/" which is a user posting a command
|
||||
* 3. It's not a reaction or deletion of a reaction
|
||||
* 2. It's not a reaction or deletion of a reaction
|
||||
* 3. It's not a deletion of a message
|
||||
*/
|
||||
if ((lastMessage.actorType !== ATTENDEE.ACTOR_TYPE.BOTS
|
||||
|
|
@ -704,10 +703,7 @@ const actions = {
|
|||
&& lastMessage.systemMessage !== 'reaction_deleted'
|
||||
&& lastMessage.systemMessage !== 'reaction_revoked'
|
||||
&& lastMessage.systemMessage !== 'message_deleted'
|
||||
&& lastMessage.systemMessage !== 'message_edited'
|
||||
&& !(typeof lastMessage.id.startsWith === 'function'
|
||||
&& lastMessage.id.startsWith('temp-')
|
||||
&& lastMessage.message.startsWith('/'))) {
|
||||
&& lastMessage.systemMessage !== 'message_edited') {
|
||||
commit('updateConversationLastMessage', { token, lastMessage })
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1202,28 +1202,6 @@ describe('conversationsStore', () => {
|
|||
const changedConversation = store.getters.conversation(testToken)
|
||||
expect(changedConversation.lastMessage).toBe(testLastMessage)
|
||||
})
|
||||
|
||||
test('ignore update from temporary if posting a command', () => {
|
||||
const testLastMessage = {
|
||||
actorType: 'users',
|
||||
actorId: 'admin',
|
||||
systemMessage: '',
|
||||
id: 'temp-42',
|
||||
message: '/quit',
|
||||
}
|
||||
|
||||
testConversation.lastMessage = previousLastMessage
|
||||
|
||||
store.dispatch('addConversation', testConversation)
|
||||
|
||||
store.dispatch('updateConversationLastMessage', {
|
||||
token: testToken,
|
||||
lastMessage: testLastMessage,
|
||||
})
|
||||
|
||||
const changedConversation = store.getters.conversation(testToken)
|
||||
expect(changedConversation.lastMessage).toBe(previousLastMessage)
|
||||
})
|
||||
})
|
||||
|
||||
describe('creating conversations', () => {
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@
|
|||
<AllowedGroups />
|
||||
<Federation v-if="supportFederation" />
|
||||
<BotsSettings />
|
||||
<Commands />
|
||||
<WebServerSetupChecks />
|
||||
<StunServers />
|
||||
<TurnServers />
|
||||
|
|
@ -43,7 +42,6 @@ import { getCapabilities } from '@nextcloud/capabilities'
|
|||
|
||||
import AllowedGroups from '../components/AdminSettings/AllowedGroups.vue'
|
||||
import BotsSettings from '../components/AdminSettings/BotsSettings.vue'
|
||||
import Commands from '../components/AdminSettings/Commands.vue'
|
||||
import Federation from '../components/AdminSettings/Federation.vue'
|
||||
import GeneralSettings from '../components/AdminSettings/GeneralSettings.vue'
|
||||
import HostedSignalingServer from '../components/AdminSettings/HostedSignalingServer.vue'
|
||||
|
|
@ -63,7 +61,6 @@ export default {
|
|||
components: {
|
||||
AllowedGroups,
|
||||
BotsSettings,
|
||||
Commands,
|
||||
Federation,
|
||||
GeneralSettings,
|
||||
HostedSignalingServer,
|
||||
|
|
|
|||
|
|
@ -14,14 +14,6 @@
|
|||
<p class="settings-hint"><?php p($l->t('Users that cannot use Talk anymore will still be listed as participants in their previous conversations and also their chat messages will be kept.')); ?></p>
|
||||
</div>
|
||||
|
||||
<div class="videocalls section" id="chat_commands">
|
||||
<h2><?php p($l->t('Commands')) ?></h2>
|
||||
<p class="settings-hint"><?php p($l->t('Specify commands the users can use in chats')); ?></p>
|
||||
|
||||
<div class="commands">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="stun_server" class="videocalls section">
|
||||
<h2><?php p($l->t('STUN servers')) ?></h2>
|
||||
<p class="settings-hint"><?php p($l->t('A STUN server is used to determine the public IP address of participants behind a router.')); ?></p>
|
||||
|
|
|
|||
|
|
@ -1,44 +1,39 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<files psalm-version="5.17.0@c620f6e80d0abfca532b00bda366062aaedf6e5d">
|
||||
<files psalm-version="5.23.1@8471a896ccea3526b26d082f4461eeea467f10a4">
|
||||
<file src="lib/AppInfo/Application.php">
|
||||
<UndefinedClass>
|
||||
<code>BeforeTemplateRenderedEvent</code>
|
||||
<code>BeforeTemplateRenderedEvent</code>
|
||||
<code><![CDATA[BeforeTemplateRenderedEvent]]></code>
|
||||
<code><![CDATA[BeforeTemplateRenderedEvent]]></code>
|
||||
</UndefinedClass>
|
||||
</file>
|
||||
<file src="lib/BackgroundJob/CheckReferenceIdColumn.php">
|
||||
<UndefinedClass>
|
||||
<code>SchemaWrapper</code>
|
||||
<code><![CDATA[SchemaWrapper]]></code>
|
||||
</UndefinedClass>
|
||||
</file>
|
||||
<file src="lib/Chat/ChatManager.php">
|
||||
<UndefinedClass>
|
||||
<code>NullCache</code>
|
||||
<code><![CDATA[NullCache]]></code>
|
||||
</UndefinedClass>
|
||||
</file>
|
||||
<file src="lib/Chat/MessageParser.php">
|
||||
<UndefinedVariable>
|
||||
<code>$guestNames</code>
|
||||
<code><![CDATA[$guestNames]]></code>
|
||||
</UndefinedVariable>
|
||||
</file>
|
||||
<file src="lib/Chat/Parser/SystemMessage.php">
|
||||
<UndefinedClass>
|
||||
<code>\OC_Util</code>
|
||||
<code><![CDATA[\OC_Util]]></code>
|
||||
</UndefinedClass>
|
||||
</file>
|
||||
<file src="lib/Command/Command/AddSamples.php">
|
||||
<ForbiddenCode>
|
||||
<code><![CDATA[shell_exec('which bc')]]></code>
|
||||
</ForbiddenCode>
|
||||
</file>
|
||||
<file src="lib/Config.php">
|
||||
<NullArgument>
|
||||
<code>null</code>
|
||||
<code><![CDATA[null]]></code>
|
||||
</NullArgument>
|
||||
</file>
|
||||
<file src="lib/Controller/TempAvatarController.php">
|
||||
<UndefinedClass>
|
||||
<code>Filesystem</code>
|
||||
<code><![CDATA[Filesystem]]></code>
|
||||
</UndefinedClass>
|
||||
</file>
|
||||
<file src="lib/Federation/Authenticator.php">
|
||||
|
|
@ -48,7 +43,7 @@
|
|||
</file>
|
||||
<file src="lib/Files/Util.php">
|
||||
<InvalidArgument>
|
||||
<code>$fileId</code>
|
||||
<code><![CDATA[$fileId]]></code>
|
||||
</InvalidArgument>
|
||||
</file>
|
||||
<file src="lib/MatterbridgeManager.php">
|
||||
|
|
@ -56,7 +51,7 @@
|
|||
<code><![CDATA[$this->tokenProvider]]></code>
|
||||
<code><![CDATA[$this->tokenProvider]]></code>
|
||||
<code><![CDATA[$this->tokenProvider]]></code>
|
||||
<code>private</code>
|
||||
<code><![CDATA[private]]></code>
|
||||
</UndefinedClass>
|
||||
</file>
|
||||
<file src="lib/Migration/Version2001Date20170707115443.php">
|
||||
|
|
@ -73,30 +68,30 @@
|
|||
</file>
|
||||
<file src="lib/PublicShare/TemplateLoader.php">
|
||||
<UndefinedClass>
|
||||
<code>BeforeTemplateRenderedEvent</code>
|
||||
<code><![CDATA[BeforeTemplateRenderedEvent]]></code>
|
||||
</UndefinedClass>
|
||||
</file>
|
||||
<file src="lib/PublicShareAuth/TemplateLoader.php">
|
||||
<UndefinedClass>
|
||||
<code>BeforeTemplateRenderedEvent</code>
|
||||
<code><![CDATA[BeforeTemplateRenderedEvent]]></code>
|
||||
</UndefinedClass>
|
||||
</file>
|
||||
<file src="lib/Service/AvatarService.php">
|
||||
<UndefinedClass>
|
||||
<code>Filesystem</code>
|
||||
<code>\OC_Image</code>
|
||||
<code><![CDATA[Filesystem]]></code>
|
||||
<code><![CDATA[\OC_Image]]></code>
|
||||
</UndefinedClass>
|
||||
</file>
|
||||
<file src="lib/Service/RecordingService.php">
|
||||
<LessSpecificReturnStatement>
|
||||
<code>$recordingFolder</code>
|
||||
<code><![CDATA[$recordingFolder]]></code>
|
||||
</LessSpecificReturnStatement>
|
||||
<MoreSpecificReturnType>
|
||||
<code>Folder</code>
|
||||
<code><![CDATA[Folder]]></code>
|
||||
</MoreSpecificReturnType>
|
||||
<UndefinedClass>
|
||||
<code>NoUserException</code>
|
||||
<code>NoUserException</code>
|
||||
<code><![CDATA[NoUserException]]></code>
|
||||
<code><![CDATA[NoUserException]]></code>
|
||||
</UndefinedClass>
|
||||
</file>
|
||||
<file src="lib/Share/Listener.php">
|
||||
|
|
@ -104,20 +99,20 @@
|
|||
<code><![CDATA[$event->getView()]]></code>
|
||||
<code><![CDATA[$event->getView()]]></code>
|
||||
<code><![CDATA[$event->getView()]]></code>
|
||||
<code>$view</code>
|
||||
<code>$view</code>
|
||||
<code>$view</code>
|
||||
<code>Filesystem</code>
|
||||
<code><![CDATA[$view]]></code>
|
||||
<code><![CDATA[$view]]></code>
|
||||
<code><![CDATA[$view]]></code>
|
||||
<code><![CDATA[Filesystem]]></code>
|
||||
</UndefinedClass>
|
||||
</file>
|
||||
<file src="lib/Share/RoomShareProvider.php">
|
||||
<UndefinedClass>
|
||||
<code>Cache</code>
|
||||
<code><![CDATA[Cache]]></code>
|
||||
</UndefinedClass>
|
||||
</file>
|
||||
<file src="lib/TInitialState.php">
|
||||
<UndefinedClass>
|
||||
<code>NoUserException</code>
|
||||
<code><![CDATA[NoUserException]]></code>
|
||||
</UndefinedClass>
|
||||
</file>
|
||||
</files>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue