Skip to content

Commit dae418c

Browse files
committed
Basic role logging
1 parent 47a4c38 commit dae418c

File tree

10 files changed

+463
-83
lines changed

10 files changed

+463
-83
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import type { AuditLogChange, Permission } from "oceanic.js";
2+
3+
export interface AuditLogUpdate<T> {
4+
old?: T;
5+
new?: T;
6+
}
7+
8+
export type AuditLogUpdates = Partial<Record<string, AuditLogUpdate<unknown>>>;
9+
10+
export interface RoleUpdates {
11+
name?: AuditLogUpdate<string>;
12+
permissions?: AuditLogUpdate<Permission>;
13+
color?: AuditLogUpdate<number>;
14+
hoist: AuditLogUpdate<boolean>;
15+
mentionable?: AuditLogUpdate<boolean>;
16+
}
17+
18+
export function parseUpdates(changes: AuditLogChange[]): AuditLogUpdates {
19+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
20+
const result: AuditLogUpdates = Object.create(null);
21+
22+
for (const change of changes) {
23+
result[change.key] = {
24+
old: "old_value" in change ? change.old_value : undefined,
25+
new: change.new_value
26+
};
27+
}
28+
29+
return result;
30+
}
31+
32+
export function parseRoleUpdates(changes: AuditLogChange[]): RoleUpdates {
33+
return parseUpdates(changes) as unknown as RoleUpdates;
34+
}

backend/src/common/errors.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export function todo(): never {
22
throw new Error("Function not implemented");
33
}
4+

backend/src/common/template/formatting.ts

Lines changed: 54 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { formatUser, formatUserBold } from "#common/discord/format.ts";
22
import { escapeMarkdown, makeMarkdownInlineCodeblock, makeMarkdownMultilineCodeblock, makeMarkdownQuote } from "#common/discord/markdown.ts";
3-
import { DurationPresentationType, FormattingWrapper, GuildPresentationType, ParameterType, TimestampPresentationType, UserPresentationType, type GuildParameter, type ParameterRecord, type UserParameter } from "#common/template/index.ts";
3+
import { DurationPresentationType, FormattingWrapper, GuildPresentationType, ParameterType, RolePresentationType, TimestampPresentationType, UserPresentationType, type EntityParameter, type ParameterRecord, type UserParameter } from "#common/template/index.ts";
44
import { TokenType, type Token } from "#common/template/parsing.ts";
55
import { dateToUnixSeconds, humanizeDuration } from "#common/time.ts";
6+
import { INTERNAL_TYPE_INTEGRITY } from "#environment.ts";
67

