Skip to content
Open
Show file tree
Hide file tree
Changes from 65 commits
Commits
Show all changes
101 commits
Select commit Hold shift + click to select a range
853e60b
Big update
crystopherross Apr 25, 2025
f0121c6
Merge remote-tracking branch 'origin/main' into iss41
crystopherross Apr 26, 2025
33085c6
nothing special
crystopherross Apr 26, 2025
9cb3c2e
Add permission to new manual dfunkt update command
crystopherross Apr 26, 2025
b663083
Linter and Prettier :D
crystopherross May 8, 2025
c817900
Add more testing info, remove code duplication.
crystopherross May 12, 2025
95289af
Provide more detailed test fail info.
crystopherross May 12, 2025
1caa99d
Provide more detailed test info.
crystopherross May 12, 2025
0de9435
Atomize update logic further.
crystopherross May 12, 2025
d282c04
Fix console log message
crystopherross May 12, 2025
65a530e
Skip cache while fetching for testting purposes.
crystopherross May 12, 2025
0e6e069
Lint + prettier
crystopherross May 12, 2025
78a14d2
Big update
crystopherross Apr 25, 2025
be0594b
nothing special
crystopherross Apr 26, 2025
647a199
Add permission to new manual dfunkt update command
crystopherross Apr 26, 2025
0e0f647
Linter and Prettier :D
crystopherross May 8, 2025
cfb2aae
Add more testing info, remove code duplication.
crystopherross May 12, 2025
6603d4d
Provide more detailed test fail info.
crystopherross May 12, 2025
c342a30
Provide more detailed test info.
crystopherross May 12, 2025
b7f78db
Atomize update logic further.
crystopherross May 12, 2025
c5ac5f7
Fix console log message
crystopherross May 12, 2025
9d4929d
Skip cache while fetching for testting purposes.
crystopherross May 12, 2025
19b3c9b
Lint + prettier
crystopherross May 12, 2025
89182be
try rebase
crystopherross May 15, 2025
00c07a2
Merge branch 'iss41' of https://github.com/datasektionen/harmony into…
crystopherross May 15, 2025
2881885
Try rebase 2
crystopherross May 15, 2025
b1348ce
Update src/commands/testMandate/test.command.ts
crystopherross May 22, 2025
132c52f
Add subcommands because apparently I like work.
crystopherross May 22, 2025
460875d
Merge branch 'iss41' of https://github.com/datasektionen/harmony into…
crystopherross May 22, 2025
4473a50
Add EV check for Hive credentials.
crystopherross Jun 22, 2025
754aaa0
Redo the `dfunk` command.
crystopherross Jun 22, 2025
2d4c934
Redo the dfunk update routine to use Hive.
crystopherross Jun 22, 2025
3bbb8e5
Add functionality to fetch data (API calls) from Hive.
crystopherross Jun 22, 2025
27a5485
Temporarily modify test cases (some roles still missing on Hive)
crystopherross Jun 22, 2025
ff37b91
Adapt test script for dfunk role update to the new version using Hive.
crystopherross Jun 22, 2025
7988ceb
Remove hard-coded translation tables.
crystopherross Jun 22, 2025
da6872f
Change all appereances of `dfunkt` to `dfunk`.
crystopherross Jun 22, 2025
ffbbde6
Variable rename
crystopherross Jun 22, 2025
4750980
Fix problems with previous variable renaming and translation tables.
crystopherross Jun 22, 2025
23faf0a
Make the dfunk role update cronjob target all servers the bot is in.
crystopherross Jun 22, 2025
c2deaa7
Remove unnecesary import.
crystopherross Jun 22, 2025
f267ec9
Format and linting
crystopherross Jun 22, 2025
0348d21
Update test cases.
crystopherross Sep 4, 2025
949e82e
Change Test Case Format
crystopherross Sep 4, 2025
93ea5c2
Change Testing logic following changes to test format.
crystopherross Sep 4, 2025
13436ce
Äntligen klar med issuen:
crystopherross Sep 4, 2025
96f46bb
Fix test validator
crystopherross Sep 4, 2025
d133e4b
Change test evaluation logic
crystopherross Sep 4, 2025
a0939dc
Remove unnecessary artifacts.
crystopherross Sep 4, 2025
dbadbaa
Linting
crystopherross Sep 4, 2025
dab874a
Reduced code duplication (still a lot of boilerplate).
crystopherross Sep 18, 2025
7a04300
Mattermost webhook endpoint moved to top of file.
crystopherross Sep 18, 2025
ccd8b53
Added 'toggle' and 'status' subcommands for 'dfunk'
crystopherross Sep 18, 2025
c6c4e92
Linting
crystopherross Sep 18, 2025
d54bc78
Update comments
crystopherross Sep 18, 2025
9ed1df3
Linting
crystopherross Sep 18, 2025
16dc4fe
Merge remote-tracking branch 'origin/main' into iss41
crystopherross Sep 18, 2025
7d579f6
Use custom-made log functions.
crystopherross Sep 18, 2025
1725c45
Restore the dfunk CronTime to each Saturday
crystopherross Sep 18, 2025
d355f0b
Modify log functions to take arbitrary inputs.
crystopherross Sep 23, 2025
9b77491
Use project's log functions.
crystopherross Sep 23, 2025
2f3e763
Rename update-dfunk-roles-get-post.ts to update-dfunk-roles.ts
crystopherross Sep 23, 2025
59acec8
Revert wide automatic role update.
crystopherross Sep 25, 2025
df2dbef
Lint
crystopherross Sep 25, 2025
6007d7d
Merge branch 'main' into iss41
crystopherross Sep 25, 2025
eb91934
Update src/commands/dfunk/subcommands/status/dfunk-status.handler.ts
crystopherross Sep 26, 2025
88f0e16
It is "elegibles", not "legibles".
crystopherross Oct 2, 2025
a18d0aa
Add envvars for Hive and Mattermost webhook in template.
crystopherross Oct 2, 2025
9741ec0
Use envvar to access Mattermost webhook token instead.
crystopherross Oct 2, 2025
f857dfb
Merge branch 'iss41' of https://github.com/datasektionen/harmony into…
crystopherross Oct 2, 2025
e96c035
Remove unnecessary local variables.
crystopherross Oct 2, 2025
f251b63
Remove unusued API functions for dfunk, retain the endpoints for futu…
crystopherross Oct 2, 2025
48cc015
Temporarily remove the tests.
crystopherross Oct 3, 2025
b6c9c03
Remove explicit test dependencies.
crystopherross Oct 3, 2025
5f0b43e
It is "elegibles", not "legibles".
crystopherross Oct 3, 2025
a3669b9
Initialize "test frmework" barebones.
crystopherross Oct 3, 2025
6939ad1
Isolate tests from production.
crystopherross Oct 3, 2025
ea518d1
Add 'test' command registration logic
crystopherross Oct 3, 2025
9863066
Finalize 'test framework' barebones
crystopherross Oct 3, 2025
a73556c
Patch .gitignore
crystopherross Oct 3, 2025
a038eb7
Stop tracking "test framework" barebone files.
crystopherross Oct 3, 2025
ab7eefe
Formatting
crystopherross Nov 14, 2025
53b08fd
Merge remote-tracking branch 'origin/main' into iss41
crystopherross Nov 14, 2025
c2725a1
Remove `/dfunk test` command.
crystopherross Nov 15, 2025
59f6f21
Remove `/dfunk test` command
crystopherross Nov 15, 2025
c110357
Change hive API error messages, rename `HIVE` envvar.
crystopherross Nov 15, 2025
177640e
Separate testing logic from the dfunk update.
crystopherross Nov 15, 2025
8f55a55
Format
crystopherross Nov 15, 2025
90ca541
Remove old files from the `include` field in `tsconfig.json`
crystopherross Nov 15, 2025
f14716e
Remove unnecessary endpoints, add comments.
crystopherross Nov 15, 2025
15aabcb
Format
crystopherross Nov 15, 2025
6ffff80
Add environment variables for Hive and Mattermost.
crystopherross Nov 20, 2025
e41a6ee
Remove Mattermost Token
crystopherross Nov 20, 2025
101c7e8
Add assets to dev environment.
crystopherross Nov 20, 2025
5fdba8c
Add `log` command.
crystopherross Nov 20, 2025
fa20be8
Add file for storing log channel ID.
crystopherross Jan 29, 2026
f4fb1a6
Change error reporting.
crystopherross Jan 29, 2026
2325067
Fix `/dfunk status` Discord bot message.
crystopherross Mar 15, 2026
011c13d
Add error handling when trying to execute job on unkown guild
crystopherross Mar 15, 2026
82665a3
Reset crontime to every Saturday 00.00
crystopherross Mar 15, 2026
2112010
Make the cronjob actually execute the update (again)
crystopherross Mar 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"@types/node": "^17.0.45",
"@typescript-eslint/eslint-plugin": "^6.7.4",
"@typescript-eslint/parser": "^6.7.4",
"cron": "^4.3.0",
"dotenv": "^16.0.3",
"eslint": "^8.24.0",
"eslint-config-prettier": "^8.5.0",
Expand Down
2 changes: 2 additions & 0 deletions src/commands/commands.names.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,7 @@ export enum CommandNames {
CLUB = "club",
KTHID = "kthid",
NOLLEGRUPP = "nollegrupp",
DFUNK = "dfunk",
KILLMOTTAGNINGEN = "killmottagningen",
MOTTAGNINGEN = "mottagningen",
}
2 changes: 2 additions & 0 deletions src/commands/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { translateMsgCommand } from "./translate/translateMsg.command";
import { clubCommand } from "./club/club.command";
import { messageCommand } from "./message/message.command";
import { ContextMenuCommandBuilder, SlashCommandBuilder } from "discord.js";
import { dfunkCommand } from "./dfunk/dfunk.command";
import { kthIdCommand } from "./kthid/kthid.command";
import { mottagningenCommand } from "./mottagningen/mottagningen.command";

