Add status role menu+heartbeat+impr CI+logging
voidbot Production Dockerization / build (push) Successful in 53s Details

This commit is contained in:
Skylar Grant 2023-08-12 22:10:05 -04:00
parent 5600af9e58
commit 6fb2a3f4e0
6 changed files with 77 additions and 23 deletions

View File

@ -1,7 +1,12 @@
name: Voidbot Dockerization
name: voidbot Production Dockerization
on:
workflow_dispatch:
push:
branches:
- main
merge:
branches:
- main
env:
DHUB_UNAME: ${{ secrets.DHUB_UNAME }}
@ -11,19 +16,21 @@ jobs:
build:
runs-on: ubuntu-latest
runs-on: self-hosted
steps:
- uses: actions/checkout@v3
- name: Pull latest from Git
run: |
cd /root/voidbot
git pull
git checkout $GITHUB_HEAD_REF
- name: Build the Docker image
run: docker build . --file Dockerfile --tag v0idf1sh/voidbot
run: |
cd /root/voidbot
docker build . --file Dockerfile --tag v0idf1sh/voidbot
- name: Log into Docker Hub
run: docker login -u $DHUB_UNAME -p $DHUB_PWORD
- name: Push image to Docker Hub
run: docker push v0idf1sh/voidbot
- name: Set up a skeleton .env file
run: echo "TOKEN=${{secrets.TOKEN}}" > .env && echo "BOTID=${{ secrets.BOTID }}" >> .env
- name: Install modules
run: npm i
- name: Refresh commands with Discord
run: node modules/_deploy-global.js
run: |
cd /root/voidbot
docker push v0idf1sh/voidbot

View File

@ -1,8 +1,8 @@
FROM node:16
FROM node:18
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY package.json ./
RUN npm install
COPY . .
CMD [ "node", "main.js" ]
CMD ["/bin/sh", "-c", "node main.js 2> /logs/$(date +%Y-%m-%d_%H-%M-%S)-error.txt 1> /logs/$(date +%Y-%m-%d_%H-%M-%S)-status.txt"]

View File

@ -11,7 +11,7 @@
"rules": "1. Show respect\n2. No politics\n3. No spam or self-promotion (server invites, advertisements, etc) without permission from a staff member. This includes DMing fellow members.\n4. No age-restricted or obscene content. This includes text, images, or links featuring nudity, sex, hard violence, or other graphically disturbing content.\n5. If you see something against the rules or something that makes you feel unsafe, let staff know. We want this server to be a welcoming space!",
"rulesFooter": "Use the Accept Rules button to gain access to the rest of the server.",
"roleMenuTitle": "Role Menu",
"treeRoleMenu": "Use the buttons below to give yourself roles.\n\n``💧`` - <@&1069416740389404763>: Get notifications when the tree is ready to be watered.\n``🍎`` - <@&1073698485376921602>: Get notifications when fruit is falling from the tree.",
"roleMenuDesc": "Use the buttons below to give yourself roles.\n\n``💧`` - <@&1069416740389404763>: Get notifications when the tree is ready to be watered.\n``🍎`` - <@&1073698485376921602>: Get notifications when fruit is falling from the tree.\n``📟`` - <@&1140098947306750073>: Get notifications when Silvanus or Silvanus FE are down and for scheduled maintenance.",
"roleMenuFooter": "Tip: Tap the button again to remove the role."
},
"emoji": {
@ -20,11 +20,13 @@
"confirm": "☑️",
"cancel": "❌",
"water": "💧",
"fruit": "🍎"
"fruit": "🍎",
"status": "📟"
},
"roleIds": {
"member": "1048328885118435368",
"waterPings": "1069416740389404763",
"fruitPings": "1073698485376921602"
"fruitPings": "1073698485376921602",
"statusPings": "1140098947306750073"
}
}

15
main.js
View File

