@@ -173,50 +173,67 @@ async def on_submit(self, interaction: discord.Interaction) -> None:
173173 Args:
174174 interaction: The submission interaction from Discord.
175175 """
176- command_name = utils .sanitize_user_command_name (self .command_name .value )
177- command_name_no_wildcard = command_name .split ("+" )[0 ].strip ()
176+ locale = str (interaction .locale ) if interaction .locale else CONFIG .default_locale
177+ index = self ._ctx .bot .permission_command_index (locale )
178+
179+ canonical = index .resolve (self .command_name .value )
180+ if canonical is None :
181+ await interaction .response .send_message (
182+ self ._ctx .translate (
183+ _ (
184+ "ftl-cmd-profile-override-command-not-found" ,
185+ command = self .command_name .value ,
186+ )
187+ ),
188+ ephemeral = True ,
189+ )
190+ return
191+
192+ base = canonical .removesuffix ("+" )
178193
179194 for bot_command in self ._ctx .bot .walk_commands ():
180- bot_command_name = utils . get_command_name (bot_command )
181- if bot_command_name == command_name_no_wildcard :
182- if "+" in command_name and not isinstance ( bot_command , commands . Group ):
183- command_name = command_name_no_wildcard
195+ if self . _ctx . bot . get_canonical_command_name (bot_command ) == base :
196+ if canonical != base and not isinstance ( bot_command , commands . Group ) :
197+ canonical = base # wildcards only apply to groups
198+
184199 if self ._ctx .bot .get_command_access_level (bot_command ) == RequiredAccessLevel .owner :
200+ # Only actual owner allowed to override owner-only commands
185201 if not await self ._ctx .bot .is_owner (self ._ctx .author ):
186202 await interaction .response .send_message (
187- self ._ctx .translate (_ ("ftl-cmd-profile-override-owner-command" , command = command_name )),
203+ self ._ctx .translate (
204+ _ (
205+ "ftl-cmd-profile-override-owner-command" ,
206+ command = self .command_name .value ,
207+ )
208+ ),
188209 ephemeral = True ,
189210 )
190211 return
191212 break
192- else :
193- await interaction .response .send_message (
194- self ._ctx .translate (_ ("ftl-cmd-profile-override-command-not-found" , command = command_name )),
195- ephemeral = True ,
196- )
197- return
213+
214+ display = index .label (canonical )
198215
199216 changed = self ._editor_view .resync_profile ()
200- if self .profile .permission_overrides .get (command_name ) == self ._override_value :
217+ if self .profile .permission_overrides .get (canonical ) == self ._override_value :
201218 if changed :
202219 await self ._editor_view .rebuild ()
203220 await interaction .response .send_message (
204221 self ._ctx .translate (
205- _ ("ftl-modal-profile-add-override-already-allow" , command = command_name )
222+ _ ("ftl-modal-profile-add-override-already-allow" , command = display )
206223 if self ._override_value == PermissionOverrideValue .allow
207- else _ ("ftl-modal-profile-add-override-already-deny" , command = command_name )
224+ else _ ("ftl-modal-profile-add-override-already-deny" , command = display )
208225 ),
209226 ephemeral = True ,
210227 )
211228 return
212229
213230 overrides = self .profile .permission_overrides .copy ()
214- overrides [command_name ] = self ._override_value
231+ overrides [canonical ] = self ._override_value
215232 new_profile = self .profile .model_copy (update = {"permission_overrides" : overrides })
216233 try :
217234 await self ._ctx .bot .database_client .update_profile (new_profile )
218235 except DatabaseOperationError as e :
219- logger .error ("Failed to set override %r on profile %d: %s" , command_name , new_profile .profile_id , e )
236+ logger .error ("Failed to set override %r on profile %d: %s" , canonical , new_profile .profile_id , e )
220237 if changed :
221238 await self ._editor_view .rebuild ()
222239 await interaction .response .send_message (
@@ -227,17 +244,17 @@ async def on_submit(self, interaction: discord.Interaction) -> None:
227244 logger .debug (
228245 "Set %s override for command %r on profile %d." ,
229246 self ._override_value .value ,
230- command_name ,
247+ canonical ,
231248 new_profile .profile_id ,
232249 )
233250 self ._editor_view .profile = new_profile
234251 await self ._editor_view .rebuild ()
235252
236253 await interaction .response .send_message (
237254 self ._ctx .translate (
238- _ ("ftl-view-profile-editor-override-allow-success" , command = command_name )
255+ _ ("ftl-view-profile-editor-override-allow-success" , command = display )
239256 if self ._override_value == PermissionOverrideValue .allow
240- else _ ("ftl-view-profile-editor-override-deny-success" , command = command_name )
257+ else _ ("ftl-view-profile-editor-override-deny-success" , command = display )
241258 ),
242259 ephemeral = True ,
243260 )
@@ -280,26 +297,43 @@ async def on_submit(self, interaction: discord.Interaction) -> None:
280297 Args:
281298 interaction: The submission interaction from Discord.
282299 """
283- name = utils .sanitize_user_command_name (self .override_name .value )
300+ locale = str (interaction .locale ) if interaction .locale else CONFIG .default_locale
301+ index = self ._ctx .bot .permission_command_index (locale )
302+ sanitized = index .sanitize (self .override_name .value )
303+
304+ resolved = index .resolve (self .override_name .value , allow_raw_key = True )
284305
285306 changed = self ._editor_view .resync_profile ()
286- if name not in self .profile .permission_overrides :
307+
308+ # Remove resolved if exists, otherwise remove sanitized input if it's an orphaned key
309+ key_to_remove = (
310+ resolved
311+ if resolved is not None and resolved in self .profile .permission_overrides
312+ else sanitized
313+ if sanitized in self .profile .permission_overrides
314+ else None
315+ )
316+
317+ if key_to_remove is None :
287318 if changed :
288319 await self ._editor_view .rebuild ()
289320 await interaction .response .send_message (
290- self ._ctx .translate (_ ("ftl-modal-profile-remove-override-not-found" , command = name )),
321+ self ._ctx .translate (
322+ _ ("ftl-modal-profile-remove-override-not-found" , command = self .override_name .value )
323+ ),
291324 ephemeral = True ,
292325 )
293326 return
294327
295- if not await self ._editor_view .remove_override (name , interaction ):
328+ if not await self ._editor_view .remove_override (key_to_remove , interaction ):
296329 if changed :
297330 await self ._editor_view .rebuild ()
298331 return
299332
300333 await self ._editor_view .rebuild ()
334+ display = index .label (key_to_remove )
301335 await interaction .response .send_message (
302- self ._ctx .translate (_ ("ftl-modal-profile-remove-override-success" , command = name )),
336+ self ._ctx .translate (_ ("ftl-modal-profile-remove-override-success" , command = display )),
303337 ephemeral = True ,
304338 )
305339
@@ -383,7 +417,7 @@ async def _on_confirm(self, interaction: discord.Interaction) -> None:
383417 access_sync_failed = False
384418 if self .profile .access_level is not None and self .profile .access_level != AccessLevel .everyone :
385419 try :
386- await self ._ctx .bot .staff_guild .revoke_access (self .profile .profile_id , self . profile . profile_type )
420+ await self ._ctx .bot .staff_guild .revoke_access (self .profile .profile_id )
387421 except Exception as e :
388422 logger .error ("Failed to revoke Discord access for profile %d: %s" , self .profile .profile_id , e )
389423 access_sync_failed = True
@@ -732,9 +766,7 @@ async def on_level_select(interaction: discord.Interaction) -> None:
732766 access_sync_failed = False
733767 try :
734768 if previously_had_access and not now_has_access :
735- await self ._ctx .bot .staff_guild .revoke_access (
736- self .profile .profile_id , self .profile .profile_type
737- )
769+ await self ._ctx .bot .staff_guild .revoke_access (self .profile .profile_id )
738770 elif not previously_had_access and now_has_access :
739771 await self ._ctx .bot .staff_guild .grant_access (
740772 self .profile .profile_id , self .profile .profile_type
@@ -793,6 +825,14 @@ def _build_overrides_section(self) -> list[discord.ui.Item[ProfileEditorView]]:
793825 Returns:
794826 A list of Component v2 items for the overrides section of the editor card.
795827 """
828+ locale = str (self ._ctx .interaction .locale ) if self ._ctx .interaction else CONFIG .default_locale
829+ index = self ._ctx .bot .permission_command_index (locale )
830+
831+ def _label (k : str ) -> str :
832+ if k .removesuffix ("+" ) not in index .keys :
833+ return "⚠️ " + k
834+ return index .label (k )
835+
796836 # ── Header: override count ──
797837
798838 overrides_header = self ._ctx .translate (
@@ -830,9 +870,9 @@ async def on_add_deny(interaction: discord.Interaction) -> None:
830870 if self .profile .permission_overrides :
831871 lines = [
832872 self ._ctx .translate (
833- _ ("ftl-view-profile-editor-override-line-allow" , command = k )
873+ _ ("ftl-view-profile-editor-override-line-allow" , command = _label ( k ) )
834874 if v == PermissionOverrideValue .allow
835- else _ ("ftl-view-profile-editor-override-line-deny" , command = k )
875+ else _ ("ftl-view-profile-editor-override-line-deny" , command = _label ( k ) )
836876 )
837877 for k , v in self .profile .permission_overrides .items ()
838878 ]
@@ -843,7 +883,7 @@ async def on_add_deny(interaction: discord.Interaction) -> None:
843883
844884 remove_options = [
845885 discord .SelectOption (
846- label = k ,
886+ label = _label ( k )[: 100 ] ,
847887 value = k ,
848888 description = self ._ctx .translate (
849889 _ ("ftl-view-profile-editor-override-value-allow" )
@@ -1054,7 +1094,7 @@ async def profile_delete_command(
10541094 access_sync_failed = False
10551095 if profile .access_level is not None and profile .access_level != AccessLevel .everyone :
10561096 try :
1057- await ctx .bot .staff_guild .revoke_access (profile .profile_id , profile . profile_type )
1097+ await ctx .bot .staff_guild .revoke_access (profile .profile_id )
10581098 except Exception as e :
10591099 logger .error ("Failed to revoke Discord access for profile %d: %s" , profile .profile_id , e )
10601100 access_sync_failed = True
0 commit comments