Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
a14bcea
update to discord.js v14
SCDerox Jan 9, 2026
bcf08e6
fixed missing strings
SCDerox Jan 9, 2026
cea21e1
fixed broken info-commands
SCDerox Jan 9, 2026
0095066
fixed duplicated entry
SCDerox Jan 9, 2026
1746bcc
Adds ping-protection module. (#168)
Kevinking500 Jan 26, 2026
de23ed2
Ping Protection V1.1 (#171)
Kevinking500 Feb 18, 2026
acf8bf7
bumped changes
SCDerox Feb 27, 2026
f0f4bc5
feat(economy): implements "Artikel bearbeiten" (#179)
jateute Mar 3, 2026
e72ed64
Added name-list-cleaner AGAIN (#183)
hfgd123 Mar 14, 2026
29addb8
Staff Management System
Mar 16, 2026
22740b7
Staff Management V1, adjusted to what Copilot requested
Mar 16, 2026
d569f1e
Fixed some changes and rewrote botReady to be better
Mar 26, 2026
55d4199
New changes from feedback.
Apr 4, 2026
bc62741
New changes from feedback, and removed many unused locales keys
Apr 5, 2026
217dc78
Some changes
Apr 8, 2026
e85a4b9
Made changes according to feedbacks, bugs and more. Also includes som…
Apr 10, 2026
971cdce
Updated according to feedbacks
Apr 11, 2026
e33fd70
Changed some lines of code according to feedback and self-testing
Apr 12, 2026
6d272e9
Some minor changes
Apr 14, 2026
9f7c41d
Some parameters fixes and adjustments
Apr 14, 2026
d88af1e
Quick config image fix
Apr 14, 2026
d14c9bc
Added deferReply for multiple functions to avoid Discord timeouts in …
Apr 14, 2026
3f0d0c5
Added deferReply to 3 more functions
Apr 14, 2026
6aa556c
Applied fixes
Apr 17, 2026
1e22522
Quick fix regarding defer reply
Apr 17, 2026
ee3d715
synced to closed source version
SCDerox Apr 24, 2026
e3c2af0
synced to closed source version
SCDerox Apr 24, 2026
b6020d7
synced to closed source version
SCDerox Apr 24, 2026
5ef3a73
Some minor locales updates, fixed default mismatches, completely rewr…
Apr 25, 2026
de40197
Small default change in config and fix for activity check CV2 message…
Apr 26, 2026
84f490e
Added staff check to infraction and suspension and updates some configs
Apr 27, 2026
cbe9b3f
Merge branch 'main' into staff-management-system
Kevinking500 Apr 27, 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
28 changes: 14 additions & 14 deletions locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1067,7 +1067,7 @@
"quota-fail": "❌ Quota Not Met",
"duty-time-title": "Shift Time - %type",
"duty-time-desc": "**Total Shifts:** %count\n**Total Duration:** %duration",
"btn-hist": "View History",
"btn-hist": "View Shift History",
"err-no-lb": "ℹ️ No shift data found for **%type**.",
"duty-lb-title": "Leaderboard - %type",
"duty-lb-desc": "**%lookback Top Shifts**\n\n%lines",
Expand All @@ -1084,7 +1084,6 @@
"err-not-on": "❌ You are not on a shift.",
"err-hist-oth": "❌ You can only view your own history.",
"mod-v-all-title": "Confirm: Void All Shifts",
"mod-v-all-lbl": "Type CONFIRM to delete all shift data",
"err-conf-fail": "❌ Data deletion confirmation failed. You must type the phrase exactly.",
"succ-v-all": "All shift data for <@%user> has been deleted successfully.",
"mod-add-t": "Add Duty Time",
Expand All @@ -1099,25 +1098,25 @@
"err-no-perm": "❌ You do not have permission to do this.",
"err-no-mem": "❌ Could not find that member.",
"ph-sel-type": "Select a Shift Type",
"msg-sel-type": "👇 Please choose your shift type:",
"msg-sel-type": "👇 Please choose your shift type below:",
"err-prof-dis": "❌ Staff Profiles are disabled.",
"err-prof-cfg": "❌ Configuration is missing. Please make sure the message is not empty.",
"err-prof-cfg": "❌ Configuration is missing. Please make sure that the message is not empty.",
"err-prof-no-own": "❌ You do not have a staff profile.",
"err-prof-no-tgt": "❌ That user does not have a profile.",
"rev-dis-text": "*Reviews disabled*",
"err-prof-no-tgt": "❌ That user does not have a staff profile.",
"rev-dis-text": "*Reviews are disabled*",
"rev-no-rate": "No ratings yet",
"stat-offl": "⚫ Offline",
"stat-onl": "🟢 Online",
"stat-idl": "🟡 Away",
"stat-dnd": "🔴 Do Not Disturb",
"stat-prof-ond": "⏱️ On duty",
"stat-prof-loa": "🌙 On LoA",
"stat-prof-ra": "⛱️ On RA",
"prof-no-intro": "*No introduction set.*",
"stat-prof-loa": "🌙 On Leave Of Absence (LOA)",
"stat-prof-ra": "⛱️ On Reduced Activity (RA)",
"prof-no-intro": "😕 *This user did not set an introduction.*",
"err-prof-empty": "❌ Profile embed is empty.",
"err-prof-perm": "❌ You must be a staff member to have a profile.",
"prof-edit-title": "Edit Profile",
"prof-edit-nick": "Custom Nickname",
"prof-edit-nick": "Your custom nickname",
"prof-edit-intro": "Introduction",
"succ-prof-wipe": "✅ Profile wiped for %u.",
"succ-prof-upd": "✅ Profile updated!",
Expand All @@ -1138,7 +1137,7 @@
"succ-del-all": "✅ ALL data has been permanently wiped.",
"err-del-time": "⏳ Data deletion timed out.",
"succ-del-tgt": "✅ Target data has been permanently wiped.",
"err-gen-no-perm": "❌ You do not have permission.",
"err-gen-no-perm": "❌ You do not have permission to do this.",
"err-no-req": "❌ Request not found.",
"err-req-hndl": "❌ Request is already %status.",
"mod-deny-req": "Deny Request",
Expand Down Expand Up @@ -1167,8 +1166,8 @@
"log-info-hdr": "%label Information",
"general-start": "Start",
"general-end": "End",
"log-end-title": "%label ended for %username",
"log-end-desc": "%label ended for %mention.",
"log-end-title": "%username's %label has ended.",
"log-end-desc": "%mention's %label has ended.",
"general-started": "Started",
"general-ended": "Ended",
"log-adj-title": "%label adjusted for %username",
Expand Down Expand Up @@ -1434,6 +1433,7 @@
"log-duty-log-fail": "[Staff Management] Failed to log duty change (%action): %error",
"err-self-infract": "That's not in the code... well, it's more of a guideline anyway. Still no.\n-# You cannot infract yourself",
"err-self-promo": "You can't promote yourself through a black hole of audacity and expect it to work.",
"status-expired-auto": "Ended automatically because the status expired."
"status-expired-auto": "Ended automatically because the status expired.",
"label-system": "System"
}
}
2 changes: 1 addition & 1 deletion modules/staff-management-system/commands/duty.js
Original file line number Diff line number Diff line change
Expand Up @@ -1035,7 +1035,7 @@ async function handleDutyAdminVoidAll(client, interaction) {
new ActionRowBuilder().addComponents(
new TextInputBuilder()
.setCustomId('confirm')
.setLabel(localize('staff-management-system', 'mod-v-all-lbl'))
.setLabel(localize('staff-management-system', 'mod-del-lbl'))
.setStyle(TextInputStyle.Short)
.setPlaceholder(confirmPhrase)
.setRequired(true)
Expand Down
12 changes: 6 additions & 6 deletions modules/staff-management-system/commands/staff-status.js
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,7 @@ async function handleStatusEndSubmit(client, interaction, type) {
flags: MessageFlags.Ephemeral
});
}
await interaction.deferUpdate();

const meta = getStatusMeta(type);
const request = await client.models['staff-management-system']['LoaRequest'].findByPk(interaction.customId.split('_')[2]);
Expand Down Expand Up @@ -574,10 +575,9 @@ async function handleStatusEndSubmit(client, interaction, type) {
.setEmoji('📜')
.setStyle(ButtonStyle.Secondary)
);
return interaction.reply({
return interaction.editReply({
embeds: [updatedEmbed.toJSON()],
components: [disabledRow.toJSON()],
flags: MessageFlags.Ephemeral
components: [disabledRow.toJSON()]
});
}

Expand Down Expand Up @@ -662,6 +662,7 @@ async function handleStatusExtendSubmit(client, interaction, type) {
flags: MessageFlags.Ephemeral
});
}
await interaction.deferUpdate();

const meta = getStatusMeta(type);
const request = await client.models['staff-management-system']['LoaRequest'].findByPk(interaction.customId.split('_')[2]);
Expand Down Expand Up @@ -719,10 +720,9 @@ async function handleStatusExtendSubmit(client, interaction, type) {
r: request.reason || localize('staff-management-system', 'info-none')
})
});
return interaction.reply({
return interaction.editReply({
embeds: [updatedEmbed.toJSON()],
components: interaction.message.components.map(c => c.toJSON()),
flags: MessageFlags.Ephemeral
components: interaction.message.components.map(c => c.toJSON())
});
}

Expand Down
39 changes: 35 additions & 4 deletions modules/staff-management-system/configs/activity-checks.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"name": "enableActivityChecks",
"category": "general",
"humanName": "Enable Activity Checks",
"description": "Allows admins to start an activity check to see who is active.",
"description": "Allows admins to start an activity check to see who is active, and also set automatic activity checks.",
"type": "boolean",
"default": true,
"elementToggle": true
Expand Down Expand Up @@ -69,12 +69,43 @@
{
"name": "duration",
"description": "The configured duration in hours."
},
{
"name": "staff-mention",
"description": "Mention of the configured staff role(s)."
},
{
"name": "supervisor-mention",
"description": "Mention of the configured supervisor role(s)."
},
{
"name": "management-mention",
"description": "Mention of the configured management role(s)."
},
{
"name": "initiator",
"description": "The user who iniated the activity check. This will show 'system' if it was an automated check."
}
],
"default": {
"title": "📋 Staff Activity Check",
"description": "Please click the button below to confirm your activity before %endtime%.",
"color": "#3498db"
"_schema": "v3",
"content": "%staff-mention%",
"embeds": [
{
"author": {
"name": "Signed, %initiator%"
},
"title": "📋 Staff Activity Check",
"description": "Please confirm your activity by clicking the button below before %end-time%. This activity check will stay open for %duration% hour(s), and members who do not respond before it ends may be marked as failed unless they qualify for an exception.",
"fields": [
{
"name": "Quick info overview",
"value": "Ends at: %end-time%\nDuration: %duration% hour(s)"
}
],
"color": "#3498db"
}
]
}
},
{
Expand Down
2 changes: 1 addition & 1 deletion modules/staff-management-system/configs/configuration.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"name": "supervisorRoles",
"category": "roles",
"humanName": "Supervisor Roles",
"description": "Roles that can manage other staff members (Approve/Deny/Manage LoA's and RA's, Manage Shifts, promote and infract users).",
"description": "Roles that can manage other staff members (Approve/Deny/Manage LoA's and RA's, Manage Shifts etc.).",
"type": "array",
"content": "roleID",
"default": []
Expand Down
26 changes: 13 additions & 13 deletions modules/staff-management-system/configs/infractions.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,23 @@
"Under Investigation"
]
},
{
"name": "infractionLogChannel",
"category": "messages",
"humanName": "Infraction Log Channel",
"description": "Where should infractions and suspensions be announced?",
"type": "channelID",
"channelTypes": [
"GUILD_TEXT",
"GUILD_NEWS"
],
"default": ""
},
{
"name": "enableSuspensions",
"category": "suspensions",
"humanName": "Enable Suspensions System",
"description": "Suspensions temporarily strip a staff member of their roles.",
"description": "Suspensions temporarily strip a staff member of their roles, and give them back after the specified duration.",
"type": "boolean",
"default": true
},
Expand Down Expand Up @@ -137,18 +149,6 @@
]
}
},
{
"name": "infractionLogChannel",
"category": "messages",
"humanName": "Infraction Log Channel",
"description": "Where should infractions and suspensions be announced?",
"type": "channelID",
"channelTypes": [
"GUILD_TEXT",
"GUILD_NEWS"
],
"default": ""
},
{
"name": "infractionMessage",
"category": "messages",
Expand Down
4 changes: 2 additions & 2 deletions modules/staff-management-system/configs/promotions.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"name": "enablePromotions",
"category": "logic",
"humanName": "Enable Promotions System",
"description": "If disabled, the /staff-management promote command will not work.",
"description": "Enabling this allows staff members to promote users to higher ranks.",
"type": "boolean",
"default": true,
"elementToggle": true
Expand All @@ -30,7 +30,7 @@
"humanName": "Auto-Add New Role?",
"description": "If enabled, the bot will automatically give the user the new rank role. Note: This makes your server prone to raids by promoting someone to a role with more dangerous permissions which can be used to do malicious actions. It is recommended to keep this setting disabled.",
"type": "boolean",
"default": true
"default": false
},
{
"name": "promotionsChannel",
Expand Down
8 changes: 4 additions & 4 deletions modules/staff-management-system/configs/reviews.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"name": "enableReviews",
"category": "settings",
"humanName": "Enable Reviews System",
"description": "Enabling this unlocks the staff review system, allowing users to submit ratings and feedback for staff members.",
"description": "Enabling this unlocks the staff review system, allowing users to submit ratings with feedback for staff members.",
"type": "boolean",
"default": true
},
Expand All @@ -39,15 +39,15 @@
"name": "allowSelfRating",
"category": "settings",
"humanName": "Allow Self-Rating?",
"description": "If enabled, staff can review themselves. This is not recommended to keep a fair ratings system.",
"description": "If enabled, staff can review themselves. This is not recommended to keep a fair review system.",
"type": "boolean",
"default": false
},
{
"name": "onlyAllowStaffReview",
"category": "settings",
"humanName": "Only let users review staff",
"description": "If enabled, only staff members can review other staff members.",
"description": "If enabled, users can only review staff members.",
"type": "boolean",
"default": true
},
Expand Down Expand Up @@ -92,7 +92,7 @@
],
"default": {
"_schema": "v3",
"content": "%staff%",
"content": "%staff-mention%",
"embeds": [
{
"title": "🌟 New Staff Rating",
Expand Down
56 changes: 41 additions & 15 deletions modules/staff-management-system/staff-management.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@ async function issueInfraction(client, interaction, targetMember, type, reason,
});
}

const canInfract = checkStaffPermissions(interaction.member, config, 'staff');
if (!canInfract) return interaction.editReply({
content: localize('staff-management-system', 'err-gen-no-perm')
});

if (type.toLowerCase() === 'suspension') {
return interaction.editReply({
content: localize('staff-management-system', 'err-use-susp')
Expand Down Expand Up @@ -250,6 +255,11 @@ async function issueSuspension(client, interaction, targetMember, durationInput,
});
}

const canSuspend = checkStaffPermissions(interaction.member, config, 'staff');
if (!canSuspend) return interaction.editReply({
content: localize('staff-management-system', 'err-gen-no-perm')
});

const durationDays = parseDurationToDays(durationInput);
if (!durationDays)
return interaction.editReply({
Expand Down Expand Up @@ -1391,27 +1401,43 @@ async function startActivityCheck(client, interactionOrChannel, isAutomated = fa

const durationHours = config.timeframe || 24;
const endTime = new Date(Date.now() + durationHours * 60 * 60 * 1000);
const generalConfig = getConfig(client, 'configuration') || {};

let embedTemplate = typeof config.checkMessage === 'string'
? JSON.parse(config.checkMessage)
: config.checkMessage;
let msgOpts = await embedTypeV2(embedTemplate, {
'%end-time%': `<t:${Math.floor(endTime.getTime() / 1000)}:F>`,
'%duration%': durationHours.toString()
});
const formatRoleMentions = (roles) => {
const roleIds = Array.isArray(roles)
? roles
: (roles ? [roles] : []);

if (msgOpts?.content?.trim() === '') delete msgOpts.content;
msgOpts.components = [
new ActionRowBuilder()
.addComponents(
new ButtonBuilder()
return roleIds.map(roleId => `<@&${roleId}>`).join(' ');
};
const initiator = isAutomated
? localize('staff-management-system', 'label-system')
: interactionOrChannel.user.toString();

const responseButtonRow = new ActionRowBuilder()
.addComponents(
new ButtonBuilder()
.setCustomId('staff-mgmt_ac-respond')
.setLabel(localize('staff-management-system', 'ac-confirm-btn'))
.setStyle(ButtonStyle.Success)
.setEmoji('✅')
)
.toJSON()
];
)
.toJSON();

let msgOpts = await embedTypeV2(embedTemplate, {
'%end-time%': `<t:${Math.floor(endTime.getTime() / 1000)}:F>`,
'%duration%': durationHours.toString(),
'%staff-mention%': formatRoleMentions(generalConfig.staffRoles),
'%supervisor-mention%': formatRoleMentions(generalConfig.supervisorRoles),
'%management-mention%': formatRoleMentions(generalConfig.managementRoles),
'%initiator%': initiator
},
{
components: [responseButtonRow]
}
);

if (msgOpts?.content?.trim() === '') delete msgOpts.content;

try {
const checkMessage = await targetChannel.send(msgOpts);
Expand Down
Loading