Skip to content

Commit b176ea1

Browse files
committed
ENHANCEMENTS:
- Commands: migrated to slash commands BUGFIXES: - Some former migrations did not re-read the configuration properly.
1 parent b9f4e63 commit b176ea1

File tree

17 files changed

+618
-188
lines changed

17 files changed

+618
-188
lines changed

core/plugin.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
from discord.utils import MISSING, _shorten
2323
from packaging.version import parse
2424
from pathlib import Path
25-
from typing import Type, Optional, TYPE_CHECKING, Union, Any, Dict, Callable, List, Generic
25+
from typing import Type, Optional, TYPE_CHECKING, Union, Any, Callable, Generic
2626

2727
from .const import DEFAULT_TAG
2828
from .listener import TEventListener
@@ -59,7 +59,7 @@ def command(
5959
description: Union[str, locale_str] = MISSING,
6060
nsfw: bool = False,
6161
auto_locale_strings: bool = True,
62-
extras: Dict[Any, Any] = MISSING,
62+
extras: dict[Any, Any] = MISSING,
6363
) -> Callable[[CommandCallback[GroupT, P, T]], Command[GroupT, P, T]]:
6464
"""Creates an application command from a regular function.
6565
@@ -122,9 +122,9 @@ def __init__(
122122
callback: CommandCallback[GroupT, P, T],
123123
nsfw: bool = False,
124124
parent: Optional[Group] = None,
125-
guild_ids: Optional[List[int]] = None,
125+
guild_ids: Optional[list[int]] = None,
126126
auto_locale_strings: bool = True,
127-
extras: Dict[Any, Any] = MISSING,
127+
extras: dict[Any, Any] = MISSING,
128128
):
129129
from services.bot import BotService
130130

@@ -142,7 +142,7 @@ def __init__(
142142
((num_servers == 1 and nodes == 1) or not bot.locals.get('channels', {}).get('admin'))):
143143
del self._params['server']
144144

145-
async def _do_call(self, interaction: Interaction, params: Dict[str, Any]) -> T:
145+
async def _do_call(self, interaction: Interaction, params: dict[str, Any]) -> T:
146146
if 'node' in inspect.signature(self._callback).parameters and 'node' not in params:
147147
params['node'] = interaction.client.node
148148
if 'server' in inspect.signature(self._callback).parameters and 'server' not in params:
@@ -175,7 +175,7 @@ def command(
175175
description: Union[str, locale_str] = MISSING,
176176
nsfw: bool = False,
177177
auto_locale_strings: bool = True,
178-
extras: Dict[Any, Any] = MISSING,
178+
extras: dict[Any, Any] = MISSING,
179179
) -> Callable[[CommandCallback[GroupT, P, T]], Command[GroupT, P, T]]:
180180
"""A decorator that creates an application command from a regular function under this group.
181181

core/utils/validators.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030