Expand All @@ -30,6 +31,7 @@ export const getOfficialBotCommands = async (): Promise<
translateMsgCommand,
clubCommand,
messageCommand,
dfunkCommand,
kthIdCommand,
nollegruppCommand,
mottagningenCommand,
Expand Down
6 changes: 6 additions & 0 deletions src/commands/dfunk/dfunk-subcommands.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export enum DfunkSubcommands {
UPDATE = "update",
TEST = "test",
STATUS = "status",
TOGGLE = "toggle",
}
36 changes: 36 additions & 0 deletions src/commands/dfunk/dfunk.command.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { SlashCommandBuilder, PermissionFlagsBits } from "discord.js";
import { CommandNames } from "../commands.names";
import { DfunkSubcommands } from "./dfunk-subcommands";

const command = new SlashCommandBuilder()
.setName(CommandNames.DFUNK)
.setDescription("Command related to the dfunk automatic update.")
.setDefaultMemberPermissions(PermissionFlagsBits.ManageGuild);

command.addSubcommand((subCommand) =>
subCommand
.setName(DfunkSubcommands.UPDATE)
.setDescription("Manually start the dfunk role update routine.")
);

command.addSubcommand((subCommand) =>
subCommand
.setName(DfunkSubcommands.TEST)
.setDescription("Start the dfunk role update test routine.")
);

