-
Notifications
You must be signed in to change notification settings - Fork 1
/
permissions.ts
108 lines (94 loc) · 2.98 KB
/
permissions.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import {
Channel,
GuildMember,
Overwrite,
PermissionFlag,
Role,
} from "droff/types";
import * as F from "fp-ts/function";
import * as Flags from "./flags";
import * as Members from "./members";
/**
* A constant of all the permissions
*/
export const ALL = Flags.all(PermissionFlag);
/**
* Check if a flag exists in the permissions.
*/
export const has = Flags.hasBigInt;
/**
* Convert a permissions bitfield to a list of flag names.
*/
export const toList = Flags.toList(PermissionFlag);
/**
* Convert a list of flag names to a bitfield.
*/
export const fromList = Flags.fromListBigint(PermissionFlag);
/**
* Reduce a list of roles to a bitfield of all the permissions added together.
*/
export const forRoles = (roles: Role[]) =>
roles.reduce(
(permissions, role) => permissions | BigInt(role.permissions),
BigInt(0),
);
/**
* From a list of roles, calculate the permissions bitfield for the member.
*/
export const forMember = (roles: Role[]) => (member: GuildMember) =>
F.pipe(Members.roles(roles)(member), forRoles);
const overwriteIsForMember =
(guildId?: string) => (member: GuildMember) => (overwrite: Overwrite) => {
if (overwrite.type === 0) {
return overwrite.id === guildId || member.roles.includes(overwrite.id);
}
return overwrite.id === member.user?.id;
};
const overwriteIsForRole =
(guildId?: string) => (role: Role) => (overwrite: Overwrite) => {
if (overwrite.type === 0) {
return overwrite.id === guildId || overwrite.id === role.id;
}
return false;
};
/**
* From a list of roles and a channel, calculate the permission bitfield for
* the guild member or role for that channel.
*/
export const forChannel =
(roles: Role[]) =>
({ guild_id, permission_overwrites: overwrites = [] }: Channel) =>
(memberOrRole: GuildMember | Role) => {
const hasAdmin = has(PermissionFlag.ADMINISTRATOR);
let basePermissions: bigint;
let filteredOverwrites: Overwrite[];
if (Members.is(memberOrRole)) {
if (memberOrRole.permissions) return BigInt(memberOrRole.permissions);
const memberRoles = Members.roles(roles)(memberOrRole);
basePermissions = forRoles(memberRoles);
filteredOverwrites = overwrites.filter(
overwriteIsForMember(guild_id)(memberOrRole),
);
} else {
const everyone = roles.find((role) => role.name === "@everyone");
basePermissions =
BigInt(everyone?.permissions || "0") | BigInt(memberOrRole.permissions);
filteredOverwrites = overwrites.filter(
overwriteIsForRole(guild_id)(memberOrRole),
);
}
if (hasAdmin(basePermissions)) {
return ALL;
}
return applyOverwrites(basePermissions)(filteredOverwrites);
};
/**
* Apply permission overwrites to a bitfield.
*/
export const applyOverwrites =
(permissions: bigint) => (overwrites: Overwrite[]) =>
overwrites.reduce(
(permissions, overwrite) =>
(permissions & ~BigInt(overwrite.deny)) | BigInt(overwrite.allow),
permissions,
);