3131
__all__ = [
3232
"file_exists",
33+
"dir_exists",
3334
"seq_or_map",
3435
"bool_or_map",
3536
"str_or_map",
@@ -115,15 +116,21 @@ def get_node_data() -> NodeData:
115116
return NodeData()
116117

117118
def file_exists(value, _, path):
118-
if path and path.split("/")[1] in [DEFAULT_TAG, COMMAND_LINE_ARGS.node]:
119+
if path and path.split("/")[1] in [DEFAULT_TAG, COMMAND_LINE_ARGS.node, 'backups', 'commands']:
119120
filename = os.path.expandvars(value)
121+
# do not check files with replacements
122+
if '{' in filename:
123+
return True
120124
if not os.path.exists(filename) or not os.path.isfile(filename):
121125
raise SchemaError(msg=f'File "{value}" does not exist or is no file', path=path)
122126
return True
123127

124128
def dir_exists(value, _, path):
125-
if path and path.split("/")[1] in [DEFAULT_TAG, COMMAND_LINE_ARGS.node]:
129+
if path and path.split("/")[1] in [DEFAULT_TAG, COMMAND_LINE_ARGS.node, 'backups', 'commands']:
126130
filename = os.path.expandvars(value)
131+
# do not check dirs with replacements
132+
if '{' in filename:
133+
return True
127134
if not os.path.exists(filename) or not os.path.isdir(filename):
128135
raise SchemaError(msg=f'Directory "{value}" does not exist or is no directory', path=path)
129136
return True

migrate.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -298,14 +298,6 @@ def migrate_3(node: str):
298298
if plugin_name in ['backup', 'ovgme', 'music']:
299299
shutil.move(f'config/plugins/{plugin_name}.yaml', f'config/services/{plugin_name}.yaml')
300300
print(f"- Migrated config/{plugin_name}.json to config/services/{plugin_name}.yaml")
301-
elif plugin_name == 'commands':
302-
data = yaml.load(Path('config/plugins/commands.yaml').read_text(encoding='utf-8'))
303-
data[DEFAULT_TAG] = {
304-
"command_prefix": cfg['BOT']['COMMAND_PREFIX']
305-
}
306-
with open('config/plugins/commands.yaml', mode='w', encoding='utf-8') as out:
307-
yaml.dump(data, out)
308-
print("- Migrated config/commands.json to config/plugins/commands.yaml")
309301
else:
310302
print(f"- Migrated config/{plugin_name}.json to config/plugins/{plugin_name}.yaml")
311303

plugins/commands/README.md

Lines changed: 107 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,31 +11,114 @@ opt_plugins:
1111
1212
The plugin itself needs to be configured with a yaml file in config/plugins/commands.yaml. Each command has a name and
1313
parameters. These parameters can be used in the arguments you use to call your external program. The sample shows how
14-
to launch DCS from a specific command (not really useful as you have .startup, but you get the idea) and dir as a shell
15-
command.
14+
to launch DCS from a specific command (not really useful as you have `/server startup`, but you get the idea) and `dir`
15+
as a shell command.
1616

1717
```yaml
1818
commands:
19-
- name: dcs # Create a command .dcs
20-
roles: # that can be run by the DCS Admin role
21-
- DCS Admin
22-
execute: # and map it to a call of DCS_server.exe
23-
cmd: DCS_server.exe
24-
args: -w {instance}
25-
cwd: C:\Program Files\Eagle Dynamics\DCS World Server\bin
26-
params: # which receives a parameter "instance" (will be auto replaced by the instance name)
27-
- instance
28-
- name: dir # Create a command .dir
29-
roles: # which can be run by Admin and DCS Admin
30-
- Admin
31-
- DCS Admin
32-
execute: # and that maps to a shell command "dir c:\"
33-
cmd: dir
34-
cwd: C:\
35-
shell: true
36-
hidden: true # the .dir command will not apply in the help command
19+
startup: # Create a command /startup
20+
roles: # that can be run by the DCS Admin role
21+
- DCS Admin
22+
execute: # and map it to a call of DCS_server.exe
23+
cmd: DCS_server.exe
24+
args: -w {instance.name}
25+
cwd: C:\Program Files\Eagle Dynamics\DCS World Server\bin
26+
params: # parameter list
27+
instance: # instance parameters have auto completion
28+
required: true # mandatory parameter
29+
dir: # Command /dir
30+
description: shows a directory listing
31+
roles: # dir can be executed be Admin and DCS Admin
32+
- Admin
33+
- DCS Admin
34+
execute:
35+
shell: true # Run dir as a shell command. You want to use this also for bat or cmd files.
36+
cmd: dir
37+
cwd: '{path}'
38+
args: '{option}'
39+
params:
40+
option:
41+
description: Options for the dir command
42+
type: str
43+
required: false
44+
path:
45+
description: Directory listing of this path
46+
type: str
47+
required: false
48+
default: C:\Program Files\Eagle Dynamics\DCS World
49+
setflag:
50+
roles:
51+
- DCS Admin
52+
event: # Instead of running a command, send an event to DCS
53+
command: setFlag # setFlag takes 2 parameters
54+
flag: '{flag}'
55+
value: '{value}'
56+
params:
57+
server: # we need to provide a server for events, otherwise they will be run on all servers
58+
required: true
59+
flag:
60+
description: Flag to be set
61+
required: true
62+
type: int
63+
choices:
64+
- 100
65+
- 110
66+
- 120
67+
value:
68+
description: Value to set
69+
type: int
70+
required: true
71+
choices:
72+
- 1
73+
- 2
74+
- 3
3775
```
38-
> [!NOTE]
39-
> * DCSServerBot needs to have the permissions to launch the respective executable!
40-
> * Do not run long-running shell scripts!
41-
> + These commands are NO slash commands, so they start with another prefix, set in the configuration!
76+
> [!IMPORTANT]
77+
> DCSServerBot needs to have the permission to launch the respective executables.
78+
79+
> [!WARNING]
80+
> Do **not** run long-running shell scripts.
81+
> Normal tasks can be long-running. You have commands to terminate them (see below).
82+
83+
### Parameter Structure
84+
```yaml
85+
params:
86+
name: # name of the parameter
87+
type: str # One of str, int, bool, member, channel, role, mentionable, number, attachment
88+
description: xxx # description of the parameter
89+
required: true # default: false
90+
default: xxx # A value to be set as default, if required = false. If not set, NONE will be applied.
91+
nsfw: false # Commands for NSFW-channels, default: false
92+
min_value: 0 # Optional: min value for range
93+
max_value: 10 # Optional: max value for range
94+
choices: # Optional: choice of values (type must match the type above)
95+
- A
96+
- B
97+
- C
98+
```
99+
100+
### Special Parameters
101+
102+
The following special parameters are supported and will be replaced by auto-completion if available:
103+
- node
104+
- instance
105+
- server
106+
- user
107+
- member
108+
- channel
109+
- role
110+
111+
These parameters will be passed as objects.<br>
112+
You can keep it simple in the params section:
113+
```yaml
114+
params:
115+
server:
116+
required: true
117+
```
118+
119+
## Discord Commands
120+
121+
| Command | Parameter | Channel | Role | Description |
122+
|:--------------------|:----------|:--------|:------|:-------------------------------------------------------------|
123+
| /commands tasklist | | all | Admin | Show all running processes that were started by this plugin. |
124+
| /commands terminate | process | all | Admin | Terminate a running process. |

0 commit comments

Comments
 (0)