@ -4,6 +4,8 @@
const dotenv = require('dotenv');
dotenv.config();
const token = process.env.TOKEN;
const heartbeatUrl = process.env.HEARTBEAT_URL;
const sendHeartbeat = typeof heartbeatUrl === 'string';
// Discord.JS
const { Client, GatewayIntentBits } = require('discord.js');
@ -28,6 +30,14 @@ client.once('ready', () => {
}).catch(err => {
console.error("Error sending status message: " + err);
});
// Heartbeat Timer
if (sendHeartbeat) {
setInterval(() => {
fn.sendHeartbeat(heartbeatUrl);
}, 30000);
if (isDev) console.log("Heartbeat interval set.");
}
});
// slash-commands
@ -58,6 +68,11 @@ client.on('interactionCreate', async interaction => {
console.error("Error handling fruit ping button: " + err);
});
break;
case 'statuspingrole':
await fn.buttonHandlers.statusPing(interaction).catch(err => {
console.error("Error handling status ping button: " + err);
});
break;
default:
break;
}

View File

@ -6,6 +6,7 @@ const isDev = process.env.isDev;
// filesystem
const fs = require('fs');
const https = require('https');
// Discord.js
const Discord = require('discord.js');
@ -41,11 +42,12 @@ const functions = {
this.buttons.acceptRules()
);
},
treeRoleMenu() {
roleMenu() {
return new ActionRowBuilder()
.addComponents(
this.buttons.waterPing(),
this.buttons.fruitPing()
this.buttons.fruitPing(),
this.buttons.statusPing()
);
},
buttons: {
@ -66,6 +68,12 @@ const functions = {
.setCustomId('fruitpingrole')
.setLabel(strings.emoji.fruit)
.setStyle(ButtonStyle.Primary);
},
statusPing() {
return new ButtonBuilder()
.setCustomId('statuspingrole')
.setLabel(strings.emoji.status)
.setStyle(ButtonStyle.Primary);
}
}
},
@ -107,12 +115,12 @@ const functions = {
.setFooter({ text: strings.embeds.rulesFooter });
return { embeds: [embed], components: [actionRow] };
},
treeRoleMenu() {
const actionRow = functions.builders.actionRows.treeRoleMenu();
roleMenu() {
const actionRow = functions.builders.actionRows.roleMenu();
const embed = new EmbedBuilder()
.setColor(strings.embeds.color)
.setTitle(strings.embeds.roleMenuTitle)
.setDescription(strings.embeds.treeRoleMenu)
.setDescription(strings.embeds.roleMenuDesc)
.setFooter({ text: strings.embeds.roleMenuFooter });
return { embeds: [embed], components: [actionRow] };
}
@ -148,11 +156,33 @@ const functions = {
}
await interaction.reply(functions.builders.embeds.info("Roles updated!")).catch(err => console.error(err));
},
async statusPing(interaction) {
const role = await functions.roles.fetchRole(interaction.guild, strings.roleIds.statusPings);
if (interaction.member.roles.cache.some(role => role.id == strings.roleIds.statusPings)) {
functions.roles.takeRole(interaction.member, role);
} else {
functions.roles.giveRole(interaction.member, role);
}
await interaction.reply(functions.builders.embeds.info("Roles updated!")).catch(err => console.error(err));
},
async acceptRules(interaction) {
const role = await functions.roles.fetchRole(interaction.guild, strings.roleIds.member);
functions.roles.giveRole(interaction.member, role).catch(err => console.error(err));
await interaction.reply(functions.builders.embeds.info("Roles updated!")).catch(err => console.error(err));
}
},
async sendHeartbeat(url) {
if (isDev) console.log("Heartbeat Sent: " + url);
https.get(url, async (response) => {
let data = '';
response.on('data', (chunk) => data += chunk);
response.on('end', () => {
parsedData = JSON.parse(data);
if ( !(parsedData.ok) ) console.error("Heartbeat failed");
});
}).on("error", (error) => console.error(error));
}
};

View File

@ -7,6 +7,6 @@ module.exports = {
.setDescription('Send the role selection menu in the current channel'),
async execute(interaction) {
await interaction.deferReply().catch(err => console.error(err));
await interaction.editReply(fn.builders.embeds.treeRoleMenu()).catch(err => console.error(err));
await interaction.editReply(fn.builders.embeds.roleMenu()).catch(err => console.error(err));
},
};