0
# Nextcord Permissions and Roles
1
2
Comprehensive permission management, role operations, and access control for Discord servers with fine-grained permission handling.
3
4
## Permissions
5
6
Discord's bitfield-based permission system with comprehensive access control capabilities.
7
8
### Permissions Class { .api }
9
10
```python
11
import nextcord
12
from typing import Dict, Iterator, Tuple, Union
13
14
class Permissions:
15
"""Wraps up a Discord permission value.
16
17
The properties provided are two-way. You can set and retrieve individual permissions.
18
19
Attributes
20
----------
21
value: int
22
The raw value of the permissions.
23
"""
24
25
def __init__(self, permissions: int = 0, **kwargs):
26
"""Initialize permissions.
27
28
Parameters
29
----------
30
permissions: int
31
The raw permissions integer.
32
**kwargs
33
Individual permission flags to set.
34
"""
35
...
36
37
@classmethod
38
def none(cls) -> Permissions:
39
"""A factory method that creates a Permissions with all permissions set to False."""
40
...
41
42
@classmethod
43
def all(cls) -> Permissions:
44
"""A factory method that creates a Permissions with all permissions set to True."""
45
...
46
47
@classmethod
48
def all_channel(cls) -> Permissions:
49
"""A factory method that creates a Permissions with all channel permissions set to True."""
50
...
51
52
@classmethod
53
def general(cls) -> Permissions:
54
"""A factory method that creates a Permissions with general permissions."""
55
...
56
57
@classmethod
58
def membership(cls) -> Permissions:
59
"""A factory method that creates a Permissions with membership permissions."""
60
...
61
62
@classmethod
63
def text(cls) -> Permissions:
64
"""A factory method that creates a Permissions with text channel permissions."""
65
...
66
67
@classmethod
68
def voice(cls) -> Permissions:
69
"""A factory method that creates a Permissions with voice channel permissions."""
70
...
71
72
@classmethod
73
def stage(cls) -> Permissions:
74
"""A factory method that creates a Permissions with stage channel permissions."""
75
...
76
77
@classmethod
78
def stage_moderator(cls) -> Permissions:
79
"""A factory method that creates a Permissions with stage moderator permissions."""
80
...
81
82
@classmethod
83
def advanced(cls) -> Permissions:
84
"""A factory method that creates a Permissions with advanced permissions."""
85
...
86
87
def update(self, **kwargs) -> None:
88
"""Bulk update permissions.
89
90
Parameters
91
----------
92
**kwargs
93
Permission flags to update.
94
"""
95
...
96
97
def __iter__(self) -> Iterator[Tuple[str, bool]]:
98
"""Iterate over all permissions."""
99
...
100
101
# Permission flags (all boolean properties)
102
class Permissions:
103
# General Server Permissions
104
@property
105
def create_instant_invite(self) -> bool:
106
"""bool: Returns True if a user can create instant invites."""
107
...
108
109
@property
110
def kick_members(self) -> bool:
111
"""bool: Returns True if a user can kick members from the guild."""
112
...
113
114
@property
115
def ban_members(self) -> bool:
116
"""bool: Returns True if a user can ban members from the guild."""
117
...
118
119
@property
120
def administrator(self) -> bool:
121
"""bool: Returns True if a user is an administrator. This role overrides all other permissions."""
122
...
123
124
@property
125
def manage_channels(self) -> bool:
126
"""bool: Returns True if a user can edit, delete, or create channels."""
127
...
128
129
@property
130
def manage_guild(self) -> bool:
131
"""bool: Returns True if a user can edit guild properties."""
132
...
133
134
@property
135
def add_reactions(self) -> bool:
136
"""bool: Returns True if a user can add reactions to messages."""
137
...
138
139
@property
140
def view_audit_log(self) -> bool:
141
"""bool: Returns True if a user can view the guild's audit log."""
142
...
143
144
@property
145
def priority_speaker(self) -> bool:
146
"""bool: Returns True if a user can use priority speaker in voice channels."""
147
...
148
149
@property
150
def stream(self) -> bool:
151
"""bool: Returns True if a user can stream in voice channels."""
152
...
153
154
@property
155
def view_channel(self) -> bool:
156
"""bool: Returns True if a user can view channels."""
157
...
158
159
@property
160
def send_messages(self) -> bool:
161
"""bool: Returns True if a user can send messages."""
162
...
163
164
@property
165
def send_tts_messages(self) -> bool:
166
"""bool: Returns True if a user can send TTS messages."""
167
...
168
169
@property
170
def manage_messages(self) -> bool:
171
"""bool: Returns True if a user can manage messages (delete/pin)."""
172
...
173
174
@property
175
def embed_links(self) -> bool:
176
"""bool: Returns True if a user's messages will embed links."""
177
...
178
179
@property
180
def attach_files(self) -> bool:
181
"""bool: Returns True if a user can attach files to messages."""
182
...
183
184
@property
185
def read_message_history(self) -> bool:
186
"""bool: Returns True if a user can read message history."""
187
...
188
189
@property
190
def mention_everyone(self) -> bool:
191
"""bool: Returns True if a user can mention @everyone and @here."""
192
...
193
194
@property
195
def external_emojis(self) -> bool:
196
"""bool: Returns True if a user can use external emojis."""
197
...
198
199
@property
200
def view_guild_insights(self) -> bool:
201
"""bool: Returns True if a user can view guild insights."""
202
...
203
204
@property
205
def connect(self) -> bool:
206
"""bool: Returns True if a user can connect to voice channels."""
207
...
208
209
@property
210
def speak(self) -> bool:
211
"""bool: Returns True if a user can speak in voice channels."""
212
...
213
214
@property
215
def mute_members(self) -> bool:
216
"""bool: Returns True if a user can mute members in voice channels."""
217
...
218
219
@property
220
def deafen_members(self) -> bool:
221
"""bool: Returns True if a user can deafen members in voice channels."""
222
...
223
224
@property
225
def move_members(self) -> bool:
226
"""bool: Returns True if a user can move members between voice channels."""
227
...
228
229
@property
230
def use_voice_activation(self) -> bool:
231
"""bool: Returns True if a user can use voice activation in voice channels."""
232
...
233
234
@property
235
def change_nickname(self) -> bool:
236
"""bool: Returns True if a user can change their nickname."""
237
...
238
239
@property
240
def manage_nicknames(self) -> bool:
241
"""bool: Returns True if a user can manage other members' nicknames."""
242
...
243
244
@property
245
def manage_roles(self) -> bool:
246
"""bool: Returns True if a user can manage roles."""
247
...
248
249
@property
250
def manage_webhooks(self) -> bool:
251
"""bool: Returns True if a user can manage webhooks."""
252
...
253
254
@property
255
def manage_emojis_and_stickers(self) -> bool:
256
"""bool: Returns True if a user can manage emojis and stickers."""
257
...
258
259
@property
260
def use_application_commands(self) -> bool:
261
"""bool: Returns True if a user can use application commands."""
262
...
263
264
@property
265
def request_to_speak(self) -> bool:
266
"""bool: Returns True if a user can request to speak in stage channels."""
267
...
268
269
@property
270
def manage_events(self) -> bool:
271
"""bool: Returns True if a user can manage guild events."""
272
...
273
274
@property
275
def manage_threads(self) -> bool:
276
"""bool: Returns True if a user can manage threads."""
277
...
278
279
@property
280
def create_public_threads(self) -> bool:
281
"""bool: Returns True if a user can create public threads."""
282
...
283
284
@property
285
def create_private_threads(self) -> bool:
286
"""bool: Returns True if a user can create private threads."""
287
...
288
289
@property
290
def external_stickers(self) -> bool:
291
"""bool: Returns True if a user can use external stickers."""
292
...
293
294
@property
295
def send_messages_in_threads(self) -> bool:
296
"""bool: Returns True if a user can send messages in threads."""
297
...
298
299
@property
300
def use_embedded_activities(self) -> bool:
301
"""bool: Returns True if a user can use embedded activities in voice channels."""
302
...
303
304
@property
305
def moderate_members(self) -> bool:
306
"""bool: Returns True if a user can moderate members (timeout, etc.)."""
307
...
308
309
# Permission usage examples
310
def create_permissions_examples():
311
"""Examples of creating and working with permissions."""
312
313
# Create permissions with specific flags
314
perms = nextcord.Permissions(
315
send_messages=True,
316
read_message_history=True,
317
add_reactions=True
318
)
319
320
# Create from raw value
321
perms_raw = nextcord.Permissions(permissions=268435456)
322
323
# Factory methods
324
admin_perms = nextcord.Permissions.all()
325
text_perms = nextcord.Permissions.text()
326
voice_perms = nextcord.Permissions.voice()
327
328
# Update permissions
329
perms.update(manage_messages=True, embed_links=True)
330
331
return perms, admin_perms, text_perms, voice_perms
332
333
@bot.slash_command(description="Check permissions for a member")
334
async def checkperms(
335
interaction: nextcord.Interaction,
336
member: Optional[nextcord.Member] = nextcord.SlashOption(
337
description="Member to check permissions for",
338
default=None
339
),
340
channel: Optional[nextcord.TextChannel] = nextcord.SlashOption(
341
description="Channel to check permissions in",
342
default=None
343
)
344
):
345
"""Check a member's permissions in a specific channel or guild."""
346
target = member or interaction.user
347
check_channel = channel or interaction.channel
348
349
# Get permissions
350
if isinstance(check_channel, nextcord.abc.GuildChannel):
351
perms = target.permissions_in(check_channel)
352
context = f"in {check_channel.mention}"
353
else:
354
perms = target.guild_permissions
355
context = "in this server"
356
357
embed = nextcord.Embed(
358
title=f"Permissions for {target.display_name}",
359
description=f"Permissions {context}",
360
color=target.color or nextcord.Color.blue()
361
)
362
363
# Key permissions to display
364
key_perms = {
365
"Administrator": perms.administrator,
366
"Manage Server": perms.manage_guild,
367
"Manage Channels": perms.manage_channels,
368
"Manage Roles": perms.manage_roles,
369
"Manage Messages": perms.manage_messages,
370
"Kick Members": perms.kick_members,
371
"Ban Members": perms.ban_members,
372
"Moderate Members": perms.moderate_members,
373
"Send Messages": perms.send_messages,
374
"View Channels": perms.view_channel,
375
"Connect to Voice": perms.connect,
376
"Speak in Voice": perms.speak,
377
"Move Members": perms.move_members,
378
}
379
380
# Group permissions by category
381
dangerous_perms = []
382
moderation_perms = []
383
basic_perms = []
384
385
for perm_name, has_perm in key_perms.items():
386
emoji = "β " if has_perm else "β"
387
perm_text = f"{emoji} {perm_name}"
388
389
if perm_name in ["Administrator", "Manage Server", "Manage Roles"]:
390
dangerous_perms.append(perm_text)
391
elif perm_name in ["Kick Members", "Ban Members", "Moderate Members", "Manage Messages"]:
392
moderation_perms.append(perm_text)
393
else:
394
basic_perms.append(perm_text)
395
396
if dangerous_perms:
397
embed.add_field(name="π΄ Administrative", value="\n".join(dangerous_perms), inline=True)
398
if moderation_perms:
399
embed.add_field(name="π‘ Moderation", value="\n".join(moderation_perms), inline=True)
400
if basic_perms:
401
embed.add_field(name="π’ Basic", value="\n".join(basic_perms), inline=True)
402
403
# Show raw permission value
404
embed.add_field(
405
name="Raw Permission Value",
406
value=f"`{perms.value}`",
407
inline=False
408
)
409
410
await interaction.response.send_message(embed=embed)
411
```
412
413
## Permission Overwrites
414
415
Channel-specific permission overrides for users and roles.
416
417
### PermissionOverwrite Class { .api }
418
419
```python
420
class PermissionOverwrite:
421
"""A permission overwrite for a channel.
422
423
Permission overwrites allow you to set specific permissions for roles or members
424
in individual channels, overriding their guild-level permissions.
425
426
Attributes
427
----------
428
allow: Permissions
429
Permissions that are explicitly allowed.
430
deny: Permissions
431
Permissions that are explicitly denied.
432
"""
433
434
def __init__(self, **permissions):
435
"""Create a permission overwrite.
436
437
Parameters
438
----------
439
**permissions
440
Permission flags. Use None for neutral (inherit), True for allow, False for deny.
441
"""
442
...
443
444
@classmethod
445
def from_pair(cls, allow: Permissions, deny: Permissions) -> PermissionOverwrite:
446
"""Create a PermissionOverwrite from an allow/deny pair.
447
448
Parameters
449
----------
450
allow: Permissions
451
Permissions to explicitly allow.
452
deny: Permissions
453
Permissions to explicitly deny.
454
455
Returns
456
-------
457
PermissionOverwrite
458
The created permission overwrite.
459
"""
460
...
461
462
def update(self, **permissions) -> None:
463
"""Update the permission overwrite.
464
465
Parameters
466
----------
467
**permissions
468
Permission flags to update.
469
"""
470
...
471
472
def is_empty(self) -> bool:
473
"""bool: Whether the overwrite is empty (no explicit allows or denies)."""
474
...
475
476
# Permission overwrite examples
477
@bot.slash_command(description="Set channel permissions for a role")
478
async def setperms(
479
interaction: nextcord.Interaction,
480
channel: nextcord.TextChannel = nextcord.SlashOption(description="Channel to modify"),
481
role: nextcord.Role = nextcord.SlashOption(description="Role to set permissions for"),
482
permission: str = nextcord.SlashOption(
483
description="Permission to modify",
484
choices=[
485
"send_messages", "view_channel", "manage_messages",
486
"add_reactions", "attach_files", "read_message_history"
487
]
488
),
489
value: str = nextcord.SlashOption(
490
description="Permission value",
491
choices=["allow", "deny", "neutral"]
492
)
493
):
494
"""Set specific channel permissions for a role."""
495
if not interaction.user.guild_permissions.manage_roles:
496
await interaction.response.send_message(
497
"β You don't have permission to manage roles.",
498
ephemeral=True
499
)
500
return
501
502
# Get current overwrite or create new one
503
overwrite = channel.overwrites_for(role)
504
505
# Set the permission
506
perm_value = None if value == "neutral" else (value == "allow")
507
setattr(overwrite, permission, perm_value)
508
509
try:
510
await channel.set_permissions(
511
role,
512
overwrite=overwrite,
513
reason=f"Permission modified by {interaction.user}"
514
)
515
516
emoji = {"allow": "β ", "deny": "β", "neutral": "β"}[value]
517
await interaction.response.send_message(
518
f"{emoji} Set `{permission}` to `{value}` for {role.mention} in {channel.mention}.",
519
ephemeral=True
520
)
521
522
except nextcord.Forbidden:
523
await interaction.response.send_message(
524
"β I don't have permission to modify channel permissions.",
525
ephemeral=True
526
)
527
except nextcord.HTTPException as e:
528
await interaction.response.send_message(
529
f"β Failed to set permissions: {e}",
530
ephemeral=True
531
)
532
533
@bot.slash_command(description="Lock a channel")
534
async def lockdown(
535
interaction: nextcord.Interaction,
536
channel: Optional[nextcord.TextChannel] = nextcord.SlashOption(
537
description="Channel to lock (defaults to current)",
538
default=None
539
),
540
reason: Optional[str] = nextcord.SlashOption(description="Reason for lockdown", default=None)
541
):
542
"""Lock a channel to prevent members from sending messages."""
543
if not interaction.user.guild_permissions.manage_channels:
544
await interaction.response.send_message(
545
"β You don't have permission to manage channels.",
546
ephemeral=True
547
)
548
return
549
550
target_channel = channel or interaction.channel
551
552
# Get @everyone role
553
everyone_role = interaction.guild.default_role
554
555
# Create overwrite that denies sending messages
556
overwrite = nextcord.PermissionOverwrite(send_messages=False)
557
558
try:
559
await target_channel.set_permissions(
560
everyone_role,
561
overwrite=overwrite,
562
reason=reason or f"Channel locked by {interaction.user}"
563
)
564
565
embed = nextcord.Embed(
566
title="π Channel Locked",
567
description=f"{target_channel.mention} has been locked.",
568
color=nextcord.Color.red()
569
)
570
571
if reason:
572
embed.add_field(name="Reason", value=reason, inline=False)
573
574
embed.set_footer(text=f"Locked by {interaction.user}", icon_url=interaction.user.display_avatar.url)
575
576
await interaction.response.send_message(embed=embed)
577
578
except nextcord.Forbidden:
579
await interaction.response.send_message(
580
"β I don't have permission to modify this channel.",
581
ephemeral=True
582
)
583
except nextcord.HTTPException as e:
584
await interaction.response.send_message(
585
f"β Failed to lock channel: {e}",
586
ephemeral=True
587
)
588
589
@bot.slash_command(description="Unlock a channel")
590
async def unlock(
591
interaction: nextcord.Interaction,
592
channel: Optional[nextcord.TextChannel] = nextcord.SlashOption(
593
description="Channel to unlock (defaults to current)",
594
default=None
595
),
596
reason: Optional[str] = nextcord.SlashOption(description="Reason for unlock", default=None)
597
):
598
"""Unlock a channel to allow members to send messages again."""
599
if not interaction.user.guild_permissions.manage_channels:
600
await interaction.response.send_message(
601
"β You don't have permission to manage channels.",
602
ephemeral=True
603
)
604
return
605
606
target_channel = channel or interaction.channel
607
everyone_role = interaction.guild.default_role
608
609
try:
610
# Remove the send_messages override (set to neutral)
611
overwrite = target_channel.overwrites_for(everyone_role)
612
overwrite.send_messages = None
613
614
if overwrite.is_empty():
615
# If overwrite is empty, delete it entirely
616
await target_channel.set_permissions(
617
everyone_role,
618
overwrite=None,
619
reason=reason or f"Channel unlocked by {interaction.user}"
620
)
621
else:
622
# Keep other overwrites but remove send_messages restriction
623
await target_channel.set_permissions(
624
everyone_role,
625
overwrite=overwrite,
626
reason=reason or f"Channel unlocked by {interaction.user}"
627
)
628
629
embed = nextcord.Embed(
630
title="π Channel Unlocked",
631
description=f"{target_channel.mention} has been unlocked.",
632
color=nextcord.Color.green()
633
)
634
635
if reason:
636
embed.add_field(name="Reason", value=reason, inline=False)
637
638
embed.set_footer(text=f"Unlocked by {interaction.user}", icon_url=interaction.user.display_avatar.url)
639
640
await interaction.response.send_message(embed=embed)
641
642
except nextcord.Forbidden:
643
await interaction.response.send_message(
644
"β I don't have permission to modify this channel.",
645
ephemeral=True
646
)
647
except nextcord.HTTPException as e:
648
await interaction.response.send_message(
649
f"β Failed to unlock channel: {e}",
650
ephemeral=True
651
)
652
```
653
654
## Roles
655
656
Guild roles with hierarchy, permissions, and member management.
657
658
### Role Class { .api }
659
660
```python
661
class Role(nextcord.abc.Snowflake):
662
"""Represents a Discord role.
663
664
Attributes
665
----------
666
id: int
667
The role ID.
668
name: str
669
The role name.
670
guild: Guild
671
The guild this role belongs to.
672
hoist: bool
673
Whether the role is displayed separately in the member list.
674
position: int
675
The role's position in the hierarchy. Higher is more important.
676
managed: bool
677
Whether the role is managed by an integration (bot, booster, etc.).
678
mentionable: bool
679
Whether the role can be mentioned by members.
680
permissions: Permissions
681
The permissions this role grants.
682
colour: Colour
683
The role's color.
684
created_at: datetime.datetime
685
When the role was created.
686
mention: str
687
A string that mentions this role.
688
members: List[Member]
689
A list of members who have this role.
690
"""
691
692
@property
693
def color(self) -> nextcord.Colour:
694
"""nextcord.Colour: An alias for colour."""
695
...
696
697
def is_default(self) -> bool:
698
"""bool: Whether this is the @everyone role."""
699
...
700
701
def is_bot_managed(self) -> bool:
702
"""bool: Whether this role is managed by a bot."""
703
...
704
705
def is_premium_subscriber(self) -> bool:
706
"""bool: Whether this role is the premium subscriber (booster) role."""
707
...
708
709
def is_integration(self) -> bool:
710
"""bool: Whether this role is managed by an integration."""
711
...
712
713
async def edit(
714
self,
715
*,
716
name: str = MISSING,
717
permissions: Permissions = MISSING,
718
colour: Union[nextcord.Colour, int] = MISSING,
719
color: Union[nextcord.Colour, int] = MISSING,
720
hoist: bool = MISSING,
721
mentionable: bool = MISSING,
722
position: int = MISSING,
723
reason: Optional[str] = None,
724
icon: Optional[bytes] = MISSING,
725
unicode_emoji: Optional[str] = MISSING,
726
) -> Role:
727
"""Edit the role.
728
729
Parameters
730
----------
731
name: str
732
The role's new name.
733
permissions: Permissions
734
The role's new permissions.
735
colour: Union[nextcord.Colour, int]
736
The role's new colour.
737
color: Union[nextcord.Colour, int]
738
Alias for colour.
739
hoist: bool
740
Whether the role should be hoisted.
741
mentionable: bool
742
Whether the role should be mentionable.
743
position: int
744
The role's new position.
745
reason: Optional[str]
746
The reason for editing this role.
747
icon: Optional[bytes]
748
The role's new icon (for premium guilds).
749
unicode_emoji: Optional[str]
750
The role's new unicode emoji (for premium guilds).
751
752
Returns
753
-------
754
Role
755
The newly edited role.
756
"""
757
...
758
759
async def delete(self, *, reason: Optional[str] = None) -> None:
760
"""Delete the role.
761
762
Parameters
763
----------
764
reason: Optional[str]
765
The reason for deleting this role.
766
"""
767
...
768
769
# Role management examples
770
@bot.slash_command(description="Create a new role")
771
async def createrole(
772
interaction: nextcord.Interaction,
773
name: str = nextcord.SlashOption(description="Role name"),
774
color: Optional[str] = nextcord.SlashOption(
775
description="Role color (hex code, e.g., #FF0000)",
776
default=None
777
),
778
hoist: bool = nextcord.SlashOption(description="Display separately in member list", default=False),
779
mentionable: bool = nextcord.SlashOption(description="Allow anyone to mention", default=False)
780
):
781
"""Create a new role with specified properties."""
782
if not interaction.user.guild_permissions.manage_roles:
783
await interaction.response.send_message(
784
"β You don't have permission to manage roles.",
785
ephemeral=True
786
)
787
return
788
789
# Parse color if provided
790
role_color = nextcord.Color.default()
791
if color:
792
try:
793
# Remove # if present
794
color_hex = color.lstrip('#')
795
role_color = nextcord.Color(int(color_hex, 16))
796
except ValueError:
797
await interaction.response.send_message(
798
"β Invalid color format. Use hex format like `#FF0000`.",
799
ephemeral=True
800
)
801
return
802
803
try:
804
role = await interaction.guild.create_role(
805
name=name,
806
color=role_color,
807
hoist=hoist,
808
mentionable=mentionable,
809
reason=f"Role created by {interaction.user}"
810
)
811
812
embed = nextcord.Embed(
813
title="Role Created",
814
description=f"Successfully created role {role.mention}",
815
color=role.color
816
)
817
818
embed.add_field(name="Name", value=role.name, inline=True)
819
embed.add_field(name="ID", value=role.id, inline=True)
820
embed.add_field(name="Position", value=role.position, inline=True)
821
embed.add_field(name="Color", value=str(role.color), inline=True)
822
embed.add_field(name="Hoisted", value="Yes" if role.hoist else "No", inline=True)
823
embed.add_field(name="Mentionable", value="Yes" if role.mentionable else "No", inline=True)
824
825
await interaction.response.send_message(embed=embed)
826
827
except nextcord.Forbidden:
828
await interaction.response.send_message(
829
"β I don't have permission to create roles.",
830
ephemeral=True
831
)
832
except nextcord.HTTPException as e:
833
await interaction.response.send_message(
834
f"β Failed to create role: {e}",
835
ephemeral=True
836
)
837
838
@bot.slash_command(description="Delete a role")
839
async def deleterole(
840
interaction: nextcord.Interaction,
841
role: nextcord.Role = nextcord.SlashOption(description="Role to delete"),
842
reason: Optional[str] = nextcord.SlashOption(description="Reason for deletion", default=None)
843
):
844
"""Delete a role from the server."""
845
if not interaction.user.guild_permissions.manage_roles:
846
await interaction.response.send_message(
847
"β You don't have permission to manage roles.",
848
ephemeral=True
849
)
850
return
851
852
# Check if it's the @everyone role
853
if role.is_default():
854
await interaction.response.send_message(
855
"β Cannot delete the @everyone role.",
856
ephemeral=True
857
)
858
return
859
860
# Check hierarchy
861
if role.position >= interaction.user.top_role.position and interaction.user != interaction.guild.owner:
862
await interaction.response.send_message(
863
"β Cannot delete this role (same or higher position than your top role).",
864
ephemeral=True
865
)
866
return
867
868
# Check if role is managed
869
if role.managed:
870
await interaction.response.send_message(
871
"β Cannot delete managed roles (bot roles, booster roles, etc.).",
872
ephemeral=True
873
)
874
return
875
876
role_name = role.name
877
member_count = len(role.members)
878
879
try:
880
await role.delete(reason=reason or f"Role deleted by {interaction.user}")
881
882
embed = nextcord.Embed(
883
title="Role Deleted",
884
description=f"Successfully deleted role **{role_name}**",
885
color=nextcord.Color.red()
886
)
887
888
embed.add_field(name="Members Affected", value=member_count, inline=True)
889
890
if reason:
891
embed.add_field(name="Reason", value=reason, inline=False)
892
893
embed.set_footer(text=f"Deleted by {interaction.user}", icon_url=interaction.user.display_avatar.url)
894
895
await interaction.response.send_message(embed=embed)
896
897
except nextcord.Forbidden:
898
await interaction.response.send_message(
899
"β I don't have permission to delete this role.",
900
ephemeral=True
901
)
902
except nextcord.HTTPException as e:
903
await interaction.response.send_message(
904
f"β Failed to delete role: {e}",
905
ephemeral=True
906
)
907
908
@bot.slash_command(description="Edit role permissions")
909
async def editroleperms(
910
interaction: nextcord.Interaction,
911
role: nextcord.Role = nextcord.SlashOption(description="Role to edit"),
912
permission: str = nextcord.SlashOption(
913
description="Permission to toggle",
914
choices=[
915
"manage_channels", "manage_guild", "kick_members", "ban_members",
916
"manage_messages", "send_messages", "add_reactions", "view_channel",
917
"connect", "speak", "mute_members", "deafen_members", "move_members",
918
"manage_nicknames", "manage_roles", "administrator"
919
]
920
),
921
value: bool = nextcord.SlashOption(description="Enable or disable the permission")
922
):
923
"""Edit permissions for a role."""
924
if not interaction.user.guild_permissions.manage_roles:
925
await interaction.response.send_message(
926
"β You don't have permission to manage roles.",
927
ephemeral=True
928
)
929
return
930
931
if role.position >= interaction.user.top_role.position and interaction.user != interaction.guild.owner:
932
await interaction.response.send_message(
933
"β Cannot edit this role (same or higher position than your top role).",
934
ephemeral=True
935
)
936
return
937
938
if role.managed:
939
await interaction.response.send_message(
940
"β Cannot edit managed roles.",
941
ephemeral=True
942
)
943
return
944
945
# Get current permissions and update
946
new_permissions = role.permissions
947
setattr(new_permissions, permission, value)
948
949
try:
950
await role.edit(
951
permissions=new_permissions,
952
reason=f"Permission {permission} {'enabled' if value else 'disabled'} by {interaction.user}"
953
)
954
955
status = "enabled" if value else "disabled"
956
emoji = "β " if value else "β"
957
958
await interaction.response.send_message(
959
f"{emoji} {permission.replace('_', ' ').title()} {status} for {role.mention}.",
960
ephemeral=True
961
)
962
963
except nextcord.Forbidden:
964
await interaction.response.send_message(
965
"β I don't have permission to edit this role.",
966
ephemeral=True
967
)
968
except nextcord.HTTPException as e:
969
await interaction.response.send_message(
970
f"β Failed to edit role: {e}",
971
ephemeral=True
972
)
973
974
@bot.slash_command(description="List all roles in the server")
975
async def listroles(interaction: nextcord.Interaction):
976
"""List all roles in the server with their information."""
977
roles = sorted(interaction.guild.roles[1:], key=lambda r: r.position, reverse=True) # Skip @everyone
978
979
if not roles:
980
await interaction.response.send_message("This server has no custom roles.")
981
return
982
983
embed = nextcord.Embed(
984
title=f"Roles in {interaction.guild.name}",
985
description=f"Total roles: {len(roles)}",
986
color=nextcord.Color.blue()
987
)
988
989
role_list = []
990
for i, role in enumerate(roles[:20]): # Limit to first 20 roles
991
member_count = len(role.members)
992
managed_indicator = " π€" if role.managed else ""
993
hoisted_indicator = " π" if role.hoist else ""
994
995
role_info = (
996
f"{i+1}. {role.mention} "
997
f"({member_count} member{'s' if member_count != 1 else ''})"
998
f"{managed_indicator}{hoisted_indicator}"
999
)
1000
role_list.append(role_info)
1001
1002
embed.add_field(
1003
name="Roles (by hierarchy)",
1004
value="\n".join(role_list) + (f"\n... and {len(roles) - 20} more" if len(roles) > 20 else ""),
1005
inline=False
1006
)
1007
1008
embed.set_footer(text="π€ = Managed | π = Hoisted")
1009
1010
await interaction.response.send_message(embed=embed)
1011
```
1012
1013
## Permission Utilities
1014
1015
Utility functions and helpers for working with permissions and roles.
1016
1017
### Permission Helpers { .api }
1018
1019
```python
1020
# Permission checking utilities
1021
def has_any_permission(member: nextcord.Member, *permissions: str) -> bool:
1022
"""Check if a member has any of the specified permissions.
1023
1024
Parameters
1025
----------
1026
member: nextcord.Member
1027
The member to check permissions for.
1028
*permissions: str
1029
Permission names to check for.
1030
1031
Returns
1032
-------
1033
bool
1034
True if the member has any of the permissions.
1035
"""
1036
member_perms = member.guild_permissions
1037
return any(getattr(member_perms, perm, False) for perm in permissions)
1038
1039
def has_all_permissions(member: nextcord.Member, *permissions: str) -> bool:
1040
"""Check if a member has all of the specified permissions.
1041
1042
Parameters
1043
----------
1044
member: nextcord.Member
1045
The member to check permissions for.
1046
*permissions: str
1047
Permission names to check for.
1048
1049
Returns
1050
-------
1051
bool
1052
True if the member has all of the permissions.
1053
"""
1054
member_perms = member.guild_permissions
1055
return all(getattr(member_perms, perm, False) for perm in permissions)
1056
1057
def get_dangerous_permissions(permissions: nextcord.Permissions) -> List[str]:
1058
"""Get a list of dangerous permissions that a user has.
1059
1060
Parameters
1061
----------
1062
permissions: nextcord.Permissions
1063
The permissions to check.
1064
1065
Returns
1066
-------
1067
List[str]
1068
List of dangerous permission names the user has.
1069
"""
1070
dangerous = [
1071
'administrator', 'manage_guild', 'manage_roles', 'manage_channels',
1072
'kick_members', 'ban_members', 'manage_webhooks', 'manage_emojis_and_stickers'
1073
]
1074
1075
return [perm for perm in dangerous if getattr(permissions, perm, False)]
1076
1077
# Permission audit command
1078
@bot.slash_command(description="Audit dangerous permissions in the server")
1079
async def auditperms(interaction: nextcord.Interaction):
1080
"""Audit members with dangerous permissions."""
1081
if not interaction.user.guild_permissions.administrator:
1082
await interaction.response.send_message(
1083
"β You need Administrator permission to use this command.",
1084
ephemeral=True
1085
)
1086
return
1087
1088
await interaction.response.defer() # This might take a moment
1089
1090
dangerous_members = []
1091
1092
for member in interaction.guild.members:
1093
if member.bot:
1094
continue
1095
1096
dangerous_perms = get_dangerous_permissions(member.guild_permissions)
1097
if dangerous_perms:
1098
dangerous_members.append((member, dangerous_perms))
1099
1100
if not dangerous_members:
1101
await interaction.followup.send("β No members found with dangerous permissions.")
1102
return
1103
1104
embed = nextcord.Embed(
1105
title="π Permission Audit Results",
1106
description=f"Found {len(dangerous_members)} members with dangerous permissions",
1107
color=nextcord.Color.orange()
1108
)
1109
1110
# Sort by number of dangerous permissions (most dangerous first)
1111
dangerous_members.sort(key=lambda x: len(x[1]), reverse=True)
1112
1113
member_list = []
1114
for member, perms in dangerous_members[:10]: # Show top 10
1115
perm_text = ", ".join(p.replace('_', ' ').title() for p in perms)
1116
member_list.append(f"**{member.display_name}** ({len(perms)}): {perm_text}")
1117
1118
embed.add_field(
1119
name="Members with Dangerous Permissions",
1120
value="\n".join(member_list) + (f"\n... and {len(dangerous_members) - 10} more" if len(dangerous_members) > 10 else ""),
1121
inline=False
1122
)
1123
1124
embed.set_footer(text="Consider reviewing these permissions for security")
1125
1126
await interaction.followup.send(embed=embed)
1127
1128
# Role hierarchy utilities
1129
@bot.slash_command(description="Show role hierarchy")
1130
async def hierarchy(interaction: nextcord.Interaction):
1131
"""Display the server's role hierarchy."""
1132
roles = sorted(interaction.guild.roles, key=lambda r: r.position, reverse=True)
1133
1134
embed = nextcord.Embed(
1135
title=f"Role Hierarchy in {interaction.guild.name}",
1136
description="Roles listed from highest to lowest position",
1137
color=nextcord.Color.blue()
1138
)
1139
1140
hierarchy_text = []
1141
for i, role in enumerate(roles[:15]): # Show top 15 roles
1142
indent = " " * min(i // 3, 3) # Add visual indentation
1143
member_count = len(role.members)
1144
1145
if role.is_default():
1146
role_name = "@everyone"
1147
else:
1148
role_name = role.name
1149
1150
hierarchy_text.append(
1151
f"{indent}{i+1}. **{role_name}** "
1152
f"({member_count} member{'s' if member_count != 1 else ''})"
1153
)
1154
1155
embed.add_field(
1156
name="Hierarchy",
1157
value="\n".join(hierarchy_text) + (f"\n... and {len(roles) - 15} more" if len(roles) > 15 else ""),
1158
inline=False
1159
)
1160
1161
embed.set_footer(text="Higher positions have priority over lower ones")
1162
1163
await interaction.response.send_message(embed=embed)
1164
1165
# Permission comparison utility
1166
@bot.slash_command(description="Compare permissions between two members")
1167
async def compareperms(
1168
interaction: nextcord.Interaction,
1169
member1: nextcord.Member = nextcord.SlashOption(description="First member"),
1170
member2: nextcord.Member = nextcord.SlashOption(description="Second member")
1171
):
1172
"""Compare permissions between two members."""
1173
perms1 = member1.guild_permissions
1174
perms2 = member2.guild_permissions
1175
1176
embed = nextcord.Embed(
1177
title="Permission Comparison",
1178
description=f"Comparing {member1.display_name} vs {member2.display_name}",
1179
color=nextcord.Color.blue()
1180
)
1181
1182
# Get all permission attributes
1183
all_perms = [attr for attr in dir(perms1) if not attr.startswith('_') and isinstance(getattr(perms1, attr), bool)]
1184
1185
# Categorize differences
1186
member1_only = []
1187
member2_only = []
1188
both_have = []
1189
neither_have = []
1190
1191
for perm in all_perms:
1192
has_perm1 = getattr(perms1, perm, False)
1193
has_perm2 = getattr(perms2, perm, False)
1194
1195
perm_display = perm.replace('_', ' ').title()
1196
1197
if has_perm1 and not has_perm2:
1198
member1_only.append(perm_display)
1199
elif has_perm2 and not has_perm1:
1200
member2_only.append(perm_display)
1201
elif has_perm1 and has_perm2:
1202
both_have.append(perm_display)
1203
else:
1204
neither_have.append(perm_display)
1205
1206
if member1_only:
1207
embed.add_field(
1208
name=f"β Only {member1.display_name} has",
1209
value=", ".join(member1_only[:10]) + ("..." if len(member1_only) > 10 else ""),
1210
inline=False
1211
)
1212
1213
if member2_only:
1214
embed.add_field(
1215
name=f"β Only {member2.display_name} has",
1216
value=", ".join(member2_only[:10]) + ("..." if len(member2_only) > 10 else ""),
1217
inline=False
1218
)
1219
1220
if both_have:
1221
embed.add_field(
1222
name="π€ Both have",
1223
value=", ".join(both_have[:10]) + ("..." if len(both_have) > 10 else ""),
1224
inline=False
1225
)
1226
1227
await interaction.response.send_message(embed=embed)
1228
```
1229
1230
This comprehensive documentation covers all aspects of nextcord's permission and role system, providing developers with the tools needed to implement sophisticated access control in their Discord bots.