diff --git a/README.md b/README.md index 837232c..72a53c3 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,11 @@ -# Toho Miku +![miku-banner](https://github.com/JanGross/toho-miku/assets/13641301/70ae153f-5e1d-4f49-9793-659ac3631403) + [![](https://dcbadge.vercel.app/api/server/uWFpsYnbPX)](https://discord.gg/uWFpsYnbPX) [![Support the project on Patreon](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fshieldsio-patreon.vercel.app%2Fapi%3Fusername%3Dtoho_miku%26type%3Dpatrons&style=for-the-badge)](https://patreon.com/toho_miku) Part of this project are - [Toho-Mon](https://github.com/JanGross/toho-mon) Bot status monitoring with webhook alerts -- [Toho-Reno](https://github.com/JanGross/toho-reno) Headless render node -- [Job-Server](https://github.com/JanGross/job-server) Jobserver managing render jobs +- [Toho-Reno](https://github.com/JanGross/toho-reno) Godot render node +- [Toho-Jose](https://github.com/JanGross/toho-jose) Jobserver managing render jobs ### Run dev container diff --git a/commands/missing.js b/commands/missing.js new file mode 100644 index 0000000..b73629b --- /dev/null +++ b/commands/missing.js @@ -0,0 +1,110 @@ +const { SlashCommandBuilder, AttachmentBuilder, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, ComponentType } = require("discord.js"); +const { Card, User, Group, Character, Badge } = require("../models"); +const { Rendering, UserUtils } = require("../util"); +const { QUALITY_NAMES } = require("../config/constants"); +const Sequelize = require("sequelize"); +const fs = require("fs"); +const edit = require("./edit"); + +//fetch all cards owned by the user and list them +module.exports = { + data: new SlashCommandBuilder() + .setName("missing") + .setDescription("View missing things") + .addStringOption((option) => + option + .setName("group") + .setDescription("Thing identifier") + .setRequired(false) + .setAutocomplete(true) + ), + permissionLevel: 0, + async execute(interaction) { + await interaction.deferReply(); + + let groupId = interaction.options.getString("group"); + let user = await UserUtils.getUserByDiscordId(interaction.member.user.id); + + let embed = new EmbedBuilder() + .setTitle(`Missing cards`); + let description = ""; + + if (groupId) { + try { + let missing = await this.FindMissingFromGroup(user.id, groupId); + missing.map((character) => { + description += `[${character.id}] ${character.name}\n`; + }); + } catch (error) { + console.error('Error:', error); + throw error; + } + + } else { + let missingCounts = await this.CountMissingFromGroup(user.id); + missingCounts.sort(({missingCount:a}, {missingCount:b}) => b-a); + missingCounts.map((group) => { + if (group.missingCount > 0) { + description += `${group.name}: ${group.missingCount}\n`; + } + }); + } + + embed.setDescription(description); + await interaction.editReply({ embeds: [embed] }); + return; + }, + async CountMissingFromGroup(userId) { + try { + const groups = await Group.findAll({ + where: { enabled: 1 } + }); + + const missingCountByGroup = await Promise.all( + groups.map(async (group) => { + const characters = await Character.findAll({ + where: { groupId: group.id, enabled: 1 }, + include: [ + { + model: Card, + where: { userId: userId }, + required: false, + }, + ], + }); + + const missingCount = characters.reduce((total, character) => { + return total + (character.Cards.length === 0 ? 1 : 0); + }, 0); + + return { + id: group.id, + name: group.name, + missingCount: missingCount, + }; + }) + ); + + return missingCountByGroup; + } catch (error) { + console.error('Error:', error); + throw error; + } + }, + async FindMissingFromGroup(userId, groupId) { + const missingCards = await Character.findAll({ + attributes: ['groupId', 'id', 'name'], + include: [{ + model: Card, + attributes: [], + required: false, + where: { userId: userId, burned: 0 }, + }], + where: { groupId: groupId }, + having: Sequelize.literal('COUNT(Cards.id) = 0'), + group: ['Character.id'], + }); + + return missingCards; + } +} \ No newline at end of file diff --git a/events/autocompleteRequest.js b/events/autocompleteRequest.js index 8c4b4e8..abd729e 100644 --- a/events/autocompleteRequest.js +++ b/events/autocompleteRequest.js @@ -40,6 +40,12 @@ module.exports = { } } + if (interaction.commandName === 'missing') { + + choices = (await SearchUtils.findByName(Group, focusedOption.value))["choices"]; + + } + if (interaction.commandName === 'wishlist') { choices = (await SearchUtils.findByName(Character, focusedOption.value))["choices"]; } diff --git a/models/character.js b/models/character.js index e2dbb58..0507a23 100644 --- a/models/character.js +++ b/models/character.js @@ -13,6 +13,7 @@ module.exports = (sequelize, DataTypes) => { Character.belongsTo(models.Group, { foreignKey: 'groupId', }); // A character can belong to many badges Character.belongsToMany(models.Badge, { through: 'BadgeCharacter' }); + Character.hasMany(models.Card, { foreignKey: 'characterId' }); } } Character.init({ diff --git a/package-lock.json b/package-lock.json index c639a5c..337eb6e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -707,9 +707,9 @@ } }, "node_modules/dottie": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.3.tgz", - "integrity": "sha512-4liA0PuRkZWQFQjwBypdxPfZaRWiv5tkhMXY2hzsa2pNf5s7U3m9cwUchfNKe8wZQxdGPQQzO6Rm2uGe0rvohQ==" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.4.tgz", + "integrity": "sha512-iz64WUOmp/ECQhWMJjTWFzJN/wQ7RJ5v/a6A2OiCwjaGCpNo66WGIjlSf+IULO9DQd0b4cFawLOTbiKSrpKodw==" }, "node_modules/editorconfig": { "version": "0.15.3", @@ -1655,9 +1655,9 @@ } }, "node_modules/node-abi/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -2029,9 +2029,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "bin": { "semver": "bin/semver" } @@ -2189,9 +2189,9 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/sequelize/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -2244,9 +2244,9 @@ } }, "node_modules/sharp/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -3292,9 +3292,9 @@ "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==" }, "dottie": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.3.tgz", - "integrity": "sha512-4liA0PuRkZWQFQjwBypdxPfZaRWiv5tkhMXY2hzsa2pNf5s7U3m9cwUchfNKe8wZQxdGPQQzO6Rm2uGe0rvohQ==" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.4.tgz", + "integrity": "sha512-iz64WUOmp/ECQhWMJjTWFzJN/wQ7RJ5v/a6A2OiCwjaGCpNo66WGIjlSf+IULO9DQd0b4cFawLOTbiKSrpKodw==" }, "editorconfig": { "version": "0.15.3", @@ -4031,9 +4031,9 @@ }, "dependencies": { "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "requires": { "lru-cache": "^6.0.0" } @@ -4288,9 +4288,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==" }, "send": { "version": "0.18.0", @@ -4371,9 +4371,9 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "requires": { "lru-cache": "^6.0.0" } @@ -4431,9 +4431,9 @@ }, "dependencies": { "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "requires": { "lru-cache": "^6.0.0" }