command.addSubcommand((subCommand) =>
subCommand
.setName(DfunkSubcommands.TOGGLE)
.setDescription("Toggles the automatic dfunk role update routine.")
);

command.addSubcommand((subCommand) =>
subCommand
.setName(DfunkSubcommands.STATUS)
.setDescription(
"Reveals the current status of the automatic dfunk role update."
)
);

export const dfunkCommand = command;
26 changes: 26 additions & 0 deletions src/commands/dfunk/dfunk.handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { CommandNotFoundError } from "../../shared/errors/command-not-founder.error";
import { GuildChatInputCommandInteraction } from "../../shared/types/GuildChatInputCommandType";
import { DfunkSubcommands } from "./dfunk-subcommands";
import { handleDfunkTest } from "./subcommands/test/dfunk-test.handler";
import { handleDfunkUpdate } from "./subcommands/update/dfunk-update.handler";
import { handleDfunkToggle } from "./subcommands/toggle/dfunk-toggle.handler";
import { handleDfunkStatus } from "./subcommands/status/dfunk-status.handler";

export async function handleDfunk(
interaction: GuildChatInputCommandInteraction
): Promise<void> {
const subcommandName = interaction.options.getSubcommand(true);

switch (subcommandName) {
case DfunkSubcommands.UPDATE:
return await handleDfunkUpdate(interaction);
case DfunkSubcommands.TEST:
return await handleDfunkTest(interaction);
case DfunkSubcommands.STATUS:
return await handleDfunkStatus(interaction);
case DfunkSubcommands.TOGGLE:
return await handleDfunkToggle(interaction);
default:
throw new CommandNotFoundError(interaction.commandName);
}
}
30 changes: 30 additions & 0 deletions src/commands/dfunk/subcommands/status/dfunk-status.handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { MessageFlags } from "discord.js";
import { jobs } from "../../../../index";
import { GuildChatInputCommandInteraction } from "../../../../shared/types/GuildChatInputCommandType";

