2
2
3
3
import discord
4
4
from discord .ext import commands
5
+ from pydantic import TypeAdapter , ValidationError
5
6
6
7
from zeusops_bot .errors import (
7
8
ConfigFileInvalidJson ,
8
9
ConfigFileNotFound ,
9
10
ConfigPatchingError ,
10
11
)
11
- from zeusops_bot .reforger_config_gen import ReforgerConfigGenerator
12
+ from zeusops_bot .models import ModDetail
13
+ from zeusops_bot .reforger_config_gen import ReforgerConfigGenerator , extract_mods
14
+ from zeusops_bot .settings import ZeusopsBotConfig
15
+
16
+ modlist_typeadapter = TypeAdapter (list [ModDetail ])
12
17
13
18
14
19
class ZeusUpload (commands .Cog ):
15
20
"""ZeusUpload cog for handling mission uploads"""
16
21
17
- def __init__ (self , bot , config ):
22
+ def __init__ (self , bot : discord . Bot , config : ZeusopsBotConfig ):
18
23
"""Initialise the cog"""
19
24
self .bot = bot
20
25
self .config = config
@@ -24,31 +29,66 @@ def __init__(self, bot, config):
24
29
)
25
30
26
31
@commands .slash_command (name = "zeus-upload" )
32
+ @discord .option (
33
+ "modlist" ,
34
+ description = "Modlist JSON exported from Reforger" ,
35
+ input_type = discord .SlashCommandOptionType .attachment ,
36
+ required = False ,
37
+ )
27
38
async def zeus_upload (
28
- self , ctx : discord .ApplicationContext , scenario_id : str , filename : str
39
+ self ,
40
+ ctx : discord .ApplicationContext ,
41
+ scenario_id : str ,
42
+ filename : str ,
43
+ modlist : discord .Attachment | None = None ,
29
44
):
30
45
"""Upload a mission as a Zeus"""
31
- try : # TODO: How do we pass modlist != None
46
+ extracted_mods = None
47
+ try :
48
+ if modlist is not None :
49
+ data = await modlist .read ()
50
+ extracted_mods = extract_mods (data .decode ())
51
+ except ConfigFileInvalidJson as e :
52
+ await ctx .respond (
53
+ "Failed to understand the attached modlist as JSON. "
54
+ "Check the file was exported from the workshop, "
55
+ "try confirming with an online validator like "
56
+ "<https://jsonlint.com/>.\n \n "
57
+ f"Parse error was:\n ```\n { e } \n ```"
58
+ )
59
+ return
60
+ except ValidationError as e :
61
+ await ctx .respond (
62
+ "Failed to understand the modlist given: valid JSON, "
63
+ "but not a list of mod objects (name/ID/optional-version). "
64
+ "Check the file was exported from the workshop.\n \n "
65
+ f"Error was:\n ```\n { e } \n ```"
66
+ )
67
+ return
68
+ try :
32
69
path = self .reforger_confgen .zeus_upload (
33
- scenario_id , filename , modlist = None
70
+ scenario_id , filename , modlist = extracted_mods
34
71
)
35
- await ctx .respond (f"Mission uploaded successfully under { path = } " )
36
72
except ConfigFileNotFound :
37
73
await ctx .respond (
38
74
"Bot config error: the base config file could not be found"
39
- " Tell the Techmins! Path was: "
40
- + str (self .reforger_confgen .base_config )
75
+ f" Tell the Techmins! Path was: { self .reforger_confgen .base_config } "
41
76
)
77
+ return
42
78
except ConfigFileInvalidJson as e :
43
79
await ctx .respond (
44
80
"Bot config error: the base config file is invalid JSON "
45
- "Tell the Techmins! Error was: " + str (e )
81
+ "Tell the Techmins!\n \n "
82
+ f"Error was:\n ```\n { e } \n ```"
46
83
)
84
+ return
47
85
except ConfigPatchingError as e :
48
86
await ctx .respond (
49
- "Failed to patch your requested change over base config.\n "
50
- f"Error was: { str ( e ) } "
87
+ "Failed to patch your requested change over base config.\n \n "
88
+ f"Error was:\n ``` \n { e } \n ``` "
51
89
)
90
+ return
91
+ await ctx .respond (f"Mission uploaded successfully under { path = } " )
52
92
53
93
@commands .slash_command (name = "zeus-set-mission" )
54
94
async def zeus_set_mission (self , ctx : discord .ApplicationContext , filename : str ):
@@ -77,11 +117,11 @@ async def current_mission(self, ctx: discord.ApplicationContext):
77
117
f"Current mission: `{ self .reforger_confgen .current_mission ()} `"
78
118
)
79
119
except ConfigFileNotFound as e :
80
- await ctx .respond (f"Could not find configured mission: { str ( e ) } " )
120
+ await ctx .respond (f"Could not find configured mission: { e } " )
81
121
82
122
@commands .Cog .listener ()
83
123
async def on_application_command_error (
84
124
self , ctx : discord .ApplicationContext , error : discord .DiscordException
85
125
):
86
126
"""Handles application command errors that are not caught elsewhere"""
87
- await ctx .respond (f"Unhandled exception: { error } " )
127
+ await ctx .respond (f"Unhandled exception: \n \n Error was: { error } " )
0 commit comments