mirror of
https://github.com/logos-storage/discord-bot.git
synced 2026-01-02 13:13:08 +00:00
adding inactive vs active roles and discord id mapping through supabase
This commit is contained in:
parent
1d1aa38913
commit
471fa1a429
358
index.js
358
index.js
@ -19,17 +19,24 @@ const supabase = createClient(
|
||||
|
||||
// Command registration
|
||||
const commands = [
|
||||
new SlashCommandBuilder()
|
||||
.setName('node')
|
||||
.setDescription('Verify your node and get the ALTRUISTIC MODE role')
|
||||
.addStringOption(option =>
|
||||
option
|
||||
.setName('nodeid')
|
||||
.setDescription('Your Node ID')
|
||||
.setRequired(true)
|
||||
)
|
||||
.setDefaultMemberPermissions('0') // Make command private
|
||||
.setDMPermission(false), // Disable DM usage
|
||||
{
|
||||
name: 'node',
|
||||
description: 'Verify your node and get roles',
|
||||
options: [{
|
||||
name: 'nodeid',
|
||||
description: 'Your Node ID',
|
||||
type: 3, // STRING type
|
||||
required: true
|
||||
}],
|
||||
default_member_permissions: null, // Allow everyone to use the command
|
||||
dm_permission: false
|
||||
},
|
||||
{
|
||||
name: 'checkroles',
|
||||
description: 'Check if your node is still active',
|
||||
default_member_permissions: null, // Allow everyone to use the command
|
||||
dm_permission: false
|
||||
}
|
||||
];
|
||||
|
||||
// Register commands when bot starts
|
||||
@ -40,94 +47,375 @@ client.once('ready', async () => {
|
||||
|
||||
// Register commands for the first guild the bot is in
|
||||
const guild = client.guilds.cache.first();
|
||||
if (guild) {
|
||||
await rest.put(
|
||||
if (!guild) {
|
||||
console.error('No guild found!');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`Registering commands for guild: ${guild.name} (${guild.id})`);
|
||||
|
||||
try {
|
||||
// Delete existing commands first
|
||||
console.log('Deleting existing commands...');
|
||||
|
||||
// Delete guild commands
|
||||
await rest.put(Routes.applicationGuildCommands(client.user.id, guild.id), { body: [] });
|
||||
console.log('Successfully deleted existing commands.');
|
||||
|
||||
// Register new commands
|
||||
console.log('Registering new commands...');
|
||||
const data = await rest.put(
|
||||
Routes.applicationGuildCommands(client.user.id, guild.id),
|
||||
{ body: commands },
|
||||
{ body: commands }
|
||||
);
|
||||
console.log(`Bot is ready as ${client.user.tag} in guild ${guild.name}!`);
|
||||
|
||||
console.log(`Successfully registered ${data.length} commands!`);
|
||||
|
||||
// Start the role check interval
|
||||
setInterval(() => checkInactiveNodes(guild), 24 * 60 * 60 * 1000);
|
||||
} catch (error) {
|
||||
console.error('Error managing commands:', error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
console.error('Error in ready event:', error);
|
||||
}
|
||||
});
|
||||
|
||||
// Function to check and remove roles from inactive nodes
|
||||
async function checkInactiveNodes(guild, specificMember = null) {
|
||||
try {
|
||||
console.log('Checking for inactive nodes...');
|
||||
// Get both roles
|
||||
const activeRole = guild.roles.cache.find(r => r.name === 'Active Participant');
|
||||
const inactiveRole = guild.roles.cache.find(r => r.name === 'Inactive Participant');
|
||||
|
||||
if (!activeRole) {
|
||||
console.error('Active Participant role not found');
|
||||
return false;
|
||||
}
|
||||
if (!inactiveRole) {
|
||||
console.error('Inactive Participant role not found');
|
||||
return false;
|
||||
}
|
||||
|
||||
// If checking a specific member
|
||||
if (specificMember) {
|
||||
console.log(`Checking status for member: ${specificMember.user.tag} (${specificMember.user.id})`);
|
||||
|
||||
// Get the most recent node record for this specific Discord user
|
||||
const { data: nodeRecords, error } = await supabase
|
||||
.from('node_records')
|
||||
.select('*')
|
||||
.eq('discord_user_id', specificMember.user.id)
|
||||
.order('timestamp', { ascending: false })
|
||||
.limit(1);
|
||||
|
||||
if (error) {
|
||||
console.error('Error checking node records:', error);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get one week ago timestamp
|
||||
const oneWeekAgo = new Date();
|
||||
oneWeekAgo.setDate(oneWeekAgo.getDate() - 7);
|
||||
|
||||
// Check if node is inactive
|
||||
const isInactive = !nodeRecords.length || new Date(nodeRecords[0].timestamp) < oneWeekAgo;
|
||||
console.log(`Node status - Records exist: ${nodeRecords.length > 0}, Last timestamp: ${nodeRecords.length ? new Date(nodeRecords[0].timestamp).toISOString() : 'none'}, Is inactive: ${isInactive}`);
|
||||
|
||||
if (isInactive) {
|
||||
// Remove Active role and add Inactive role
|
||||
if (specificMember.roles.cache.has(activeRole.id)) {
|
||||
await specificMember.roles.remove(activeRole);
|
||||
await specificMember.roles.add(inactiveRole);
|
||||
console.log(`Changed ${specificMember.user.tag} to inactive status`);
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
// Add Active role and remove Inactive role if needed
|
||||
if (specificMember.roles.cache.has(inactiveRole.id)) {
|
||||
await specificMember.roles.remove(inactiveRole);
|
||||
await specificMember.roles.add(activeRole);
|
||||
console.log(`Changed ${specificMember.user.tag} to active status`);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// If checking all members
|
||||
const membersWithRole = guild.members.cache.filter(member =>
|
||||
member.roles.cache.has(activeRole.id)
|
||||
);
|
||||
|
||||
const oneWeekAgo = new Date();
|
||||
oneWeekAgo.setDate(oneWeekAgo.getDate() - 7);
|
||||
|
||||
for (const [_, member] of membersWithRole) {
|
||||
const { data: nodeRecords, error } = await supabase
|
||||
.from('node_records')
|
||||
.select('*')
|
||||
.eq('discord_user_id', member.user.id)
|
||||
.order('timestamp', { ascending: false })
|
||||
.limit(1);
|
||||
|
||||
if (error) {
|
||||
console.error('Error checking node records:', error);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!nodeRecords.length || new Date(nodeRecords[0].timestamp) < oneWeekAgo) {
|
||||
try {
|
||||
await member.roles.remove(activeRole);
|
||||
await member.roles.add(inactiveRole);
|
||||
console.log(`Changed ${member.user.tag} to inactive status due to inactivity`);
|
||||
} catch (error) {
|
||||
console.error(`Error updating roles for ${member.user.tag}:`, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error in checkInactiveNodes:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle slash commands
|
||||
client.on('interactionCreate', async interaction => {
|
||||
if (!interaction.isChatInputCommand()) return;
|
||||
if (interaction.commandName !== 'node') return;
|
||||
|
||||
if (interaction.commandName === 'node') {
|
||||
try {
|
||||
// Initial reply is ephemeral (only visible to the command user)
|
||||
await interaction.deferReply({ ephemeral: true });
|
||||
|
||||
// Check bot permissions first
|
||||
if (!interaction.guild.members.me.permissions.has('ManageRoles')) {
|
||||
await interaction.editReply({
|
||||
content: '❌ Bot is missing permissions. Please give the bot "Manage Roles" permission and make sure its role is above the "Altruistic Mode" role.',
|
||||
content: '❌ Bot is missing permissions. Please give the bot "Manage Roles" permission and make sure its role is above the roles.',
|
||||
ephemeral: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const nodeId = interaction.options.getString('nodeid');
|
||||
console.log(`Processing verification for user: ${interaction.user.tag}`);
|
||||
|
||||
// Check database for node
|
||||
const { data: node } = await supabase
|
||||
// First, check if this Discord user already has a node
|
||||
const { data: existingUserNodes, error: userCheckError } = await supabase
|
||||
.from('node_records')
|
||||
.select('node_id')
|
||||
.eq('discord_user_id', interaction.user.id)
|
||||
.limit(1);
|
||||
|
||||
if (userCheckError) {
|
||||
console.error('Error checking existing user nodes:', userCheckError);
|
||||
await interaction.editReply({
|
||||
content: '❌ Error checking user status.',
|
||||
ephemeral: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (existingUserNodes && existingUserNodes.length > 0) {
|
||||
await interaction.editReply({
|
||||
content: '❌ You already have a node associated with your Discord account. Please contact the moderators if you need to change your node association.',
|
||||
ephemeral: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Then, check if the node is already associated with another Discord user
|
||||
const { data: existingNodeUser, error: nodeCheckError } = await supabase
|
||||
.from('node_records')
|
||||
.select('discord_user_id')
|
||||
.eq('node_id', nodeId)
|
||||
.not('discord_user_id', 'is', null)
|
||||
.limit(1);
|
||||
|
||||
if (nodeCheckError) {
|
||||
console.error('Error checking node association:', nodeCheckError);
|
||||
await interaction.editReply({
|
||||
content: '❌ Error checking node status.',
|
||||
ephemeral: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (existingNodeUser && existingNodeUser.length > 0) {
|
||||
await interaction.editReply({
|
||||
content: '❌ This node is already associated with another Discord user. Please contact the moderators if you believe this is an error.',
|
||||
ephemeral: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Now check if the node exists and is active (within last 24 hours)
|
||||
const { data: existingNode, error: findError } = await supabase
|
||||
.from('node_records')
|
||||
.select('*')
|
||||
.eq('node_id', nodeId)
|
||||
.single();
|
||||
.order('timestamp', { ascending: false })
|
||||
.limit(1);
|
||||
|
||||
if (!node) {
|
||||
if (findError) {
|
||||
console.error('Error finding node:', findError);
|
||||
await interaction.editReply({
|
||||
content: '❌ No node found with this ID.',
|
||||
content: '❌ Error checking node status.',
|
||||
ephemeral: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Get and assign role
|
||||
const role = interaction.guild.roles.cache.find(r => r.name === 'Altruistic Mode');
|
||||
if (!role) {
|
||||
if (!existingNode || existingNode.length === 0) {
|
||||
console.log('Node verification failed for user:', interaction.user.tag);
|
||||
await interaction.editReply({
|
||||
content: '❌ Could not find the "Altruistic Mode" role.',
|
||||
content: '❌ No node found with this ID. However, the bot only works for nodes setup using the [Codex CLI](https://github.com/codex-storage/cli) and does not work on manual installation of Codex as we do not log node information from the manual process.',
|
||||
ephemeral: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if bot's role is higher than the role it's trying to assign
|
||||
if (interaction.guild.members.me.roles.highest.position <= role.position) {
|
||||
// Check if node is active (last update within 24 hours)
|
||||
const oneDayAgo = new Date();
|
||||
oneDayAgo.setDate(oneDayAgo.getDate() - 1);
|
||||
|
||||
if (new Date(existingNode[0].timestamp) < oneDayAgo) {
|
||||
await interaction.editReply({
|
||||
content: '❌ Bot\'s role must be higher than the "Altruistic Mode" role in the server settings.',
|
||||
content: '❌ This node has not been active in the last 24 hours. Please make sure your node is running and try again.',
|
||||
ephemeral: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to add the role
|
||||
// Get all roles first
|
||||
const altruisticRole = interaction.guild.roles.cache.find(r => r.name === 'Altruistic Mode');
|
||||
const activeRole = interaction.guild.roles.cache.find(r => r.name === 'Active Participant');
|
||||
const inactiveRole = interaction.guild.roles.cache.find(r => r.name === 'Inactive Participant');
|
||||
|
||||
if (!altruisticRole || !activeRole || !inactiveRole) {
|
||||
await interaction.editReply({
|
||||
content: '❌ Could not find one or more required roles.',
|
||||
ephemeral: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Check bot permissions
|
||||
if (!interaction.guild.members.me.permissions.has('ManageRoles')) {
|
||||
await interaction.editReply({
|
||||
content: '❌ Bot is missing "Manage Roles" permission.',
|
||||
ephemeral: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if bot's role is higher than the roles it needs to assign
|
||||
const botRole = interaction.guild.members.me.roles.highest;
|
||||
if (botRole.position <= altruisticRole.position ||
|
||||
botRole.position <= activeRole.position ||
|
||||
botRole.position <= inactiveRole.position) {
|
||||
await interaction.editReply({
|
||||
content: '❌ Bot\'s role must be higher than the roles it needs to assign. Please move the bot\'s role up in the server settings.',
|
||||
ephemeral: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Now update the discord_user_id
|
||||
console.log(`Attempting to update discord_user_id for node ${nodeId} to ${interaction.user.id}`);
|
||||
|
||||
const { error: updateError } = await supabase
|
||||
.from('node_records')
|
||||
.update({ discord_user_id: interaction.user.id })
|
||||
.eq('node_id', nodeId)
|
||||
.eq('timestamp', existingNode[0].timestamp);
|
||||
|
||||
if (updateError) {
|
||||
console.error('Error updating node:', updateError);
|
||||
await interaction.editReply({
|
||||
content: '❌ Error updating node information.',
|
||||
ephemeral: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`Successfully updated discord_user_id for node ${nodeId}`);
|
||||
|
||||
// Add Altruistic and Active roles, remove Inactive role
|
||||
try {
|
||||
await interaction.member.roles.add(role);
|
||||
await interaction.member.roles.add([altruisticRole, activeRole]);
|
||||
if (interaction.member.roles.cache.has(inactiveRole.id)) {
|
||||
await interaction.member.roles.remove(inactiveRole);
|
||||
}
|
||||
console.log('Roles updated successfully for user:', interaction.user.tag);
|
||||
|
||||
// Send private success message to user
|
||||
await interaction.editReply({
|
||||
content: '✅ Role granted successfully!',
|
||||
content: '✅ Your node has been verified and roles have been granted!',
|
||||
ephemeral: true
|
||||
});
|
||||
|
||||
} catch (roleError) {
|
||||
console.error('Role assignment error:', roleError);
|
||||
await interaction.editReply({
|
||||
content: '❌ Failed to assign role. Please check bot permissions.',
|
||||
content: '❌ Failed to update roles. The bot\'s role must be higher than the roles it needs to assign.',
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
try {
|
||||
if (!interaction.replied && !interaction.deferred) {
|
||||
await interaction.reply({
|
||||
content: '❌ An error occurred.',
|
||||
ephemeral: true
|
||||
});
|
||||
} else {
|
||||
await interaction.editReply({
|
||||
content: '❌ An error occurred.',
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
} catch (replyError) {
|
||||
console.error('Error sending error message:', replyError);
|
||||
}
|
||||
}
|
||||
} else if (interaction.commandName === 'checkroles') {
|
||||
try {
|
||||
await interaction.deferReply({ ephemeral: true });
|
||||
|
||||
const isActive = await checkInactiveNodes(interaction.guild, interaction.member);
|
||||
|
||||
if (isActive) {
|
||||
await interaction.editReply({
|
||||
content: '✅ Your node is active and roles are up to date.',
|
||||
ephemeral: true
|
||||
});
|
||||
} else {
|
||||
await interaction.editReply({
|
||||
content: '❌ No node found with this ID. However, the bot only works for nodes setup using the [Codex CLI](https://github.com/codex-storage/cli) and does not work on manual installation of Codex as we do not log node information from the manual process.',
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error in role check:', error);
|
||||
try {
|
||||
if (!interaction.replied && !interaction.deferred) {
|
||||
await interaction.reply({
|
||||
content: '❌ An error occurred.',
|
||||
ephemeral: true
|
||||
});
|
||||
} else {
|
||||
await interaction.editReply({
|
||||
content: '❌ An error occurred.',
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
} catch (replyError) {
|
||||
console.error('Error sending error message:', replyError);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
client.login(process.env.DISCORD_BOT_TOKEN);
|
||||
Loading…
x
Reference in New Issue
Block a user