@helyx/module-reactionroles 1.0.12 → 1.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/index.js +0 -325
- package/manifest.json +2 -2
- package/migrations/0001_reactionroles_foundation.sql +60 -0
- package/package.json +2 -2
- package/migrations/0002_cleanup_retry_order.sql +0 -6
- package/migrations/0003_persistent_reactions.sql +0 -37
- package/migrations/0004_entry_lookup_indexes.sql +0 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @helyx/module-reactionroles
|
|
2
2
|
|
|
3
|
+
## 1.0.14
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Remove the Reaction Roles command root now that the dashboard Panels workspace owns panel creation and management.
|
|
8
|
+
|
|
9
|
+
## 1.0.13
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Consolidate the module database migration history into a clean one-file baseline for the planned database rebuild.
|
|
14
|
+
|
|
3
15
|
## 1.0.12
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/dist/index.js
CHANGED
|
@@ -90,103 +90,6 @@ export const reactionRolesModule = defineModule({
|
|
|
90
90
|
},
|
|
91
91
|
records: reactionRoleRecords,
|
|
92
92
|
interactions: {
|
|
93
|
-
commands: [
|
|
94
|
-
{
|
|
95
|
-
name: "reaction-role",
|
|
96
|
-
description: "Create and manage Helyx role panels.",
|
|
97
|
-
registration: "global",
|
|
98
|
-
contexts: ["guild"],
|
|
99
|
-
integrationTypes: ["guild_install"],
|
|
100
|
-
subcommands: [
|
|
101
|
-
{
|
|
102
|
-
name: "create",
|
|
103
|
-
acknowledgement: "immediate-modal",
|
|
104
|
-
description: "Open the guided Reaction Roles builder.",
|
|
105
|
-
permissionId: "reactionroles.create",
|
|
106
|
-
options: [
|
|
107
|
-
{
|
|
108
|
-
type: "channel",
|
|
109
|
-
name: "channel",
|
|
110
|
-
description: "Prefill the destination channel.",
|
|
111
|
-
channelTypes: ["guild_text", "guild_announcement"],
|
|
112
|
-
},
|
|
113
|
-
{
|
|
114
|
-
type: "string",
|
|
115
|
-
name: "style",
|
|
116
|
-
description: "Prefill the public message style.",
|
|
117
|
-
choices: [
|
|
118
|
-
{ name: "Text", value: "text" },
|
|
119
|
-
{ name: "Embed", value: "embed" },
|
|
120
|
-
],
|
|
121
|
-
},
|
|
122
|
-
{
|
|
123
|
-
type: "string",
|
|
124
|
-
name: "control",
|
|
125
|
-
description: "Prefill how members choose roles.",
|
|
126
|
-
choices: [
|
|
127
|
-
{ name: "Buttons", value: "buttons" },
|
|
128
|
-
{ name: "Dropdown", value: "dropdown" },
|
|
129
|
-
{ name: "Emoji reactions", value: "reactions" },
|
|
130
|
-
],
|
|
131
|
-
},
|
|
132
|
-
{
|
|
133
|
-
type: "boolean",
|
|
134
|
-
name: "one-role-only",
|
|
135
|
-
description: "Allow each member to hold only one role from this panel.",
|
|
136
|
-
},
|
|
137
|
-
{
|
|
138
|
-
type: "boolean",
|
|
139
|
-
name: "persistent-reactions",
|
|
140
|
-
description: "Keep member reactions visible and synchronised with roles.",
|
|
141
|
-
},
|
|
142
|
-
],
|
|
143
|
-
rateLimit: { scope: "user", limit: 5, windowSeconds: 60 },
|
|
144
|
-
execute: startCreate,
|
|
145
|
-
},
|
|
146
|
-
{
|
|
147
|
-
name: "edit",
|
|
148
|
-
acknowledgement: "immediate-modal",
|
|
149
|
-
description: "Edit an existing role panel.",
|
|
150
|
-
permissionId: "reactionroles.manage",
|
|
151
|
-
options: [
|
|
152
|
-
referenceOption(),
|
|
153
|
-
{
|
|
154
|
-
type: "boolean",
|
|
155
|
-
name: "persistent-reactions",
|
|
156
|
-
description: "Keep member reactions visible and synchronised with roles.",
|
|
157
|
-
},
|
|
158
|
-
],
|
|
159
|
-
autocomplete: autocompletePanelReference,
|
|
160
|
-
execute: startEdit,
|
|
161
|
-
},
|
|
162
|
-
{
|
|
163
|
-
name: "list",
|
|
164
|
-
acknowledgement: "deferred-ephemeral",
|
|
165
|
-
description: "List the active and degraded role panels.",
|
|
166
|
-
permissionId: "reactionroles.manage",
|
|
167
|
-
execute: listPanels,
|
|
168
|
-
},
|
|
169
|
-
{
|
|
170
|
-
name: "repair",
|
|
171
|
-
acknowledgement: "deferred-ephemeral",
|
|
172
|
-
description: "Revalidate and repair a role panel.",
|
|
173
|
-
permissionId: "reactionroles.manage",
|
|
174
|
-
options: [referenceOption()],
|
|
175
|
-
autocomplete: autocompletePanelReference,
|
|
176
|
-
execute: repairPanel,
|
|
177
|
-
},
|
|
178
|
-
{
|
|
179
|
-
name: "delete",
|
|
180
|
-
acknowledgement: "deferred-ephemeral",
|
|
181
|
-
description: "Delete a role panel without changing member roles.",
|
|
182
|
-
permissionId: "reactionroles.delete",
|
|
183
|
-
options: [referenceOption()],
|
|
184
|
-
autocomplete: autocompletePanelReference,
|
|
185
|
-
execute: prepareDelete,
|
|
186
|
-
},
|
|
187
|
-
],
|
|
188
|
-
},
|
|
189
|
-
],
|
|
190
93
|
buttons: [
|
|
191
94
|
{
|
|
192
95
|
customId: COMPONENT_IDS.continueDraft,
|
|
@@ -432,43 +335,6 @@ export const reactionRolesModule = defineModule({
|
|
|
432
335
|
},
|
|
433
336
|
health: () => ({ status: healthStatus, message: healthMessage }),
|
|
434
337
|
});
|
|
435
|
-
async function startCreate(context) {
|
|
436
|
-
const guildId = requireGuild(context);
|
|
437
|
-
const channel = context.getChannelOption("channel");
|
|
438
|
-
const style = context.getStringOption("style");
|
|
439
|
-
const control = context.getStringOption("control");
|
|
440
|
-
const sessions = sessionService(context.services);
|
|
441
|
-
const nextState = {
|
|
442
|
-
mode: "create",
|
|
443
|
-
selectionMode: context.getBooleanOption("one-role-only") === true
|
|
444
|
-
? "one_only"
|
|
445
|
-
: "multiple",
|
|
446
|
-
persistentReactions: context.getBooleanOption("persistent-reactions") !== false,
|
|
447
|
-
...(channel ? { channelId: channel.id } : {}),
|
|
448
|
-
...(style ? { messageStyle: requiredStyle([style]) } : {}),
|
|
449
|
-
...(control ? { controlType: requiredControl([control]) } : {}),
|
|
450
|
-
};
|
|
451
|
-
const existing = await sessions.getFor(guildId, context.userId, PANEL_PURPOSE);
|
|
452
|
-
if (existing) {
|
|
453
|
-
await sessions.update({
|
|
454
|
-
sessionId: existing.sessionId,
|
|
455
|
-
state: { ...existing.state, pendingReplacement: nextState },
|
|
456
|
-
expectedVersion: existing.version,
|
|
457
|
-
expiresAt: expiresAt(),
|
|
458
|
-
});
|
|
459
|
-
await context.reply(existingDraftResponse());
|
|
460
|
-
return;
|
|
461
|
-
}
|
|
462
|
-
await sessions.create({
|
|
463
|
-
guildId,
|
|
464
|
-
userId: context.userId,
|
|
465
|
-
purpose: PANEL_PURPOSE,
|
|
466
|
-
state: nextState,
|
|
467
|
-
expiresAt: expiresAt(),
|
|
468
|
-
replace: true,
|
|
469
|
-
});
|
|
470
|
-
await context.showModal(basicModal(defaultsFromSessionState(nextState)));
|
|
471
|
-
}
|
|
472
338
|
async function continueDraft(context) {
|
|
473
339
|
const guildId = requireGuild(context);
|
|
474
340
|
const session = await sessionService(context.services).getFor(guildId, context.userId, PANEL_PURPOSE);
|
|
@@ -525,108 +391,6 @@ async function keepDraft(context) {
|
|
|
525
391
|
},
|
|
526
392
|
});
|
|
527
393
|
}
|
|
528
|
-
async function startEdit(context) {
|
|
529
|
-
const guildId = requireGuild(context);
|
|
530
|
-
const panel = await findPanelReference(context.services, guildId, context.getStringOption("reference"));
|
|
531
|
-
const persistentReactions = context.getBooleanOption("persistent-reactions");
|
|
532
|
-
const draft = persistentReactions === null
|
|
533
|
-
? panel
|
|
534
|
-
: validatePanelDraft({ ...panel, persistentReactions });
|
|
535
|
-
await sessionService(context.services).create({
|
|
536
|
-
guildId,
|
|
537
|
-
userId: context.userId,
|
|
538
|
-
purpose: PANEL_PURPOSE,
|
|
539
|
-
state: {
|
|
540
|
-
mode: "edit",
|
|
541
|
-
panelId: panel.panelId,
|
|
542
|
-
expectedRevision: panel.revision,
|
|
543
|
-
draft: serializeDraft(draft),
|
|
544
|
-
},
|
|
545
|
-
expiresAt: expiresAt(),
|
|
546
|
-
replace: true,
|
|
547
|
-
});
|
|
548
|
-
await context.showModal(basicModal(draft, true));
|
|
549
|
-
}
|
|
550
|
-
async function listPanels(context) {
|
|
551
|
-
const guildId = requireGuild(context);
|
|
552
|
-
const result = await panels.repository(context.services).list({
|
|
553
|
-
guildId,
|
|
554
|
-
limit: 10,
|
|
555
|
-
});
|
|
556
|
-
await context.reply({
|
|
557
|
-
ephemeral: true,
|
|
558
|
-
componentsV2: {
|
|
559
|
-
text: [
|
|
560
|
-
{
|
|
561
|
-
content: result.panels.length === 0
|
|
562
|
-
? "No Reaction Roles panels have been created."
|
|
563
|
-
: result.panels
|
|
564
|
-
.map((panel) => `**${panel.title}** · \`${panel.panelId}\` · ${panel.status} · revision ${panel.revision}`)
|
|
565
|
-
.join("\n"),
|
|
566
|
-
},
|
|
567
|
-
],
|
|
568
|
-
},
|
|
569
|
-
allowedUserMentionIds: [],
|
|
570
|
-
});
|
|
571
|
-
}
|
|
572
|
-
async function repairPanel(context) {
|
|
573
|
-
const guildId = requireGuild(context);
|
|
574
|
-
await context.deferReply?.(true);
|
|
575
|
-
const panel = await findPanelReference(context.services, guildId, context.getStringOption("reference"));
|
|
576
|
-
const repaired = await panels.repair(interactionMutationContext(context, guildId), panel.panelId, panel.revision, false);
|
|
577
|
-
await context.reply({
|
|
578
|
-
ephemeral: true,
|
|
579
|
-
componentsV2: {
|
|
580
|
-
text: [
|
|
581
|
-
{
|
|
582
|
-
content: `Role panel **${repaired.title}** is active at revision ${repaired.revision}.`,
|
|
583
|
-
},
|
|
584
|
-
],
|
|
585
|
-
},
|
|
586
|
-
allowedUserMentionIds: [],
|
|
587
|
-
});
|
|
588
|
-
}
|
|
589
|
-
async function prepareDelete(context) {
|
|
590
|
-
const guildId = requireGuild(context);
|
|
591
|
-
const panel = await findPanelReference(context.services, guildId, context.getStringOption("reference"));
|
|
592
|
-
await sessionService(context.services).create({
|
|
593
|
-
guildId,
|
|
594
|
-
userId: context.userId,
|
|
595
|
-
purpose: PANEL_PURPOSE,
|
|
596
|
-
state: {
|
|
597
|
-
mode: "delete",
|
|
598
|
-
panelId: panel.panelId,
|
|
599
|
-
expectedRevision: panel.revision,
|
|
600
|
-
},
|
|
601
|
-
expiresAt: expiresAt(),
|
|
602
|
-
replace: true,
|
|
603
|
-
});
|
|
604
|
-
await context.reply({
|
|
605
|
-
ephemeral: true,
|
|
606
|
-
componentsV2: {
|
|
607
|
-
text: [
|
|
608
|
-
{
|
|
609
|
-
content: `Delete **${panel.title}**? Helyx will try to remove its panel message. Existing member roles will not change.`,
|
|
610
|
-
},
|
|
611
|
-
],
|
|
612
|
-
},
|
|
613
|
-
buttons: [
|
|
614
|
-
{
|
|
615
|
-
type: "button",
|
|
616
|
-
customId: COMPONENT_IDS.deleteConfirm,
|
|
617
|
-
label: "Delete role panel",
|
|
618
|
-
style: "danger",
|
|
619
|
-
},
|
|
620
|
-
{
|
|
621
|
-
type: "button",
|
|
622
|
-
customId: COMPONENT_IDS.cancel,
|
|
623
|
-
label: "Keep role panel",
|
|
624
|
-
style: "secondary",
|
|
625
|
-
},
|
|
626
|
-
],
|
|
627
|
-
allowedUserMentionIds: [],
|
|
628
|
-
});
|
|
629
|
-
}
|
|
630
394
|
async function saveBasicDraft(context) {
|
|
631
395
|
const guildId = requireGuild(context);
|
|
632
396
|
const sessions = sessionService(context.services);
|
|
@@ -1204,39 +968,6 @@ function basicModal(panel, editing = false) {
|
|
|
1204
968
|
],
|
|
1205
969
|
};
|
|
1206
970
|
}
|
|
1207
|
-
function existingDraftResponse() {
|
|
1208
|
-
return {
|
|
1209
|
-
ephemeral: true,
|
|
1210
|
-
componentsV2: {
|
|
1211
|
-
text: [
|
|
1212
|
-
{
|
|
1213
|
-
content: "You already have a Reaction Roles draft. Continue it or replace it with a new draft.",
|
|
1214
|
-
},
|
|
1215
|
-
],
|
|
1216
|
-
},
|
|
1217
|
-
buttons: [
|
|
1218
|
-
{
|
|
1219
|
-
type: "button",
|
|
1220
|
-
customId: COMPONENT_IDS.continueDraft,
|
|
1221
|
-
label: "Continue draft",
|
|
1222
|
-
style: "primary",
|
|
1223
|
-
},
|
|
1224
|
-
{
|
|
1225
|
-
type: "button",
|
|
1226
|
-
customId: COMPONENT_IDS.replaceDraft,
|
|
1227
|
-
label: "Replace draft",
|
|
1228
|
-
style: "danger",
|
|
1229
|
-
},
|
|
1230
|
-
{
|
|
1231
|
-
type: "button",
|
|
1232
|
-
customId: COMPONENT_IDS.keepDraft,
|
|
1233
|
-
label: "Cancel",
|
|
1234
|
-
style: "secondary",
|
|
1235
|
-
},
|
|
1236
|
-
],
|
|
1237
|
-
allowedUserMentionIds: [],
|
|
1238
|
-
};
|
|
1239
|
-
}
|
|
1240
971
|
function defaultsFromSessionState(state) {
|
|
1241
972
|
return {
|
|
1242
973
|
...(typeof state.channelId === "string"
|
|
@@ -1402,62 +1133,6 @@ function interactionMutationContext(context, guildId) {
|
|
|
1402
1133
|
addChannelMessageReaction: (channelId, messageId, emojiIdentifier) => context.addChannelMessageReaction(channelId, messageId, emojiIdentifier),
|
|
1403
1134
|
};
|
|
1404
1135
|
}
|
|
1405
|
-
async function findPanelReference(services, guildId, value) {
|
|
1406
|
-
const reference = value?.trim();
|
|
1407
|
-
if (!reference)
|
|
1408
|
-
throw new Error("Role panel reference is required");
|
|
1409
|
-
const panel = await panels.repository(services).findById(guildId, reference);
|
|
1410
|
-
if (!panel)
|
|
1411
|
-
throw new Error("Role panel was not found");
|
|
1412
|
-
return panel;
|
|
1413
|
-
}
|
|
1414
|
-
async function autocompletePanelReference(context) {
|
|
1415
|
-
if (!context.serverId || context.focusedOptionName !== "reference") {
|
|
1416
|
-
await context.respond([]);
|
|
1417
|
-
return;
|
|
1418
|
-
}
|
|
1419
|
-
const query = context.focusedValue.trim().normalize("NFKC").toLowerCase();
|
|
1420
|
-
const repository = panels.repository(context.services);
|
|
1421
|
-
const choices = [];
|
|
1422
|
-
let cursor;
|
|
1423
|
-
for (let pageNumber = 0; pageNumber < 5 && choices.length < 25; pageNumber += 1) {
|
|
1424
|
-
const page = await repository.listReferences({
|
|
1425
|
-
guildId: context.serverId,
|
|
1426
|
-
...(cursor ? { cursor } : {}),
|
|
1427
|
-
limit: query ? 100 : 25,
|
|
1428
|
-
});
|
|
1429
|
-
for (const panel of page.panels) {
|
|
1430
|
-
if (panel.status === "deleting")
|
|
1431
|
-
continue;
|
|
1432
|
-
const searchable = `${panel.title} ${panel.panelId} ${panel.status}`.toLowerCase();
|
|
1433
|
-
if (query && !searchable.includes(query))
|
|
1434
|
-
continue;
|
|
1435
|
-
const title = panel.title.replaceAll(/\s+/gu, " ").trim();
|
|
1436
|
-
const suffix = `${panel.status} · ${panel.panelId.slice(0, 8)}`;
|
|
1437
|
-
choices.push({
|
|
1438
|
-
name: `${title.slice(0, Math.max(1, 97 - suffix.length))} · ${suffix}`,
|
|
1439
|
-
value: panel.panelId,
|
|
1440
|
-
});
|
|
1441
|
-
if (choices.length === 25)
|
|
1442
|
-
break;
|
|
1443
|
-
}
|
|
1444
|
-
if (!query || !page.nextCursor)
|
|
1445
|
-
break;
|
|
1446
|
-
cursor = page.nextCursor;
|
|
1447
|
-
}
|
|
1448
|
-
await context.respond(choices);
|
|
1449
|
-
}
|
|
1450
|
-
function referenceOption() {
|
|
1451
|
-
return {
|
|
1452
|
-
type: "string",
|
|
1453
|
-
name: "reference",
|
|
1454
|
-
description: "Panel reference shown by /reaction-role list.",
|
|
1455
|
-
required: true,
|
|
1456
|
-
minLength: 1,
|
|
1457
|
-
maxLength: 100,
|
|
1458
|
-
autocomplete: true,
|
|
1459
|
-
};
|
|
1460
|
-
}
|
|
1461
1136
|
function sessionService(services) {
|
|
1462
1137
|
return services.get(HELYX_SERVICE_NAMES.sessions);
|
|
1463
1138
|
}
|
package/manifest.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"releaseStatus": "live",
|
|
4
4
|
"id": "helyx.reactionroles",
|
|
5
5
|
"name": "Reaction Roles",
|
|
6
|
-
"version": "1.0.
|
|
6
|
+
"version": "1.0.14",
|
|
7
7
|
"description": "Let members select approved roles themselves.",
|
|
8
8
|
"entry": "./dist/index.js",
|
|
9
9
|
"framework": "^0.1.0",
|
|
@@ -307,7 +307,7 @@
|
|
|
307
307
|
}
|
|
308
308
|
},
|
|
309
309
|
"contributions": {
|
|
310
|
-
"commands": [
|
|
310
|
+
"commands": [],
|
|
311
311
|
"events": [
|
|
312
312
|
"discord.channel-delete",
|
|
313
313
|
"discord.channel-update",
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
-- Baseline source: 0001_reactionroles_foundation.sql
|
|
2
|
+
|
|
1
3
|
CREATE TABLE IF NOT EXISTS reactionroles_panels (
|
|
2
4
|
panel_id text PRIMARY KEY,
|
|
3
5
|
guild_id text NOT NULL,
|
|
@@ -106,3 +108,61 @@ CREATE UNIQUE INDEX IF NOT EXISTS reactionroles_cleanup_message_reason_idx
|
|
|
106
108
|
message_id,
|
|
107
109
|
reason
|
|
108
110
|
);
|
|
111
|
+
|
|
112
|
+
-- Baseline source: 0002_cleanup_retry_order.sql
|
|
113
|
+
|
|
114
|
+
UPDATE reactionroles_message_cleanup
|
|
115
|
+
SET next_attempt_at = created_at
|
|
116
|
+
WHERE next_attempt_at IS NULL;
|
|
117
|
+
|
|
118
|
+
ALTER TABLE reactionroles_message_cleanup
|
|
119
|
+
ALTER COLUMN next_attempt_at SET NOT NULL;
|
|
120
|
+
|
|
121
|
+
-- Baseline source: 0003_persistent_reactions.sql
|
|
122
|
+
|
|
123
|
+
ALTER TABLE reactionroles_panels
|
|
124
|
+
ADD COLUMN IF NOT EXISTS persistent_reactions boolean NOT NULL DEFAULT true;
|
|
125
|
+
|
|
126
|
+
DO $$
|
|
127
|
+
DECLARE
|
|
128
|
+
constraint_name text;
|
|
129
|
+
BEGIN
|
|
130
|
+
FOR constraint_name IN
|
|
131
|
+
SELECT conname
|
|
132
|
+
FROM pg_constraint
|
|
133
|
+
WHERE conrelid = 'reactionroles_panels'::regclass
|
|
134
|
+
AND contype = 'c'
|
|
135
|
+
AND conname <> 'reactionroles_panels_reaction_selection_check'
|
|
136
|
+
AND pg_get_constraintdef(oid) LIKE '%control_type%reactions%selection_mode%'
|
|
137
|
+
LOOP
|
|
138
|
+
EXECUTE format(
|
|
139
|
+
'ALTER TABLE reactionroles_panels DROP CONSTRAINT %I',
|
|
140
|
+
constraint_name
|
|
141
|
+
);
|
|
142
|
+
END LOOP;
|
|
143
|
+
|
|
144
|
+
IF NOT EXISTS (
|
|
145
|
+
SELECT 1
|
|
146
|
+
FROM pg_constraint
|
|
147
|
+
WHERE conrelid = 'reactionroles_panels'::regclass
|
|
148
|
+
AND conname = 'reactionroles_panels_reaction_selection_check'
|
|
149
|
+
) THEN
|
|
150
|
+
ALTER TABLE reactionroles_panels
|
|
151
|
+
ADD CONSTRAINT reactionroles_panels_reaction_selection_check
|
|
152
|
+
CHECK (
|
|
153
|
+
control_type <> 'reactions'
|
|
154
|
+
OR selection_mode <> 'one_only'
|
|
155
|
+
OR persistent_reactions = false
|
|
156
|
+
);
|
|
157
|
+
END IF;
|
|
158
|
+
END
|
|
159
|
+
$$;
|
|
160
|
+
|
|
161
|
+
-- Baseline source: 0004_entry_lookup_indexes.sql
|
|
162
|
+
|
|
163
|
+
CREATE INDEX IF NOT EXISTS reactionroles_entries_role_panel_idx
|
|
164
|
+
ON reactionroles_entries (role_id, panel_id);
|
|
165
|
+
|
|
166
|
+
CREATE INDEX IF NOT EXISTS reactionroles_entries_emoji_panel_idx
|
|
167
|
+
ON reactionroles_entries (emoji_id, panel_id)
|
|
168
|
+
WHERE emoji_id IS NOT NULL;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@helyx/module-reactionroles",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.14",
|
|
4
4
|
"description": "Configurable self-service Discord role panels for Helyx.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"helyx",
|
|
@@ -50,6 +50,6 @@
|
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"@helyx/module-manifest": ">=0.7.0 <0.8.0",
|
|
53
|
-
"@helyx/sdk": ">=0.8.
|
|
53
|
+
"@helyx/sdk": ">=0.8.4 <0.9.0"
|
|
54
54
|
}
|
|
55
55
|
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
ALTER TABLE reactionroles_panels
|
|
2
|
-
ADD COLUMN IF NOT EXISTS persistent_reactions boolean NOT NULL DEFAULT true;
|
|
3
|
-
|
|
4
|
-
DO $$
|
|
5
|
-
DECLARE
|
|
6
|
-
constraint_name text;
|
|
7
|
-
BEGIN
|
|
8
|
-
FOR constraint_name IN
|
|
9
|
-
SELECT conname
|
|
10
|
-
FROM pg_constraint
|
|
11
|
-
WHERE conrelid = 'reactionroles_panels'::regclass
|
|
12
|
-
AND contype = 'c'
|
|
13
|
-
AND conname <> 'reactionroles_panels_reaction_selection_check'
|
|
14
|
-
AND pg_get_constraintdef(oid) LIKE '%control_type%reactions%selection_mode%'
|
|
15
|
-
LOOP
|
|
16
|
-
EXECUTE format(
|
|
17
|
-
'ALTER TABLE reactionroles_panels DROP CONSTRAINT %I',
|
|
18
|
-
constraint_name
|
|
19
|
-
);
|
|
20
|
-
END LOOP;
|
|
21
|
-
|
|
22
|
-
IF NOT EXISTS (
|
|
23
|
-
SELECT 1
|
|
24
|
-
FROM pg_constraint
|
|
25
|
-
WHERE conrelid = 'reactionroles_panels'::regclass
|
|
26
|
-
AND conname = 'reactionroles_panels_reaction_selection_check'
|
|
27
|
-
) THEN
|
|
28
|
-
ALTER TABLE reactionroles_panels
|
|
29
|
-
ADD CONSTRAINT reactionroles_panels_reaction_selection_check
|
|
30
|
-
CHECK (
|
|
31
|
-
control_type <> 'reactions'
|
|
32
|
-
OR selection_mode <> 'one_only'
|
|
33
|
-
OR persistent_reactions = false
|
|
34
|
-
);
|
|
35
|
-
END IF;
|
|
36
|
-
END
|
|
37
|
-
$$;
|