Skip to content

Commit

Permalink
Add methods for computing permissions in a channel. (#29)
Browse files Browse the repository at this point in the history
  • Loading branch information
abitofevrything authored Feb 18, 2024
1 parent 82d8d50 commit c18a053
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 0 deletions.
1 change: 1 addition & 0 deletions lib/nyxx_extensions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ export 'src/role.dart';
export 'src/sanitizer.dart';
export 'src/user.dart';
export 'src/utils/formatters.dart';
export 'src/permissions.dart';
export 'src/endpoint_paginator.dart';
95 changes: 95 additions & 0 deletions lib/src/permissions.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import 'package:nyxx/nyxx.dart';

/// Compute the permissions for [member] in a given [channel].
///
/// {@template compute_permissions_detail}
/// This method returns the permissions for [member] according to the
/// permissions granted to them by their roles at a guild level as well as
/// the permission overwrites for [channel].
///
/// Adapted from https://discord.com/developers/docs/topics/permissions#permission-overwrites
/// {@endtemplate}
Future<Permissions> computePermissions(
GuildChannel channel,
Member member,
) async {
final guild = await channel.guild.get();

Future<Permissions> computeBasePermissions() async {
if (guild.ownerId == member.id) {
return Permissions.allPermissions;
}

final everyoneRole = await guild.roles[guild.id].get();
Flags<Permissions> permissions = everyoneRole.permissions;

for (final role in member.roles) {
final rolePermissions = (await role.get()).permissions;

permissions |= rolePermissions;
}

permissions = Permissions(permissions.value);
permissions as Permissions;

if (permissions.isAdministrator) {
return Permissions.allPermissions;
}

return permissions;
}

Future<Permissions> computeOverwrites(Permissions basePermissions) async {
if (basePermissions.isAdministrator) {
return Permissions.allPermissions;
}

Flags<Permissions> permissions = basePermissions;

final everyoneOverwrite = channel.permissionOverwrites.where((overwrite) => overwrite.id == guild.id).singleOrNull;
if (everyoneOverwrite != null) {
permissions &= ~everyoneOverwrite.deny;
permissions |= everyoneOverwrite.allow;
}

Flags<Permissions> allow = Permissions(0);
Flags<Permissions> deny = Permissions(0);

for (final roleId in member.roleIds) {
final roleOverwrite = channel.permissionOverwrites.where((overwrite) => overwrite.id == roleId).singleOrNull;
if (roleOverwrite != null) {
allow |= roleOverwrite.allow;
deny |= roleOverwrite.deny;
}
}

permissions &= ~deny;
permissions |= allow;

final memberOverwrite = channel.permissionOverwrites.where((overwrite) => overwrite.id == member.id).singleOrNull;
if (memberOverwrite != null) {
permissions &= ~memberOverwrite.deny;
permissions |= memberOverwrite.allow;
}

return Permissions(permissions.value);
}

return computeOverwrites(await computeBasePermissions());
}

/// Extensions for computing permissions in a [GuildChannel].
extension MemberComputePermissions on PartialMember {
/// Compute this member's permissions in [channel].
///
/// {@macro compute_permissions_detail}
Future<Permissions> computePermissionsIn(GuildChannel channel) async => await computePermissions(channel, await get());
}

/// Extensions for computing a [Member]'s permissions.
extension ChannelComputePermissions on GuildChannel {
/// Compute [member]'s permissions in this channel.
///
/// {@macro compute_permissions_detail}
Future<Permissions> computePermissionsFor(PartialMember member) async => await computePermissions(this, await member.get());
}

0 comments on commit c18a053

Please sign in to comment.