export const handleDfunkStatus = async (
interaction: GuildChatInputCommandInteraction
): Promise<void> => {
// We assume that this job is loaded
const dfunkUpdateJob = jobs.get("updateDfunkRoles")!;
const jobStatus = dfunkUpdateJob.job.isActive;
if (jobStatus) {
Comment thread
crystopherross marked this conversation as resolved.
Outdated
await interaction.reply({
content: `The automatic dfunk role update is active.
The automatic update was last executed ${
dfunkUpdateJob.job.lastExecution
}.
The next automatic update will be executed ${dfunkUpdateJob.job.nextDate()}
To toggle this functionality on/off, use the \`/dfunk toggle\` command.
`,
flags: MessageFlags.Ephemeral,
});
} else {
await interaction.reply({
content: `The automatic dfunk role update is inactive.
The automatic update was last executed ${dfunkUpdateJob.job.lastExecution}.
To toggle this functionality on/off, use the \`/dfunk toggle\` command.`,
flags: MessageFlags.Ephemeral,
});
}
};
123 changes: 123 additions & 0 deletions src/commands/dfunk/subcommands/test/dfunk-test.handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { testCases } from "../../../../tests/dfunk-roles-update/test_cases";
import { executeTestCase } from "../../../../tests/dfunk-roles-update/tests";
import { GuildChatInputCommandInteraction } from "../../../../shared/types/GuildChatInputCommandType";
import {
Role as DiscordRole,
Collection,
GuildMember as DiscordGuildMember,
} from "discord.js";
import {
createDfunkDiscordRoles /*removeDfunkDiscordRoles,*/,
} from "../../../../jobs/update-dfunk-roles";
import * as log from "../../../../shared/utils/log";
export const handleDfunkTest = async (
interaction: GuildChatInputCommandInteraction
): Promise<void> => {
// Create dfunk roles in case these are missing
await createDfunkDiscordRoles(interaction.guild);
const failedData: Map<
number,
{
processedDfunkData: {
currentGroups: Map<string, string[]>;
specialRoles: [
{
roleName: string;
specialRoleLegibles: Set<string>;
}
];
};
dbUsers: Map<string, string>;
discordData: {
guildRoles: Collection<string, DiscordRole>;
guildMembers: Collection<string, DiscordGuildMember>;
};
}
> = new Map();
for (let index = 0; index < testCases.length; index++) {
const testResult = await executeTestCase(
interaction.guild,
"1013769549398671542",
testCases[index],
index + 1
);
if (!testResult.result) {
failedData.set(index + 1, {
processedDfunkData: testResult.processedDfunkData,
dbUsers: testResult.dbUsers,
discordData: testResult.discordData,
});
break;
}
}
log.error("Failed test cases: " + Array.from(failedData.keys()).join(", "));
failedData.forEach(
(
caseData: {
processedDfunkData: {
currentGroups: Map<string, string[]>;
specialRoles: [
{
roleName: string;
specialRoleLegibles: Set<string>;
}
];
};
dbUsers: Map<string, string>;
discordData: {
guildRoles: Collection<string, DiscordRole>;
guildMembers: Collection<string, DiscordGuildMember>;
};
},
caseNumber: number
) => {
log.info("Test case " + caseNumber + ": ");
caseData.processedDfunkData.currentGroups.forEach(
(users: string[], group: string) => {
log.info(
"The group " +
group +
" should have users: " +
users.join(", ")
);
}
);

log.info(
"Users fetched from database: " +
Array.from(caseData.dbUsers.keys()).join(", ")
);
log.info("Fetched Discord Data: ");
log.info(
"Roles fetched:" +
caseData.discordData.guildRoles
.map((role) => role.name)
.join(", ")
);
caseData.discordData.guildRoles.each((role) =>
log.info(
"Users having " +
role.name +
": " +
role.members
.map((member) => member.displayName)
.join(", ")
)
);
log.info(
"Users fetched: " +
caseData.discordData.guildMembers
.map((member) => member.displayName)
.join(", ")
);
caseData.discordData.guildMembers.each((member) =>
log.info(
"(Cached) Roles of user " +
member.displayName +
": " +
member.roles.cache.map((role) => role.name).join(", ")
)
);
}
);
};
28 changes: 28 additions & 0 deletions src/commands/dfunk/subcommands/toggle/dfunk-toggle.handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { GuildChatInputCommandInteraction } from "../../../../shared/types/GuildChatInputCommandType";
import { jobs } from "../../../../index";
import { MessageFlags } from "discord.js";