78
export function formatTokens(params: ParameterRecord, tokens: Token[]): string {
89
let result = "";
@@ -22,23 +23,29 @@ export function formatTokens(params: ParameterRecord, tokens: Token[]): string {
2223

2324
switch (token.valueType) {
2425
case ParameterType.User:
25-
if (!(typeof value === "object"
26-
&& "id" in value && typeof value.id === "string"
27-
&& "tag" in value && typeof value.tag === "string")) {
26+
if (!isUserParam(value))
2827
throw new Error(`params['${token.parameter}'] is not a user!`);
29-
}
3028

3129
output = formatUserParam(value, token.presentation, escaped);
3230
break;
3331
case ParameterType.Guild:
34-
if (!(typeof value === "object"
35-
&& "id" in value && typeof value.id === "string"
36-
&& "name" in value && typeof value.name === "string")) {
37-
throw new Error(`params['${token.parameter}'] is not a user!`);
38-
}
32+
if (!isEntityParam(value))
33+
throw new Error(`params['${token.parameter}'] is not a guild!`);
3934

4035
output = formatGuildParam(value, token.presentation, escaped);
4136
break;
37+
case ParameterType.Role:
38+
if (!isEntityParam(value))
39+
throw new Error(`params['${token.parameter}'] is not a role!`);
40+
41+
output = formatRoleParam(value, token.presentation, escaped);
42+
break;
43+
case ParameterType.Number:
44+
if (typeof value !== "number")
45+
throw new Error(`params['${token.parameter}'] is not a number!`);
46+
47+
output = value.toString();
48+
break;
4249
case ParameterType.Duration:
4350
if (typeof value !== "number")
4451
throw new Error(`params['${token.parameter}'] is not a number!`);
@@ -56,7 +63,10 @@ export function formatTokens(params: ParameterRecord, tokens: Token[]): string {
5663
if (typeof value !== "string")
5764
throw new Error(`params['${token.parameter}'] is not a string!`);
5865

59-
output = value;
66+
if (escaped && token.valueType === ParameterType.RawString)
67+
output = escapeMarkdown(value);
68+
else
69+
output = value;
6070
break;
6171
}
6272
} else
@@ -78,7 +88,24 @@ export function formatTokens(params: ParameterRecord, tokens: Token[]): string {
7888
}
7989

8090
return result;
91+
}
8192

93+
function isUserParam(value: {} | undefined): value is UserParameter {
94+
if (!INTERNAL_TYPE_INTEGRITY)
95+
return true;
96+
97+
return typeof value === "object"
98+
&& "id" in value && typeof value.id === "string"
99+
&& "tag" in value && typeof value.tag === "string";
100+
}
101+
102+
function isEntityParam(value: {} | undefined): value is EntityParameter {
103+
if (!INTERNAL_TYPE_INTEGRITY)
104+
return true;
105+
106+
return typeof value === "object"
107+
&& "id" in value && typeof value.id === "string"
108+
&& "name" in value && typeof value.name === "string";
82109
}
83110

84111
function formatUserParam(user: UserParameter, presentation: UserPresentationType, escaped: boolean): string {
@@ -100,7 +127,7 @@ function formatUserParam(user: UserParameter, presentation: UserPresentationType
100127
}
101128
}
102129

103-
function formatGuildParam(guild: GuildParameter, presentation: GuildPresentationType, escaped: boolean): string {
130+
function formatGuildParam(guild: EntityParameter, presentation: GuildPresentationType, escaped: boolean): string {
104131
switch (presentation) {
105132
case GuildPresentationType.Name:
106133
return escaped ? escapeMarkdown(guild.name) : guild.name;
@@ -113,6 +140,21 @@ function formatGuildParam(guild: GuildParameter, presentation: GuildPresentation
113140
}
114141
}
115142

143+
function formatRoleParam(role: EntityParameter, presentation: RolePresentationType, escaped: boolean): string {
144+
switch (presentation) {
145+
case RolePresentationType.Name:
146+
return escaped ? escapeMarkdown(role.name) : role.name;
147+
case RolePresentationType.Mention:
148+
return `<@&${role.id}>`;
149+
case RolePresentationType.NameMention:
150+
return `${escapeMarkdown(role.name)} (<@&${role.id}>)`;
151+
case RolePresentationType.NameMentionBold:
152+
return `**${escapeMarkdown(role.name)} (<@&${role.id}>)**`;
153+
case RolePresentationType.ID:
154+
return role.id;
155+
}
156+
}
157+
116158
function formatDurationParam(duration: number, presentation: DurationPresentationType): string {
117159
switch (presentation) {
118160
case DurationPresentationType.Readable:

backend/src/common/template/index.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ export const enum FormattingWrapper {
4646
export const enum ParameterType {
4747
User,
4848
Guild,
49+
Role,
50+
Number,
4951
Duration,
5052
Timestamp,
5153
RawString,
@@ -69,6 +71,14 @@ export const enum GuildPresentationType {
6971
MaskedLink,
7072
}
7173

74+
export const enum RolePresentationType {
75+
Name,
76+
Mention,
77+
NameMention,
78+
NameMentionBold,
79+
ID,
80+
}
81+
7282
export const enum DurationPresentationType {
7383
Readable,
7484
Seconds,
@@ -88,11 +98,13 @@ export const enum TimestampPresentationType {
8898
}
8999

90100
export type UserParameter = { id: string; tag: string; };
91-
export type GuildParameter = { id: string; name: string; };
101+
export type EntityParameter = { id: string; name: string; };
92102

93103
type ParameterValue<T extends ParameterType = any> =
94104
T extends ParameterType.User ? UserParameter :
95-
T extends ParameterType.Guild ? GuildParameter :
105+
T extends ParameterType.Guild ? EntityParameter :
106+
T extends ParameterType.Role ? EntityParameter :
107+
T extends ParameterType.Number ? number :
96108
T extends ParameterType.RawString ? string :
97109
T extends ParameterType.MarkdownString ? string :
98110
T extends ParameterType.Duration ? number :

backend/src/common/template/parsing.ts

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { DurationPresentationType, FormattingWrapper, GuildPresentationType, ParameterType, TimestampPresentationType, UserPresentationType } from "#common/template/index.ts";
1+
import { DurationPresentationType, FormattingWrapper, GuildPresentationType, ParameterType, RolePresentationType, TimestampPresentationType, UserPresentationType } from "#common/template/index.ts";
22

33
const FORMAT_PATTERN = /\{\{(?<wrapper>>|`|```)?(?<parameter>\w+)(?:#(?<presentation>\w+))?\}\}?/g;
44

@@ -53,6 +53,8 @@ function parseFormatToken(input: FormatGroups, params: Record<string, ParameterT
5353

5454
const result = { type: TokenType.Format, parameter: input.parameter, wrapper } as const;
5555

56+
// TODO: what is this horror...
57+
5658
switch (valueType) {
5759
case ParameterType.User: {
5860
const presentation = parseUserPresentation(input.presentation);
@@ -70,6 +72,14 @@ function parseFormatToken(input: FormatGroups, params: Record<string, ParameterT
7072

7173
return { ...result, valueType, presentation };
7274
}
75+
case ParameterType.Role: {
76+
const presentation = parseRolePresentation(input.presentation);
77+
78+
if (presentation === null)
79+
return `Invalid role presentation: '${input.presentation!}'`;
80+
81+
return { ...result, valueType, presentation };
82+
}
7383
case ParameterType.Duration: {
7484
const presentation = parseDurationPresentation(input.presentation);
7585

@@ -86,6 +96,7 @@ function parseFormatToken(input: FormatGroups, params: Record<string, ParameterT
8696

8797
return { ...result, valueType, presentation };
8898
}
99+
case ParameterType.Number:
89100
case ParameterType.RawString:
90101
case ParameterType.MarkdownString:
91102
return { ...result, valueType };
@@ -143,6 +154,24 @@ function parseGuildPresentation(input: string | undefined): GuildPresentationTyp
143154
}
144155
}
145156

157+
function parseRolePresentation(input: string | undefined): RolePresentationType | null {
158+
switch (input) {
159+
case "name":
160+
case undefined:
161+
return RolePresentationType.Name;
162+
case "mention":
163+
return RolePresentationType.Mention;
164+
case "name_mention":
165+
return RolePresentationType.NameMention;
166+
case "name_mention_bold":
167+
return RolePresentationType.NameMentionBold;
168+
case "id":
169+
return RolePresentationType.ID;
170+
default:
171+
return null;
172+
}
173+
}
174+
146175
function parseDurationPresentation(input: string | undefined): DurationPresentationType | null {
147176
switch (input) {
148177
case "readable":
@@ -217,8 +246,9 @@ export type FormatToken =
217246
& (
218247
| { valueType: ParameterType.User; presentation: UserPresentationType; }
219248
| { valueType: ParameterType.Guild; presentation: GuildPresentationType; }
249+
| { valueType: ParameterType.Role; presentation: RolePresentationType; }
220250
| { valueType: ParameterType.Duration; presentation: DurationPresentationType; }
221251
| { valueType: ParameterType.Timestamp; presentation: TimestampPresentationType; }
222-
| { valueType: ParameterType.MarkdownString | ParameterType.RawString; }
252+
| { valueType: ParameterType.Number | ParameterType.MarkdownString | ParameterType.RawString; }
223253
)
224254
& { wrapper: FormattingWrapper | null; };

0 commit comments

Comments
 (0)