export const handleDfunkToggle = async (
interaction: GuildChatInputCommandInteraction
): Promise<void> => {
// We assume that this job is loaded
const dfunkUpdateJob = jobs.get("updateDfunkRoles")!;
const jobStatus = dfunkUpdateJob.job.isActive;
if (jobStatus) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const jobStatus = dfunkUpdateJob.job.isActive;
if (jobStatus) {
if (dfunkUpdateJob.job.isActive) {

await dfunkUpdateJob.job.stop();
await interaction.reply({
content: `
The automatic dfunk role update has been turned off.
Use this same command (\`/dfunk toggle\`) to turn on this functionality.`,
flags: MessageFlags.Ephemeral,
});
} else {
await dfunkUpdateJob.job.start();
await interaction.reply({
content: `The automatic dfunk role update has been turned on.
The next automatic update will be executed ${dfunkUpdateJob.job.nextDate()}.
Use this same command (\`/dfunk toggle\`) to turn off this functionality.`,
flags: MessageFlags.Ephemeral,
});
}
};
8 changes: 8 additions & 0 deletions src/commands/dfunk/subcommands/update/dfunk-update.handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { updateDiscordDfunkRoles } from "../../../../jobs/update-dfunk-roles";
import { GuildChatInputCommandInteraction } from "../../../../shared/types/GuildChatInputCommandType";

export const handleDfunkUpdate = async (
interaction: GuildChatInputCommandInteraction
): Promise<void> => {
await updateDiscordDfunkRoles(interaction.guild);
};
6 changes: 5 additions & 1 deletion src/commands/handle-commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
import { handleTranslateMsg } from "./translate/translateMsg.handler";
import { handleClub } from "./club/club.handler";
import { handleMessage } from "./message/message.handler";
import { handleDfunk } from "./dfunk/dfunk.handler";
import { BaseInteraction, MessageFlags, Interaction } from "discord.js";
import { handleKthId } from "./kthid/kthid.handler";
import {
Expand Down Expand Up @@ -166,11 +167,14 @@ const handleChatInputCommand = async (
case CommandNames.MESSAGE:
await handleMessage(guildInteraction);
return;
case CommandNames.DFUNK:
await handleDfunk(guildInteraction);
return;
case CommandNames.KTHID:
await handleKthId(guildInteraction);
return;
case CommandNames.NOLLEGRUPP:
handleNollegrupp(guildInteraction);
await handleNollegrupp(guildInteraction);
return;
case CommandNames.MOTTAGNINGEN:
handleMottagningen(guildInteraction);
Expand Down
Loading