From cb150edf114cdd0c4a53852ce21a4953ffa560a4 Mon Sep 17 00:00:00 2001 From: q-Sci Date: Fri, 6 Oct 2023 15:41:04 +0200 Subject: [PATCH 01/11] registered match command --- commands/match/match-command.ts | 418 ++++++++++++++++++++++++++++++++ index.ts | 4 +- package.json | 3 +- 3 files changed, 422 insertions(+), 3 deletions(-) create mode 100644 commands/match/match-command.ts diff --git a/commands/match/match-command.ts b/commands/match/match-command.ts new file mode 100644 index 0000000..abcd315 --- /dev/null +++ b/commands/match/match-command.ts @@ -0,0 +1,418 @@ +import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder, SlashCommandBuilder, Guild, Role, User, TextChannel } from 'discord.js'; +import { client, db } from '../../common'; +import cron from 'cron'; +import 'dotenv/config' + +const questions = [ + { question: 'Auf allen Autobahnen soll ein generelles Tempolimit gelten.', tag: ['Verkehrssicherheit', ' Klimawandel'] }, + { question: 'Deutschland soll seine Verteidigungsausgaben erhöhen.', tag: 'Verteidigungspolitik' }, + { question: 'Bei Bundestagswahlen sollen auch Jugendliche ab 16 Jahren wählen dürfen.', tag: ['Wahlalter', 'Demokratie'] }, + { question: 'Die Förderung von Windenenergie soll beendet werden?', tag: ['Energiepolitik', 'Klimawandel'] }, + { question: 'Die Möglichkeiten der Vermieterinnen und Vermieter, Wohnungsmieten zu erhöhen, sollen gesetzlich stärker begrenzt werden.', tag: ['Mietpreisbremse', 'Wohnraumkosten'] }, + { question: 'Die Ukraine soll Mitglied der Europäischen Union werden dürfen.', tag: ['EU-Erweiterung', 'Ukraine Krieg'] }, + { question: 'Der geplante Ausstieg aus der Kohleverstromung soll vorgezogen werden.', tag: ['Energiepolitik', 'Umweltschutz'] }, + { question: 'Alle Erwerbstätigen sollen in der gesetzlichen Rentenversicherung versichert sein müssen.', tag: 'Sozialpolitik' }, + { question: 'Das Recht anerkannter Flüchtlinge auf Familiennachzug soll abgeschafft werden.', tag: 'Migrationspolitik' }, + { question: 'Auf den Umsatz, der in Deutschland mit digitalen Dienstleistungen erzielt wird, soll eine nationale Steuer erhoben werden.', tag: 'Steuerpolitik' }, + { question: 'Die traditionelle Familie aus Vater, Mutter und Kindern soll stärker als andere Lebensgemeinschaften gefördert werden.', tag: 'Familienpolitik' }, + { question: 'Spenden von Unternehmen an Parteien sollen weiterhin erlaubt sein.', tag: 'Parteienfinanzierung' }, + { question: 'Migration in die Europäische Union sollte erleichtert werden.', tag: 'Migrationspolitik' }, + { question: 'Studentinnen und Studenten sollen BAföG unabhängig vom Einkommen ihrer Eltern erhalten.', tag: 'Bildungspolitik' }, + { question: 'In Deutschland soll es generell möglich sein, neben der deutschen eine zweite Staatsbürgerschaft zu haben.', tag: ['Staatsbürgerschaft', 'Migrationspolitik'] }, + { question: 'Bundesbehörden sollen in ihren Veröffentlichungen unterschiedliche Geschlechtsidentitäten sprachlich berücksichtigen müssen.', tag: ['Genderpolitik', 'Minderheitenpolitik'] }, + { question: 'Der Solidaritätszuschlag soll vollständig abgeschafft werden.', tag: ['Steuerpolitik', 'Solidaritätszuschlag'] }, + { question: 'Das Tragen eines Kopftuchs soll Beamtinnen im Dienst generell erlaubt sein.', tag: ['Religionsfreiheit', 'Minderheitenpolitik'] }, + { question: 'Die Zulassung von neuen Autos mit Verbrennungsmotor soll auch langfristig möglich sein.', tag: 'Klimawandel' }, + { question: 'Der Bund soll mehr Zuständigkeiten in der Schulpolitik erhalten.', tag: 'Bildungspolitik' }, + { question: 'Der Bund soll Projekte zur Bekämpfung des Antisemitismus stärker finanziell unterstützen.', tag: ['Antisemitismus', 'Minderheitenpolitik'] }, + { question: 'Chinesische Firmen sollen keine Aufträge für den Ausbau der Kommunikationsinfrastruktur in Deutschland erhalten dürfen.', tag: 'Wirtschaftspolitik' }, + { question: 'Der Staat soll weiterhin für Religionsgemeinschaften die Kirchensteuer einziehen.', tag: 'Kirchensteuer' }, + { question: 'Der kontrollierte Verkauf von Cannabis soll generell erlaubt sein.', tag: 'Drogenpolitik' }, + { question: 'Deutschland soll aus der Europäischen Union austreten.', tag: 'EU-Politik' }, + { question: 'Die Landeslisten der Parteien für die Wahlen zum Deutschen Bundestag sollen abwechselnd mit Frauen und Männern besetzt werden müssen.', tag: ['Geschlechtergerechtigkeit', 'Minderheitenpolitik'] }, + { question: 'Stationäre Behandlungen im Krankenhaus sollen weiterhin über eine Fallpauschale abgerechnet werden.', tag: 'Gesundheitspolitik' }, + { question: 'Auf hohe Vermögen soll wieder eine Steuer erhoben werden.', tag: ['Steuerpolitik', 'Vermögenssteuer'] }, + { question: 'Bei der Videoüberwachung öffentlicher Plätze soll Gesichtserkennungssoftware eingesetzt werden dürfen.', tag: ['Datenschutz', 'Videoüberwachung'] }, + { question: 'Auch Ehepaare ohne Kinder sollen weiterhin steuerlich begünstigt werden.', tag: 'Familienpolitik' }, + { question: 'Ökologische Landwirtschaft soll stärker gefördert werden als konventionelle Landwirtschaft.', tag: 'Klimawandel' }, + { question: 'Islamische Verbände sollen als Religionsgemeinschaften staatlich anerkannt werden können.', tag: ['Religionspolitik', 'Minderheitenpolitik'] }, + { question: 'Der staatlich festgelegte Preis für den Ausstoß von CO2 beim Heizen und Autofahren soll stärker steigen als geplant.', tag: ['Klimaschutz', 'Klimawandel'] }, + { question: 'Die Schuldenbremse im Grundgesetz soll beibehalten werden.', tag: 'Wirtschaftspolitik' }, + { question: 'Asyl soll weiterhin nur politisch Verfolgten gewährt werden.', tag: 'Migrationspolitik' }, + { question: 'Der gesetzliche Mindestlohn sollte erhöht werden.', tag: 'Sozialpolitik' }, + { question: 'Der Flugverkehr soll höher besteuert werden.', tag: ['Flugverkehr', 'Klimapolitik'] }, + { question: 'Unternehmen sollen selbst entscheiden, ob sie ihren Beschäftigten das Arbeiten im Homeoffice erlauben.', tag: ['Arbeitsrecht', 'Digitalisierung'] }, +]; + +const checkForFeedbackRequests = async () => { + const now = new Date(); + const oneWeekAgo = new Date(now.getTime() - (7 * 24 * 60 * 60 * 1000)); + + const users = await db.db('contrabot').collection("users").find({ + completionTime: { + $lt: oneWeekAgo.toISOString() + }, + feedbackRequestSent: { $ne: true } // This ensures that you don't ask for feedback multiple times + }).toArray(); + + // Create a button to start the survey + const startSurveyButton = new ButtonBuilder() + .setCustomId('start_survey') + .setLabel('Jetzt Feedback geben') + .setStyle(ButtonStyle.Primary); + + const actionRow = new ActionRowBuilder() + .addComponents(startSurveyButton); + + for (const user of users) { + const discordUser = await client.users.fetch(user.userId); + if (discordUser) { + await discordUser.send({ + content: ` + Hallo 👋, vor einer Woche hast du den Test ausgefüllt. + Wir können Contraversum nur durch Feedback unserer Nutzerinnen und Nutzer verbessern. + Daher wäre es ein wichtiger Beitrag für das Projekt und damit auch für die Depolarisierung + der Gesellschaft, wenn du uns Feedback geben könntest. Es dauert weniger als 3 Minuten. Vielen Dank, dein ContraBot ❤️`, + components: [actionRow] + }); + + // Update context for this user in the database + await db.db('contrabot').collection("users").updateOne( + { userId: user.userId }, + { + $set: { + feedbackRequestSent: true + } + } + ); + } + } +}; + +const job = new cron.CronJob('0 0 * * * *', checkForFeedbackRequests); // checks for Feedback every hour +job.start(); + + +export const sendTestButton = async () => { + const button = new ButtonBuilder() + .setCustomId('start_test') + .setLabel('Start Test') + .setStyle(ButtonStyle.Danger); + + const actionRow = new ActionRowBuilder() + .addComponents(button); + + const guildId = process.env.GUILD_ID; + if (!guildId) throw new Error('GUILD_ID is not defined in .env'); + + const guild: Guild | undefined = client.guilds.cache.get(guildId); + if (!guild) throw new Error('Guild not found'); + + (guild.channels.cache.get("1135557183845711983") as TextChannel).send({ components: [actionRow] }); // Channel Id for #How-to-basics +}; + + + +const sendTestReminder = async () => { + try { + const guildId = process.env.GUILD_ID; + if (!guildId) throw new Error('GUILD_ID is not defined in .env'); + + const guild: Guild | undefined = client.guilds.cache.get(guildId); + if (!guild) throw new Error('Guild not found'); + + const verifiedRole: Role | undefined = guild.roles.cache.get('1143590879274213486'); + if (!verifiedRole) throw new Error('Verified role not found'); + + const members = await guild.members.fetch().catch(console.error); + if (!members) throw new Error('Verified role not found'); + + const oneWeekAgo = new Date(); + oneWeekAgo.setDate(oneWeekAgo.getDate() - 7); + + for (const [userID, member] of members) { + const joinDate = member.joinedAt; + if (!joinDate) continue; + + const user = await db.db('contrabot').collection('users').findOne({ userId: userID }); + + if ( + !member.roles.cache.has(verifiedRole.id) && + joinDate <= oneWeekAgo && + !user?.reminderSent + ) { + // Send the test reminder to the member + await member.send("Hey 👋, du hast den Test noch nicht ausgefüllt. Wir würden uns freuen, wenn du den Test noch ausfüllst, damit du mit anderen Usern gematcht werden kannst."); + await member.send("Um einen Test zu starten, tippe /test in den Server ein oder klicke auf die rote Taste 'Test starten' im Channel #how-to-basics."); + + // Add the user to the database and creates reminderSent status + await db.db('contrabot').collection('users').updateOne( + { userId: userID }, + { + $set: + { reminderSent: true } + }, + { upsert: true } + ); + } + } + } catch (error) { + console.error('Error sending test reminders:', error); + } +}; + +// Schedule the function to run every day +const dailyJob = new cron.CronJob('0 0 0 * * *', sendTestReminder); +dailyJob.start(); + +export const sendQuestion = async (interaction: any) => { + + const userContext = await db.db('contrabot').collection("users").findOne({ userId: interaction.user.id }); + + let currentQuestionIndex = userContext?.currentQuestionIndex || 0; + let userResponses = userContext?.userVector || []; + var currentQuestionDisplay = currentQuestionIndex + 1 + + if (currentQuestionIndex === 0) { + userResponses = []; + } + + if (currentQuestionIndex < questions.length) { + const embed = new EmbedBuilder() + .setTitle("Frage: " + currentQuestionDisplay + "/38") + .setDescription(questions[currentQuestionIndex].question) + .setColor('#fb2364'); + + const builder = new ActionRowBuilder().addComponents([ + new ButtonBuilder() + .setCustomId(`agree`) + .setStyle(ButtonStyle.Success) + .setEmoji("👍"), + new ButtonBuilder() + .setCustomId(`neutral`) + .setStyle(ButtonStyle.Secondary) + .setEmoji("😐"), + new ButtonBuilder() + .setCustomId(`disagree`) + .setStyle(ButtonStyle.Danger) + .setEmoji("👎"), + ]); + + interaction.user.send({ + embeds: [embed], + components: [builder] + }); + + + // Update context for this user in the database + await db.db('contrabot').collection("users").updateOne( + { userId: interaction.user.id }, + { + $set: { + userId: interaction.user.id, + username: interaction.user.username, + + currentQuestionIndex: currentQuestionIndex + 1, + userVector: userResponses, + feedbackRequestSent: false, + currentFeedbackQuestionIndex: 0, + invited: interaction.user.invited, + joined: interaction.user.joinedTimestamp + + } + }, + { upsert: true } + ); + } else { + const guildId = process.env.GUILD_ID; + if (!guildId) throw new Error('GUILD_ID not found'); + + const guild: Guild | undefined = client.guilds.cache.get(guildId); + if (!guild) throw new Error('Guild not found'); + + const bestMatch = await findMatchingUser(interaction.user.id, userResponses, guild); + if (bestMatch) { + const interactionGuildMember = guild.members.cache.get(interaction.user.id); + if (!interactionGuildMember) throw new Error('interactionGuildMember was nog found'); + + bestMatch.GuildMember = await guild.members.fetch(bestMatch.userId); + if (!guild) throw new Error('bestMatch.GuildMember'); + + const matchesCategory = guild.channels.cache.find((category: any) => category.name === 'matches' && category.type === 4); + + const channelName = `match-${interaction.user.username}-${bestMatch.username}`; + + const textChannel = await guild.channels.create({ + parent: matchesCategory?.id, + name: channelName.toLowerCase(), + type: 0, + }); + + await textChannel.permissionOverwrites.edit(interactionGuildMember, { + ViewChannel: true, + SendMessages: true, + }); + await textChannel.permissionOverwrites.edit(bestMatch.GuildMember, { + ViewChannel: true, + SendMessages: true, + }); + + const everyone = await guild.roles.everyone; + + await textChannel.permissionOverwrites.edit(everyone, { + ViewChannel: false, + }); + + await textChannel.send(`Hallo ${interactionGuildMember} 👋, hallo ${bestMatch.GuildMember} 👋, basierend auf unserem Algorithmus wurdet ihr als Gesprächspartner ausgewählt. Bitte vergesst nicht respektvoll zu bleiben. Viel Spaß bei eurem Match!`); + await textChannel.send(`Bei beispielsweise diesen drei Fragen seid ihr nicht einer Meinung:`); + conversationStarter(textChannel, interaction, bestMatch.userVector, userResponses); + + interaction.user.send(`Du wurdest erfolgreich mit **@${bestMatch.username}** gematcht. Schau auf den Discord-Server um mit dem Chatten zu beginnen! 😊`); + + verifyUser(interaction, guild); + + } + else { + console.warn('No best match found'); + interaction.user.send("Leider konnte zur Zeit kein geeigneter Gesprächspartner gefunden werden. Bitte versuchen Sie es später erneut."); + } + // Reset context for this user in the database + await db.db('contrabot').collection("users").updateOne( + { userId: interaction.user.id }, + { + $set: { + currentQuestionIndex: 0, // Reset to first question + completionTime: new Date().toISOString(), // Set completion time + } + } + ); + } +} + +async function conversationStarter(channelOfDestination: any, interaction: any, bestMatch: number[], user: number[]) { + + // get all contrasting and similar answers + let addedToDisagree = false; // Track if any numbers were added to disagree + const disagree: number[] = []; + + user.forEach((value, i) => { + const total = value + bestMatch[i]; + if (value !== 0 && total === 0) { + disagree.push(i); + addedToDisagree = true; + } + }); + // Only add to disagree if the flag is still false + if (!addedToDisagree || disagree.length < 6) { + user.forEach((value, i) => { + const total = value + bestMatch[i]; + if (Math.abs(total) === 1) { + disagree.push(i); + } + }); + } + + const selectedIndexes = getRandomDisagreement(disagree, 6); + sendDisagreedQuestions(channelOfDestination, selectedIndexes.slice(0, 3)); +} + +function getRandomDisagreement(arr: number[], num: number) { + return Array.from({ length: Math.min(num, arr.length) }, () => arr.splice(Math.floor(Math.random() * arr.length), 1)[0]); +} + +function sendDisagreedQuestions(channelOfDestination: any, disagree: number[]) { + disagree.forEach((value) => { + channelOfDestination.send({ + embeds: [ + new EmbedBuilder() + .setTitle(`Frage: ${value + 1}/38`) + .setDescription(questions[value].question) + .setColor('#fb2364') + ] + }); + }); + + // Make it so that the tags of the questions are printed properly + const selectedTags = disagree + .map(index => questions[index].tag) + .filter(tag => tag) + .slice(0, 3); + + const topicsMessage = `Als Gesprächsthemen können z.B. ${selectedTags.map(tag => `**${tag}**`).join(", ")} besprochen werden.`; + channelOfDestination.send(topicsMessage); +} + +async function findMatchingUser(userId: string, userResponses: number[], guild: Guild): Promise<{ userId: string, username: string, userVector: number[], GuildMember: any } | null> { + + if (!userId || !Array.isArray(userResponses) || userResponses.length === 0) { + console.log("Invalid input parameters"); + return null; + } + + try { + const users = await db.db('contrabot').collection("users").find({}).toArray(); + + if (!Array.isArray(users)) { + console.error("Error retrieving users from database"); + return null; + } + + let mostOppositeUser: { userId: string, username: string, userVector: number[], GuildMember: any } | null = null; + let lowestDifferenceScore = Infinity; + + for (const user of users) { + if (user.userId === userId) { + console.log("Skipped: same userId as input userId"); + continue; + } + + if (!Array.isArray(user.userVector) || user.userVector.length === 0) { + console.log(`Skipped: Missing or invalid userVector for userId ${user.userId}`); + continue; + } + + const differenceScore = userResponses.reduce((acc, value, index) => { + return acc + value * user.userVector[index]; + }, 0); + + if (differenceScore < lowestDifferenceScore) { + lowestDifferenceScore = differenceScore; + mostOppositeUser = { userId: user.userId, username: user.username, userVector: user.userVector, GuildMember: null }; + } + } + + if (mostOppositeUser) { + const isMember = await guild.members.fetch(mostOppositeUser.userId).then(() => true).catch(() => false); + if (!isMember) { + await db.db('contrabot').collection("users").deleteOne({ userId: mostOppositeUser.userId }); + console.log(`Deleted: userId ${mostOppositeUser.userId} is no longer on the server.`); + return await findMatchingUser(userId, userResponses, guild); // Recursive call if the best match isn't a server member + } + } + + return mostOppositeUser || null; + + } catch (error) { + console.error("Error in findMatchingUser: ", error); + return null; + } +} + +function verifyUser(interaction: any, guild: Guild) { + const role: Role | undefined = guild.roles.cache.get('1143590879274213486'); // Verified role: 1143590879274213486 + if (!role) throw new Error('Role not found'); + + const interactionGuildMember = guild.members.cache.get(interaction.user.id); + if (!interactionGuildMember) throw new Error('Guild not found'); + + interactionGuildMember.roles.add(role).catch(console.error); +} + +export const data = new SlashCommandBuilder().setName('match').setDescription('Requests new match without retaking the test.'); +export const execute = async (interaction: any) => { + await interaction.reply({ + content: 'Neues Match wird ermittelt. Bitte schaue in deinen Direktnachrichten nach :)', + ephemeral: true, + }); + sendQuestion(interaction); +}; diff --git a/index.ts b/index.ts index e73e9bb..f323844 100644 --- a/index.ts +++ b/index.ts @@ -13,9 +13,9 @@ client.on(Events.ClientReady, async (c) => { }); client.login(process.env.TOKEN); // Log in to the bot -client.on("ready", () => { +/*client.on("ready", () => { sendTestButton() -}); +});*/ // Load commands const foldersPath = path.join(__dirname, 'commands'); diff --git a/package.json b/package.json index df21ad6..842b52f 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,8 @@ "start": "ts-node index.ts", "mac-start": "brew services start mongodb-community@7.0 && ts-node index.ts", "systemd-start": "sudo systemctl start mongod && ts-node index.ts", - "systemv-start": "sudo service start mongod && ts-node index.ts" + "systemv-start": "sudo service start mongod && ts-node index.ts", + "deploy-commands": "ts-node deploy-commands.ts" }, "keywords": [], "author": "", From 2a9d1bbc368a01aa81c87c50a15dc51ba22ea10b Mon Sep 17 00:00:00 2001 From: q-Sci Date: Fri, 6 Oct 2023 18:27:44 +0200 Subject: [PATCH 02/11] moved stuff to other files --- commands/match/match-command.ts | 277 +-------------------- commands/test/test-command.ts | 155 +----------- functions/conversationStarter.ts | 57 +++++ functions/findMatchingUser.ts | 60 +++++ startSurvey.ts => functions/startSurvey.ts | 0 index.ts | 2 +- questions.ts | 44 ++++ 7 files changed, 170 insertions(+), 425 deletions(-) create mode 100644 functions/conversationStarter.ts create mode 100644 functions/findMatchingUser.ts rename startSurvey.ts => functions/startSurvey.ts (100%) create mode 100644 questions.ts diff --git a/commands/match/match-command.ts b/commands/match/match-command.ts index abcd315..75e44e0 100644 --- a/commands/match/match-command.ts +++ b/commands/match/match-command.ts @@ -1,169 +1,9 @@ import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder, SlashCommandBuilder, Guild, Role, User, TextChannel } from 'discord.js'; import { client, db } from '../../common'; -import cron from 'cron'; -import 'dotenv/config' - -const questions = [ - { question: 'Auf allen Autobahnen soll ein generelles Tempolimit gelten.', tag: ['Verkehrssicherheit', ' Klimawandel'] }, - { question: 'Deutschland soll seine Verteidigungsausgaben erhöhen.', tag: 'Verteidigungspolitik' }, - { question: 'Bei Bundestagswahlen sollen auch Jugendliche ab 16 Jahren wählen dürfen.', tag: ['Wahlalter', 'Demokratie'] }, - { question: 'Die Förderung von Windenenergie soll beendet werden?', tag: ['Energiepolitik', 'Klimawandel'] }, - { question: 'Die Möglichkeiten der Vermieterinnen und Vermieter, Wohnungsmieten zu erhöhen, sollen gesetzlich stärker begrenzt werden.', tag: ['Mietpreisbremse', 'Wohnraumkosten'] }, - { question: 'Die Ukraine soll Mitglied der Europäischen Union werden dürfen.', tag: ['EU-Erweiterung', 'Ukraine Krieg'] }, - { question: 'Der geplante Ausstieg aus der Kohleverstromung soll vorgezogen werden.', tag: ['Energiepolitik', 'Umweltschutz'] }, - { question: 'Alle Erwerbstätigen sollen in der gesetzlichen Rentenversicherung versichert sein müssen.', tag: 'Sozialpolitik' }, - { question: 'Das Recht anerkannter Flüchtlinge auf Familiennachzug soll abgeschafft werden.', tag: 'Migrationspolitik' }, - { question: 'Auf den Umsatz, der in Deutschland mit digitalen Dienstleistungen erzielt wird, soll eine nationale Steuer erhoben werden.', tag: 'Steuerpolitik' }, - { question: 'Die traditionelle Familie aus Vater, Mutter und Kindern soll stärker als andere Lebensgemeinschaften gefördert werden.', tag: 'Familienpolitik' }, - { question: 'Spenden von Unternehmen an Parteien sollen weiterhin erlaubt sein.', tag: 'Parteienfinanzierung' }, - { question: 'Migration in die Europäische Union sollte erleichtert werden.', tag: 'Migrationspolitik' }, - { question: 'Studentinnen und Studenten sollen BAföG unabhängig vom Einkommen ihrer Eltern erhalten.', tag: 'Bildungspolitik' }, - { question: 'In Deutschland soll es generell möglich sein, neben der deutschen eine zweite Staatsbürgerschaft zu haben.', tag: ['Staatsbürgerschaft', 'Migrationspolitik'] }, - { question: 'Bundesbehörden sollen in ihren Veröffentlichungen unterschiedliche Geschlechtsidentitäten sprachlich berücksichtigen müssen.', tag: ['Genderpolitik', 'Minderheitenpolitik'] }, - { question: 'Der Solidaritätszuschlag soll vollständig abgeschafft werden.', tag: ['Steuerpolitik', 'Solidaritätszuschlag'] }, - { question: 'Das Tragen eines Kopftuchs soll Beamtinnen im Dienst generell erlaubt sein.', tag: ['Religionsfreiheit', 'Minderheitenpolitik'] }, - { question: 'Die Zulassung von neuen Autos mit Verbrennungsmotor soll auch langfristig möglich sein.', tag: 'Klimawandel' }, - { question: 'Der Bund soll mehr Zuständigkeiten in der Schulpolitik erhalten.', tag: 'Bildungspolitik' }, - { question: 'Der Bund soll Projekte zur Bekämpfung des Antisemitismus stärker finanziell unterstützen.', tag: ['Antisemitismus', 'Minderheitenpolitik'] }, - { question: 'Chinesische Firmen sollen keine Aufträge für den Ausbau der Kommunikationsinfrastruktur in Deutschland erhalten dürfen.', tag: 'Wirtschaftspolitik' }, - { question: 'Der Staat soll weiterhin für Religionsgemeinschaften die Kirchensteuer einziehen.', tag: 'Kirchensteuer' }, - { question: 'Der kontrollierte Verkauf von Cannabis soll generell erlaubt sein.', tag: 'Drogenpolitik' }, - { question: 'Deutschland soll aus der Europäischen Union austreten.', tag: 'EU-Politik' }, - { question: 'Die Landeslisten der Parteien für die Wahlen zum Deutschen Bundestag sollen abwechselnd mit Frauen und Männern besetzt werden müssen.', tag: ['Geschlechtergerechtigkeit', 'Minderheitenpolitik'] }, - { question: 'Stationäre Behandlungen im Krankenhaus sollen weiterhin über eine Fallpauschale abgerechnet werden.', tag: 'Gesundheitspolitik' }, - { question: 'Auf hohe Vermögen soll wieder eine Steuer erhoben werden.', tag: ['Steuerpolitik', 'Vermögenssteuer'] }, - { question: 'Bei der Videoüberwachung öffentlicher Plätze soll Gesichtserkennungssoftware eingesetzt werden dürfen.', tag: ['Datenschutz', 'Videoüberwachung'] }, - { question: 'Auch Ehepaare ohne Kinder sollen weiterhin steuerlich begünstigt werden.', tag: 'Familienpolitik' }, - { question: 'Ökologische Landwirtschaft soll stärker gefördert werden als konventionelle Landwirtschaft.', tag: 'Klimawandel' }, - { question: 'Islamische Verbände sollen als Religionsgemeinschaften staatlich anerkannt werden können.', tag: ['Religionspolitik', 'Minderheitenpolitik'] }, - { question: 'Der staatlich festgelegte Preis für den Ausstoß von CO2 beim Heizen und Autofahren soll stärker steigen als geplant.', tag: ['Klimaschutz', 'Klimawandel'] }, - { question: 'Die Schuldenbremse im Grundgesetz soll beibehalten werden.', tag: 'Wirtschaftspolitik' }, - { question: 'Asyl soll weiterhin nur politisch Verfolgten gewährt werden.', tag: 'Migrationspolitik' }, - { question: 'Der gesetzliche Mindestlohn sollte erhöht werden.', tag: 'Sozialpolitik' }, - { question: 'Der Flugverkehr soll höher besteuert werden.', tag: ['Flugverkehr', 'Klimapolitik'] }, - { question: 'Unternehmen sollen selbst entscheiden, ob sie ihren Beschäftigten das Arbeiten im Homeoffice erlauben.', tag: ['Arbeitsrecht', 'Digitalisierung'] }, -]; - -const checkForFeedbackRequests = async () => { - const now = new Date(); - const oneWeekAgo = new Date(now.getTime() - (7 * 24 * 60 * 60 * 1000)); - - const users = await db.db('contrabot').collection("users").find({ - completionTime: { - $lt: oneWeekAgo.toISOString() - }, - feedbackRequestSent: { $ne: true } // This ensures that you don't ask for feedback multiple times - }).toArray(); - - // Create a button to start the survey - const startSurveyButton = new ButtonBuilder() - .setCustomId('start_survey') - .setLabel('Jetzt Feedback geben') - .setStyle(ButtonStyle.Primary); - - const actionRow = new ActionRowBuilder() - .addComponents(startSurveyButton); - - for (const user of users) { - const discordUser = await client.users.fetch(user.userId); - if (discordUser) { - await discordUser.send({ - content: ` - Hallo 👋, vor einer Woche hast du den Test ausgefüllt. - Wir können Contraversum nur durch Feedback unserer Nutzerinnen und Nutzer verbessern. - Daher wäre es ein wichtiger Beitrag für das Projekt und damit auch für die Depolarisierung - der Gesellschaft, wenn du uns Feedback geben könntest. Es dauert weniger als 3 Minuten. Vielen Dank, dein ContraBot ❤️`, - components: [actionRow] - }); - - // Update context for this user in the database - await db.db('contrabot').collection("users").updateOne( - { userId: user.userId }, - { - $set: { - feedbackRequestSent: true - } - } - ); - } - } -}; - -const job = new cron.CronJob('0 0 * * * *', checkForFeedbackRequests); // checks for Feedback every hour -job.start(); - - -export const sendTestButton = async () => { - const button = new ButtonBuilder() - .setCustomId('start_test') - .setLabel('Start Test') - .setStyle(ButtonStyle.Danger); - - const actionRow = new ActionRowBuilder() - .addComponents(button); - - const guildId = process.env.GUILD_ID; - if (!guildId) throw new Error('GUILD_ID is not defined in .env'); - - const guild: Guild | undefined = client.guilds.cache.get(guildId); - if (!guild) throw new Error('Guild not found'); - - (guild.channels.cache.get("1135557183845711983") as TextChannel).send({ components: [actionRow] }); // Channel Id for #How-to-basics -}; - - - -const sendTestReminder = async () => { - try { - const guildId = process.env.GUILD_ID; - if (!guildId) throw new Error('GUILD_ID is not defined in .env'); - - const guild: Guild | undefined = client.guilds.cache.get(guildId); - if (!guild) throw new Error('Guild not found'); - - const verifiedRole: Role | undefined = guild.roles.cache.get('1143590879274213486'); - if (!verifiedRole) throw new Error('Verified role not found'); - - const members = await guild.members.fetch().catch(console.error); - if (!members) throw new Error('Verified role not found'); - - const oneWeekAgo = new Date(); - oneWeekAgo.setDate(oneWeekAgo.getDate() - 7); - - for (const [userID, member] of members) { - const joinDate = member.joinedAt; - if (!joinDate) continue; - - const user = await db.db('contrabot').collection('users').findOne({ userId: userID }); - - if ( - !member.roles.cache.has(verifiedRole.id) && - joinDate <= oneWeekAgo && - !user?.reminderSent - ) { - // Send the test reminder to the member - await member.send("Hey 👋, du hast den Test noch nicht ausgefüllt. Wir würden uns freuen, wenn du den Test noch ausfüllst, damit du mit anderen Usern gematcht werden kannst."); - await member.send("Um einen Test zu starten, tippe /test in den Server ein oder klicke auf die rote Taste 'Test starten' im Channel #how-to-basics."); - - // Add the user to the database and creates reminderSent status - await db.db('contrabot').collection('users').updateOne( - { userId: userID }, - { - $set: - { reminderSent: true } - }, - { upsert: true } - ); - } - } - } catch (error) { - console.error('Error sending test reminders:', error); - } -}; - -// Schedule the function to run every day -const dailyJob = new cron.CronJob('0 0 0 * * *', sendTestReminder); -dailyJob.start(); +import 'dotenv/config'; +import questions from '../../questions'; +import findMatchingUser from '../../functions/findMatchingUser'; +import conversationStarter from '../../functions/conversationStarter'; export const sendQuestion = async (interaction: any) => { @@ -289,115 +129,6 @@ export const sendQuestion = async (interaction: any) => { } } -async function conversationStarter(channelOfDestination: any, interaction: any, bestMatch: number[], user: number[]) { - - // get all contrasting and similar answers - let addedToDisagree = false; // Track if any numbers were added to disagree - const disagree: number[] = []; - - user.forEach((value, i) => { - const total = value + bestMatch[i]; - if (value !== 0 && total === 0) { - disagree.push(i); - addedToDisagree = true; - } - }); - // Only add to disagree if the flag is still false - if (!addedToDisagree || disagree.length < 6) { - user.forEach((value, i) => { - const total = value + bestMatch[i]; - if (Math.abs(total) === 1) { - disagree.push(i); - } - }); - } - - const selectedIndexes = getRandomDisagreement(disagree, 6); - sendDisagreedQuestions(channelOfDestination, selectedIndexes.slice(0, 3)); -} - -function getRandomDisagreement(arr: number[], num: number) { - return Array.from({ length: Math.min(num, arr.length) }, () => arr.splice(Math.floor(Math.random() * arr.length), 1)[0]); -} - -function sendDisagreedQuestions(channelOfDestination: any, disagree: number[]) { - disagree.forEach((value) => { - channelOfDestination.send({ - embeds: [ - new EmbedBuilder() - .setTitle(`Frage: ${value + 1}/38`) - .setDescription(questions[value].question) - .setColor('#fb2364') - ] - }); - }); - - // Make it so that the tags of the questions are printed properly - const selectedTags = disagree - .map(index => questions[index].tag) - .filter(tag => tag) - .slice(0, 3); - - const topicsMessage = `Als Gesprächsthemen können z.B. ${selectedTags.map(tag => `**${tag}**`).join(", ")} besprochen werden.`; - channelOfDestination.send(topicsMessage); -} - -async function findMatchingUser(userId: string, userResponses: number[], guild: Guild): Promise<{ userId: string, username: string, userVector: number[], GuildMember: any } | null> { - - if (!userId || !Array.isArray(userResponses) || userResponses.length === 0) { - console.log("Invalid input parameters"); - return null; - } - - try { - const users = await db.db('contrabot').collection("users").find({}).toArray(); - - if (!Array.isArray(users)) { - console.error("Error retrieving users from database"); - return null; - } - - let mostOppositeUser: { userId: string, username: string, userVector: number[], GuildMember: any } | null = null; - let lowestDifferenceScore = Infinity; - - for (const user of users) { - if (user.userId === userId) { - console.log("Skipped: same userId as input userId"); - continue; - } - - if (!Array.isArray(user.userVector) || user.userVector.length === 0) { - console.log(`Skipped: Missing or invalid userVector for userId ${user.userId}`); - continue; - } - - const differenceScore = userResponses.reduce((acc, value, index) => { - return acc + value * user.userVector[index]; - }, 0); - - if (differenceScore < lowestDifferenceScore) { - lowestDifferenceScore = differenceScore; - mostOppositeUser = { userId: user.userId, username: user.username, userVector: user.userVector, GuildMember: null }; - } - } - - if (mostOppositeUser) { - const isMember = await guild.members.fetch(mostOppositeUser.userId).then(() => true).catch(() => false); - if (!isMember) { - await db.db('contrabot').collection("users").deleteOne({ userId: mostOppositeUser.userId }); - console.log(`Deleted: userId ${mostOppositeUser.userId} is no longer on the server.`); - return await findMatchingUser(userId, userResponses, guild); // Recursive call if the best match isn't a server member - } - } - - return mostOppositeUser || null; - - } catch (error) { - console.error("Error in findMatchingUser: ", error); - return null; - } -} - function verifyUser(interaction: any, guild: Guild) { const role: Role | undefined = guild.roles.cache.get('1143590879274213486'); // Verified role: 1143590879274213486 if (!role) throw new Error('Role not found'); diff --git a/commands/test/test-command.ts b/commands/test/test-command.ts index 998b9c1..0e43a6c 100644 --- a/commands/test/test-command.ts +++ b/commands/test/test-command.ts @@ -1,48 +1,10 @@ import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder, SlashCommandBuilder, Guild, Role, User, TextChannel } from 'discord.js'; import { client, db } from '../../common'; import cron from 'cron'; -import 'dotenv/config' - -const questions = [ - { question: 'Auf allen Autobahnen soll ein generelles Tempolimit gelten.', tag: ['Verkehrssicherheit', ' Klimawandel'] }, - { question: 'Deutschland soll seine Verteidigungsausgaben erhöhen.', tag: 'Verteidigungspolitik' }, - { question: 'Bei Bundestagswahlen sollen auch Jugendliche ab 16 Jahren wählen dürfen.', tag: ['Wahlalter', 'Demokratie'] }, - { question: 'Die Förderung von Windenenergie soll beendet werden?', tag: ['Energiepolitik', 'Klimawandel'] }, - { question: 'Die Möglichkeiten der Vermieterinnen und Vermieter, Wohnungsmieten zu erhöhen, sollen gesetzlich stärker begrenzt werden.', tag: ['Mietpreisbremse', 'Wohnraumkosten'] }, - { question: 'Die Ukraine soll Mitglied der Europäischen Union werden dürfen.', tag: ['EU-Erweiterung', 'Ukraine Krieg'] }, - { question: 'Der geplante Ausstieg aus der Kohleverstromung soll vorgezogen werden.', tag: ['Energiepolitik', 'Umweltschutz'] }, - { question: 'Alle Erwerbstätigen sollen in der gesetzlichen Rentenversicherung versichert sein müssen.', tag: 'Sozialpolitik' }, - { question: 'Das Recht anerkannter Flüchtlinge auf Familiennachzug soll abgeschafft werden.', tag: 'Migrationspolitik' }, - { question: 'Auf den Umsatz, der in Deutschland mit digitalen Dienstleistungen erzielt wird, soll eine nationale Steuer erhoben werden.', tag: 'Steuerpolitik' }, - { question: 'Die traditionelle Familie aus Vater, Mutter und Kindern soll stärker als andere Lebensgemeinschaften gefördert werden.', tag: 'Familienpolitik' }, - { question: 'Spenden von Unternehmen an Parteien sollen weiterhin erlaubt sein.', tag: 'Parteienfinanzierung' }, - { question: 'Migration in die Europäische Union sollte erleichtert werden.', tag: 'Migrationspolitik' }, - { question: 'Studentinnen und Studenten sollen BAföG unabhängig vom Einkommen ihrer Eltern erhalten.', tag: 'Bildungspolitik' }, - { question: 'In Deutschland soll es generell möglich sein, neben der deutschen eine zweite Staatsbürgerschaft zu haben.', tag: ['Staatsbürgerschaft', 'Migrationspolitik'] }, - { question: 'Bundesbehörden sollen in ihren Veröffentlichungen unterschiedliche Geschlechtsidentitäten sprachlich berücksichtigen müssen.', tag: ['Genderpolitik', 'Minderheitenpolitik'] }, - { question: 'Der Solidaritätszuschlag soll vollständig abgeschafft werden.', tag: ['Steuerpolitik', 'Solidaritätszuschlag'] }, - { question: 'Das Tragen eines Kopftuchs soll Beamtinnen im Dienst generell erlaubt sein.', tag: ['Religionsfreiheit', 'Minderheitenpolitik'] }, - { question: 'Die Zulassung von neuen Autos mit Verbrennungsmotor soll auch langfristig möglich sein.', tag: 'Klimawandel' }, - { question: 'Der Bund soll mehr Zuständigkeiten in der Schulpolitik erhalten.', tag: 'Bildungspolitik' }, - { question: 'Der Bund soll Projekte zur Bekämpfung des Antisemitismus stärker finanziell unterstützen.', tag: ['Antisemitismus', 'Minderheitenpolitik'] }, - { question: 'Chinesische Firmen sollen keine Aufträge für den Ausbau der Kommunikationsinfrastruktur in Deutschland erhalten dürfen.', tag: 'Wirtschaftspolitik' }, - { question: 'Der Staat soll weiterhin für Religionsgemeinschaften die Kirchensteuer einziehen.', tag: 'Kirchensteuer' }, - { question: 'Der kontrollierte Verkauf von Cannabis soll generell erlaubt sein.', tag: 'Drogenpolitik' }, - { question: 'Deutschland soll aus der Europäischen Union austreten.', tag: 'EU-Politik' }, - { question: 'Die Landeslisten der Parteien für die Wahlen zum Deutschen Bundestag sollen abwechselnd mit Frauen und Männern besetzt werden müssen.', tag: ['Geschlechtergerechtigkeit', 'Minderheitenpolitik'] }, - { question: 'Stationäre Behandlungen im Krankenhaus sollen weiterhin über eine Fallpauschale abgerechnet werden.', tag: 'Gesundheitspolitik' }, - { question: 'Auf hohe Vermögen soll wieder eine Steuer erhoben werden.', tag: ['Steuerpolitik', 'Vermögenssteuer'] }, - { question: 'Bei der Videoüberwachung öffentlicher Plätze soll Gesichtserkennungssoftware eingesetzt werden dürfen.', tag: ['Datenschutz', 'Videoüberwachung'] }, - { question: 'Auch Ehepaare ohne Kinder sollen weiterhin steuerlich begünstigt werden.', tag: 'Familienpolitik' }, - { question: 'Ökologische Landwirtschaft soll stärker gefördert werden als konventionelle Landwirtschaft.', tag: 'Klimawandel' }, - { question: 'Islamische Verbände sollen als Religionsgemeinschaften staatlich anerkannt werden können.', tag: ['Religionspolitik', 'Minderheitenpolitik'] }, - { question: 'Der staatlich festgelegte Preis für den Ausstoß von CO2 beim Heizen und Autofahren soll stärker steigen als geplant.', tag: ['Klimaschutz', 'Klimawandel'] }, - { question: 'Die Schuldenbremse im Grundgesetz soll beibehalten werden.', tag: 'Wirtschaftspolitik' }, - { question: 'Asyl soll weiterhin nur politisch Verfolgten gewährt werden.', tag: 'Migrationspolitik' }, - { question: 'Der gesetzliche Mindestlohn sollte erhöht werden.', tag: 'Sozialpolitik' }, - { question: 'Der Flugverkehr soll höher besteuert werden.', tag: ['Flugverkehr', 'Klimapolitik'] }, - { question: 'Unternehmen sollen selbst entscheiden, ob sie ihren Beschäftigten das Arbeiten im Homeoffice erlauben.', tag: ['Arbeitsrecht', 'Digitalisierung'] }, -]; +import 'dotenv/config'; +import questions from '../../questions'; +import findMatchingUser from '../../functions/findMatchingUser'; +import conversationStarter from '../../functions/conversationStarter'; const checkForFeedbackRequests = async () => { const now = new Date(); @@ -289,115 +251,6 @@ export const sendQuestion = async (interaction: any) => { } } -async function conversationStarter(channelOfDestination: any, interaction: any, bestMatch: number[], user: number[]) { - - // get all contrasting and similar answers - let addedToDisagree = false; // Track if any numbers were added to disagree - const disagree: number[] = []; - - user.forEach((value, i) => { - const total = value + bestMatch[i]; - if (value !== 0 && total === 0) { - disagree.push(i); - addedToDisagree = true; - } - }); - // Only add to disagree if the flag is still false - if (!addedToDisagree || disagree.length < 6) { - user.forEach((value, i) => { - const total = value + bestMatch[i]; - if (Math.abs(total) === 1) { - disagree.push(i); - } - }); - } - - const selectedIndexes = getRandomDisagreement(disagree, 6); - sendDisagreedQuestions(channelOfDestination, selectedIndexes.slice(0, 3)); -} - -function getRandomDisagreement(arr: number[], num: number) { - return Array.from({ length: Math.min(num, arr.length) }, () => arr.splice(Math.floor(Math.random() * arr.length), 1)[0]); -} - -function sendDisagreedQuestions(channelOfDestination: any, disagree: number[]) { - disagree.forEach((value) => { - channelOfDestination.send({ - embeds: [ - new EmbedBuilder() - .setTitle(`Frage: ${value + 1}/38`) - .setDescription(questions[value].question) - .setColor('#fb2364') - ] - }); - }); - - // Make it so that the tags of the questions are printed properly - const selectedTags = disagree - .map(index => questions[index].tag) - .filter(tag => tag) - .slice(0, 3); - - const topicsMessage = `Als Gesprächsthemen können z.B. ${selectedTags.map(tag => `**${tag}**`).join(", ")} besprochen werden.`; - channelOfDestination.send(topicsMessage); -} - -async function findMatchingUser(userId: string, userResponses: number[], guild: Guild): Promise<{ userId: string, username: string, userVector: number[], GuildMember: any } | null> { - - if (!userId || !Array.isArray(userResponses) || userResponses.length === 0) { - console.log("Invalid input parameters"); - return null; - } - - try { - const users = await db.db('contrabot').collection("users").find({}).toArray(); - - if (!Array.isArray(users)) { - console.error("Error retrieving users from database"); - return null; - } - - let mostOppositeUser: { userId: string, username: string, userVector: number[], GuildMember: any } | null = null; - let lowestDifferenceScore = Infinity; - - for (const user of users) { - if (user.userId === userId) { - console.log("Skipped: same userId as input userId"); - continue; - } - - if (!Array.isArray(user.userVector) || user.userVector.length === 0) { - console.log(`Skipped: Missing or invalid userVector for userId ${user.userId}`); - continue; - } - - const differenceScore = userResponses.reduce((acc, value, index) => { - return acc + value * user.userVector[index]; - }, 0); - - if (differenceScore < lowestDifferenceScore) { - lowestDifferenceScore = differenceScore; - mostOppositeUser = { userId: user.userId, username: user.username, userVector: user.userVector, GuildMember: null }; - } - } - - if (mostOppositeUser) { - const isMember = await guild.members.fetch(mostOppositeUser.userId).then(() => true).catch(() => false); - if (!isMember) { - await db.db('contrabot').collection("users").deleteOne({ userId: mostOppositeUser.userId }); - console.log(`Deleted: userId ${mostOppositeUser.userId} is no longer on the server.`); - return await findMatchingUser(userId, userResponses, guild); // Recursive call if the best match isn't a server member - } - } - - return mostOppositeUser || null; - - } catch (error) { - console.error("Error in findMatchingUser: ", error); - return null; - } -} - function verifyUser(interaction: any, guild: Guild) { const role: Role | undefined = guild.roles.cache.get('1143590879274213486'); // Verified role: 1143590879274213486 if (!role) throw new Error('Role not found'); diff --git a/functions/conversationStarter.ts b/functions/conversationStarter.ts new file mode 100644 index 0000000..65e3544 --- /dev/null +++ b/functions/conversationStarter.ts @@ -0,0 +1,57 @@ +import { EmbedBuilder } from 'discord.js'; +import questions from '../questions'; + +async function conversationStarter(channelOfDestination: any, interaction: any, bestMatch: number[], user: number[]) { + + // get all contrasting and similar answers + let addedToDisagree = false; // Track if any numbers were added to disagree + const disagree: number[] = []; + + user.forEach((value, i) => { + const total = value + bestMatch[i]; + if (value !== 0 && total === 0) { + disagree.push(i); + addedToDisagree = true; + } + }); + // Only add to disagree if the flag is still false + if (!addedToDisagree || disagree.length < 6) { + user.forEach((value, i) => { + const total = value + bestMatch[i]; + if (Math.abs(total) === 1) { + disagree.push(i); + } + }); + } + + const selectedIndexes = getRandomDisagreement(disagree, 6); + sendDisagreedQuestions(channelOfDestination, selectedIndexes.slice(0, 3)); +} + +function getRandomDisagreement(arr: number[], num: number) { + return Array.from({ length: Math.min(num, arr.length) }, () => arr.splice(Math.floor(Math.random() * arr.length), 1)[0]); +} + +function sendDisagreedQuestions(channelOfDestination: any, disagree: number[]) { + disagree.forEach((value) => { + channelOfDestination.send({ + embeds: [ + new EmbedBuilder() + .setTitle(`Frage: ${value + 1}/38`) + .setDescription(questions[value].question) + .setColor('#fb2364') + ] + }); + }); + + // Make it so that the tags of the questions are printed properly + const selectedTags = disagree + .map(index => questions[index].tag) + .filter(tag => tag) + .slice(0, 3); + + const topicsMessage = `Als Gesprächsthemen können z.B. ${selectedTags.map(tag => `**${tag}**`).join(", ")} besprochen werden.`; + channelOfDestination.send(topicsMessage); +} + +export default conversationStarter; diff --git a/functions/findMatchingUser.ts b/functions/findMatchingUser.ts new file mode 100644 index 0000000..eb01bf0 --- /dev/null +++ b/functions/findMatchingUser.ts @@ -0,0 +1,60 @@ +import { Guild } from 'discord.js'; +import { db } from '../common'; + +async function findMatchingUser(userId: string, userResponses: number[], guild: Guild): Promise<{ userId: string, username: string, userVector: number[], GuildMember: any } | null> { + + if (!userId || !Array.isArray(userResponses) || userResponses.length === 0) { + console.log("Invalid input parameters"); + return null; + } + + try { + const users = await db.db('contrabot').collection("users").find({}).toArray(); + + if (!Array.isArray(users)) { + console.error("Error retrieving users from database"); + return null; + } + + let mostOppositeUser: { userId: string, username: string, userVector: number[], GuildMember: any } | null = null; + let lowestDifferenceScore = Infinity; + + for (const user of users) { + if (user.userId === userId) { + console.log("Skipped: same userId as input userId"); + continue; + } + + if (!Array.isArray(user.userVector) || user.userVector.length === 0) { + console.log(`Skipped: Missing or invalid userVector for userId ${user.userId}`); + continue; + } + + const differenceScore = userResponses.reduce((acc, value, index) => { + return acc + value * user.userVector[index]; + }, 0); + + if (differenceScore < lowestDifferenceScore) { + lowestDifferenceScore = differenceScore; + mostOppositeUser = { userId: user.userId, username: user.username, userVector: user.userVector, GuildMember: null }; + } + } + + if (mostOppositeUser) { + const isMember = await guild.members.fetch(mostOppositeUser.userId).then(() => true).catch(() => false); + if (!isMember) { + await db.db('contrabot').collection("users").deleteOne({ userId: mostOppositeUser.userId }); + console.log(`Deleted: userId ${mostOppositeUser.userId} is no longer on the server.`); + return await findMatchingUser(userId, userResponses, guild); // Recursive call if the best match isn't a server member + } + } + + return mostOppositeUser || null; + + } catch (error) { + console.error("Error in findMatchingUser: ", error); + return null; + } +} + +export default findMatchingUser; diff --git a/startSurvey.ts b/functions/startSurvey.ts similarity index 100% rename from startSurvey.ts rename to functions/startSurvey.ts diff --git a/index.ts b/index.ts index f323844..a07f1a7 100644 --- a/index.ts +++ b/index.ts @@ -1,7 +1,7 @@ import 'dotenv/config' import { Events } from 'discord.js'; import { sendQuestion, sendTestButton } from './commands/test/test-command'; -import { sendSurveyQuestions, Feedbackquestions } from './startSurvey'; +import { sendSurveyQuestions, Feedbackquestions } from './functions/startSurvey'; import * as fs from 'fs'; import path from 'path' import { google } from 'googleapis'; diff --git a/questions.ts b/questions.ts new file mode 100644 index 0000000..f8a20c9 --- /dev/null +++ b/questions.ts @@ -0,0 +1,44 @@ +// all questions used in the political test + +const questions = [ + { question: 'Auf allen Autobahnen soll ein generelles Tempolimit gelten.', tag: ['Verkehrssicherheit', ' Klimawandel'] }, + { question: 'Deutschland soll seine Verteidigungsausgaben erhöhen.', tag: 'Verteidigungspolitik' }, + { question: 'Bei Bundestagswahlen sollen auch Jugendliche ab 16 Jahren wählen dürfen.', tag: ['Wahlalter', 'Demokratie'] }, + { question: 'Die Förderung von Windenenergie soll beendet werden?', tag: ['Energiepolitik', 'Klimawandel'] }, + { question: 'Die Möglichkeiten der Vermieterinnen und Vermieter, Wohnungsmieten zu erhöhen, sollen gesetzlich stärker begrenzt werden.', tag: ['Mietpreisbremse', 'Wohnraumkosten'] }, + { question: 'Die Ukraine soll Mitglied der Europäischen Union werden dürfen.', tag: ['EU-Erweiterung', 'Ukraine Krieg'] }, + { question: 'Der geplante Ausstieg aus der Kohleverstromung soll vorgezogen werden.', tag: ['Energiepolitik', 'Umweltschutz'] }, + { question: 'Alle Erwerbstätigen sollen in der gesetzlichen Rentenversicherung versichert sein müssen.', tag: 'Sozialpolitik' }, + { question: 'Das Recht anerkannter Flüchtlinge auf Familiennachzug soll abgeschafft werden.', tag: 'Migrationspolitik' }, + { question: 'Auf den Umsatz, der in Deutschland mit digitalen Dienstleistungen erzielt wird, soll eine nationale Steuer erhoben werden.', tag: 'Steuerpolitik' }, + { question: 'Die traditionelle Familie aus Vater, Mutter und Kindern soll stärker als andere Lebensgemeinschaften gefördert werden.', tag: 'Familienpolitik' }, + { question: 'Spenden von Unternehmen an Parteien sollen weiterhin erlaubt sein.', tag: 'Parteienfinanzierung' }, + { question: 'Migration in die Europäische Union sollte erleichtert werden.', tag: 'Migrationspolitik' }, + { question: 'Studentinnen und Studenten sollen BAföG unabhängig vom Einkommen ihrer Eltern erhalten.', tag: 'Bildungspolitik' }, + { question: 'In Deutschland soll es generell möglich sein, neben der deutschen eine zweite Staatsbürgerschaft zu haben.', tag: ['Staatsbürgerschaft', 'Migrationspolitik'] }, + { question: 'Bundesbehörden sollen in ihren Veröffentlichungen unterschiedliche Geschlechtsidentitäten sprachlich berücksichtigen müssen.', tag: ['Genderpolitik', 'Minderheitenpolitik'] }, + { question: 'Der Solidaritätszuschlag soll vollständig abgeschafft werden.', tag: ['Steuerpolitik', 'Solidaritätszuschlag'] }, + { question: 'Das Tragen eines Kopftuchs soll Beamtinnen im Dienst generell erlaubt sein.', tag: ['Religionsfreiheit', 'Minderheitenpolitik'] }, + { question: 'Die Zulassung von neuen Autos mit Verbrennungsmotor soll auch langfristig möglich sein.', tag: 'Klimawandel' }, + { question: 'Der Bund soll mehr Zuständigkeiten in der Schulpolitik erhalten.', tag: 'Bildungspolitik' }, + { question: 'Der Bund soll Projekte zur Bekämpfung des Antisemitismus stärker finanziell unterstützen.', tag: ['Antisemitismus', 'Minderheitenpolitik'] }, + { question: 'Chinesische Firmen sollen keine Aufträge für den Ausbau der Kommunikationsinfrastruktur in Deutschland erhalten dürfen.', tag: 'Wirtschaftspolitik' }, + { question: 'Der Staat soll weiterhin für Religionsgemeinschaften die Kirchensteuer einziehen.', tag: 'Kirchensteuer' }, + { question: 'Der kontrollierte Verkauf von Cannabis soll generell erlaubt sein.', tag: 'Drogenpolitik' }, + { question: 'Deutschland soll aus der Europäischen Union austreten.', tag: 'EU-Politik' }, + { question: 'Die Landeslisten der Parteien für die Wahlen zum Deutschen Bundestag sollen abwechselnd mit Frauen und Männern besetzt werden müssen.', tag: ['Geschlechtergerechtigkeit', 'Minderheitenpolitik'] }, + { question: 'Stationäre Behandlungen im Krankenhaus sollen weiterhin über eine Fallpauschale abgerechnet werden.', tag: 'Gesundheitspolitik' }, + { question: 'Auf hohe Vermögen soll wieder eine Steuer erhoben werden.', tag: ['Steuerpolitik', 'Vermögenssteuer'] }, + { question: 'Bei der Videoüberwachung öffentlicher Plätze soll Gesichtserkennungssoftware eingesetzt werden dürfen.', tag: ['Datenschutz', 'Videoüberwachung'] }, + { question: 'Auch Ehepaare ohne Kinder sollen weiterhin steuerlich begünstigt werden.', tag: 'Familienpolitik' }, + { question: 'Ökologische Landwirtschaft soll stärker gefördert werden als konventionelle Landwirtschaft.', tag: 'Klimawandel' }, + { question: 'Islamische Verbände sollen als Religionsgemeinschaften staatlich anerkannt werden können.', tag: ['Religionspolitik', 'Minderheitenpolitik'] }, + { question: 'Der staatlich festgelegte Preis für den Ausstoß von CO2 beim Heizen und Autofahren soll stärker steigen als geplant.', tag: ['Klimaschutz', 'Klimawandel'] }, + { question: 'Die Schuldenbremse im Grundgesetz soll beibehalten werden.', tag: 'Wirtschaftspolitik' }, + { question: 'Asyl soll weiterhin nur politisch Verfolgten gewährt werden.', tag: 'Migrationspolitik' }, + { question: 'Der gesetzliche Mindestlohn sollte erhöht werden.', tag: 'Sozialpolitik' }, + { question: 'Der Flugverkehr soll höher besteuert werden.', tag: ['Flugverkehr', 'Klimapolitik'] }, + { question: 'Unternehmen sollen selbst entscheiden, ob sie ihren Beschäftigten das Arbeiten im Homeoffice erlauben.', tag: ['Arbeitsrecht', 'Digitalisierung'] }, +]; + +export default questions; From 2eb94f375e557e830245dbc2419e3e1e345bdef1 Mon Sep 17 00:00:00 2001 From: q-Sci Date: Fri, 6 Oct 2023 20:17:49 +0200 Subject: [PATCH 03/11] fixed some issue --- commands/test/test-command.ts | 3 ++- index.ts | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/commands/test/test-command.ts b/commands/test/test-command.ts index 0e43a6c..fe255fb 100644 --- a/commands/test/test-command.ts +++ b/commands/test/test-command.ts @@ -70,7 +70,8 @@ export const sendTestButton = async () => { const guild: Guild | undefined = client.guilds.cache.get(guildId); if (!guild) throw new Error('Guild not found'); - (guild.channels.cache.get("1135557183845711983") as TextChannel).send({ components: [actionRow] }); // Channel Id for #How-to-basics + // (guild.channels.cache.get("1135557183845711983") as TextChannel).send({ components: [actionRow] }); // Channel Id for #How-to-basics (main server) + // (guild.channels.cache.get("1159905209414332526") as TextChannel).send({ components: [actionRow] }); // Test server channel }; diff --git a/index.ts b/index.ts index a07f1a7..370fe3a 100644 --- a/index.ts +++ b/index.ts @@ -13,9 +13,9 @@ client.on(Events.ClientReady, async (c) => { }); client.login(process.env.TOKEN); // Log in to the bot -/*client.on("ready", () => { +client.on("ready", () => { sendTestButton() -});*/ +}); // Load commands const foldersPath = path.join(__dirname, 'commands'); From ae59198439fe6872a88b36b53e842146f718cbbe Mon Sep 17 00:00:00 2001 From: q-Sci Date: Mon, 9 Oct 2023 16:27:24 +0200 Subject: [PATCH 04/11] more cleanup --- commands/match/match-command.ts | 159 ++++++++++---------------------- functions/findMatchingUser.ts | 104 ++++++++++----------- 2 files changed, 100 insertions(+), 163 deletions(-) diff --git a/commands/match/match-command.ts b/commands/match/match-command.ts index 75e44e0..a1cf74e 100644 --- a/commands/match/match-command.ts +++ b/commands/match/match-command.ts @@ -1,7 +1,6 @@ -import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder, SlashCommandBuilder, Guild, Role, User, TextChannel } from 'discord.js'; +import { SlashCommandBuilder, Guild } from 'discord.js'; import { client, db } from '../../common'; import 'dotenv/config'; -import questions from '../../questions'; import findMatchingUser from '../../functions/findMatchingUser'; import conversationStarter from '../../functions/conversationStarter'; @@ -11,132 +10,70 @@ export const sendQuestion = async (interaction: any) => { let currentQuestionIndex = userContext?.currentQuestionIndex || 0; let userResponses = userContext?.userVector || []; - var currentQuestionDisplay = currentQuestionIndex + 1 if (currentQuestionIndex === 0) { userResponses = []; } - if (currentQuestionIndex < questions.length) { - const embed = new EmbedBuilder() - .setTitle("Frage: " + currentQuestionDisplay + "/38") - .setDescription(questions[currentQuestionIndex].question) - .setColor('#fb2364'); - - const builder = new ActionRowBuilder().addComponents([ - new ButtonBuilder() - .setCustomId(`agree`) - .setStyle(ButtonStyle.Success) - .setEmoji("👍"), - new ButtonBuilder() - .setCustomId(`neutral`) - .setStyle(ButtonStyle.Secondary) - .setEmoji("😐"), - new ButtonBuilder() - .setCustomId(`disagree`) - .setStyle(ButtonStyle.Danger) - .setEmoji("👎"), - ]); - - interaction.user.send({ - embeds: [embed], - components: [builder] - }); - - - // Update context for this user in the database - await db.db('contrabot').collection("users").updateOne( - { userId: interaction.user.id }, - { - $set: { - userId: interaction.user.id, - username: interaction.user.username, - - currentQuestionIndex: currentQuestionIndex + 1, - userVector: userResponses, - feedbackRequestSent: false, - currentFeedbackQuestionIndex: 0, - invited: interaction.user.invited, - joined: interaction.user.joinedTimestamp - - } - }, - { upsert: true } - ); - } else { - const guildId = process.env.GUILD_ID; - if (!guildId) throw new Error('GUILD_ID not found'); - - const guild: Guild | undefined = client.guilds.cache.get(guildId); - if (!guild) throw new Error('Guild not found'); + const guildId = process.env.GUILD_ID; + if (!guildId) throw new Error('GUILD_ID not found'); - const bestMatch = await findMatchingUser(interaction.user.id, userResponses, guild); - if (bestMatch) { - const interactionGuildMember = guild.members.cache.get(interaction.user.id); - if (!interactionGuildMember) throw new Error('interactionGuildMember was nog found'); + const guild: Guild | undefined = client.guilds.cache.get(guildId); + if (!guild) throw new Error('Guild not found'); + + const bestMatch = await findMatchingUser(interaction.user.id, userResponses, guild); + if (bestMatch) { + const interactionGuildMember = guild.members.cache.get(interaction.user.id); + if (!interactionGuildMember) throw new Error('interactionGuildMember was nog found'); - bestMatch.GuildMember = await guild.members.fetch(bestMatch.userId); - if (!guild) throw new Error('bestMatch.GuildMember'); + bestMatch.GuildMember = await guild.members.fetch(bestMatch.userId); + if (!guild) throw new Error('bestMatch.GuildMember'); - const matchesCategory = guild.channels.cache.find((category: any) => category.name === 'matches' && category.type === 4); + const matchesCategory = guild.channels.cache.find((category: any) => category.name === 'matches' && category.type === 4); - const channelName = `match-${interaction.user.username}-${bestMatch.username}`; + const channelName = `match-${interaction.user.username}-${bestMatch.username}`; - const textChannel = await guild.channels.create({ - parent: matchesCategory?.id, - name: channelName.toLowerCase(), - type: 0, - }); - - await textChannel.permissionOverwrites.edit(interactionGuildMember, { - ViewChannel: true, - SendMessages: true, - }); - await textChannel.permissionOverwrites.edit(bestMatch.GuildMember, { - ViewChannel: true, - SendMessages: true, - }); - - const everyone = await guild.roles.everyone; + const textChannel = await guild.channels.create({ + parent: matchesCategory?.id, + name: channelName.toLowerCase(), + type: 0, + }); - await textChannel.permissionOverwrites.edit(everyone, { - ViewChannel: false, - }); + await textChannel.permissionOverwrites.edit(interactionGuildMember, { + ViewChannel: true, + SendMessages: true, + }); + await textChannel.permissionOverwrites.edit(bestMatch.GuildMember, { + ViewChannel: true, + SendMessages: true, + }); - await textChannel.send(`Hallo ${interactionGuildMember} 👋, hallo ${bestMatch.GuildMember} 👋, basierend auf unserem Algorithmus wurdet ihr als Gesprächspartner ausgewählt. Bitte vergesst nicht respektvoll zu bleiben. Viel Spaß bei eurem Match!`); - await textChannel.send(`Bei beispielsweise diesen drei Fragen seid ihr nicht einer Meinung:`); - conversationStarter(textChannel, interaction, bestMatch.userVector, userResponses); + const everyone = await guild.roles.everyone; - interaction.user.send(`Du wurdest erfolgreich mit **@${bestMatch.username}** gematcht. Schau auf den Discord-Server um mit dem Chatten zu beginnen! 😊`); + await textChannel.permissionOverwrites.edit(everyone, { + ViewChannel: false, + }); - verifyUser(interaction, guild); + await textChannel.send(`Hallo ${interactionGuildMember} 👋, hallo ${bestMatch.GuildMember} 👋, basierend auf unserem Algorithmus wurdet ihr als Gesprächspartner ausgewählt. Bitte vergesst nicht respektvoll zu bleiben. Viel Spaß bei eurem Match!`); + await textChannel.send(`Bei beispielsweise diesen drei Fragen seid ihr nicht einer Meinung:`); + conversationStarter(textChannel, interaction, bestMatch.userVector, userResponses); - } - else { - console.warn('No best match found'); - interaction.user.send("Leider konnte zur Zeit kein geeigneter Gesprächspartner gefunden werden. Bitte versuchen Sie es später erneut."); - } - // Reset context for this user in the database - await db.db('contrabot').collection("users").updateOne( - { userId: interaction.user.id }, - { - $set: { - currentQuestionIndex: 0, // Reset to first question - completionTime: new Date().toISOString(), // Set completion time - } - } - ); + interaction.user.send(`Du wurdest erfolgreich mit **@${bestMatch.username}** gematcht. Schau auf den Discord-Server um mit dem Chatten zu beginnen! 😊`); + } else { + console.warn('No best match found'); + interaction.user.send("Leider konnte zur Zeit kein geeigneter Gesprächspartner gefunden werden. Bitte versuchen Sie es später erneut."); } -} - -function verifyUser(interaction: any, guild: Guild) { - const role: Role | undefined = guild.roles.cache.get('1143590879274213486'); // Verified role: 1143590879274213486 - if (!role) throw new Error('Role not found'); - - const interactionGuildMember = guild.members.cache.get(interaction.user.id); - if (!interactionGuildMember) throw new Error('Guild not found'); - interactionGuildMember.roles.add(role).catch(console.error); + // Reset context for this user in the database + await db.db('contrabot').collection("users").updateOne( + { userId: interaction.user.id }, + { + $set: { + currentQuestionIndex: 0, // Reset to first question + completionTime: new Date().toISOString(), // Set completion time + } + } + ); } export const data = new SlashCommandBuilder().setName('match').setDescription('Requests new match without retaking the test.'); diff --git a/functions/findMatchingUser.ts b/functions/findMatchingUser.ts index eb01bf0..f0330d9 100644 --- a/functions/findMatchingUser.ts +++ b/functions/findMatchingUser.ts @@ -3,58 +3,58 @@ import { db } from '../common'; async function findMatchingUser(userId: string, userResponses: number[], guild: Guild): Promise<{ userId: string, username: string, userVector: number[], GuildMember: any } | null> { - if (!userId || !Array.isArray(userResponses) || userResponses.length === 0) { - console.log("Invalid input parameters"); - return null; - } - - try { - const users = await db.db('contrabot').collection("users").find({}).toArray(); - - if (!Array.isArray(users)) { - console.error("Error retrieving users from database"); - return null; - } - - let mostOppositeUser: { userId: string, username: string, userVector: number[], GuildMember: any } | null = null; - let lowestDifferenceScore = Infinity; - - for (const user of users) { - if (user.userId === userId) { - console.log("Skipped: same userId as input userId"); - continue; - } - - if (!Array.isArray(user.userVector) || user.userVector.length === 0) { - console.log(`Skipped: Missing or invalid userVector for userId ${user.userId}`); - continue; - } - - const differenceScore = userResponses.reduce((acc, value, index) => { - return acc + value * user.userVector[index]; - }, 0); - - if (differenceScore < lowestDifferenceScore) { - lowestDifferenceScore = differenceScore; - mostOppositeUser = { userId: user.userId, username: user.username, userVector: user.userVector, GuildMember: null }; - } - } - - if (mostOppositeUser) { - const isMember = await guild.members.fetch(mostOppositeUser.userId).then(() => true).catch(() => false); - if (!isMember) { - await db.db('contrabot').collection("users").deleteOne({ userId: mostOppositeUser.userId }); - console.log(`Deleted: userId ${mostOppositeUser.userId} is no longer on the server.`); - return await findMatchingUser(userId, userResponses, guild); // Recursive call if the best match isn't a server member - } - } - - return mostOppositeUser || null; - - } catch (error) { - console.error("Error in findMatchingUser: ", error); - return null; - } + if (!userId || !Array.isArray(userResponses) || userResponses.length === 0) { + console.log("Invalid input parameters"); + return null; + } + + try { + const users = await db.db('contrabot').collection("users").find({}).toArray(); + + if (!Array.isArray(users)) { + console.error("Error retrieving users from database"); + return null; + } + + let mostOppositeUser: { userId: string, username: string, userVector: number[], GuildMember: any } | null = null; + let lowestDifferenceScore = Infinity; + + for (const user of users) { + if (user.userId === userId) { + console.log("Skipped: same userId as input userId"); + continue; + } + + if (!Array.isArray(user.userVector) || user.userVector.length === 0) { + console.log(`Skipped: Missing or invalid userVector for userId ${user.userId}`); + continue; + } + + const differenceScore = userResponses.reduce((acc, value, index) => { + return acc + value * user.userVector[index]; + }, 0); + + if (differenceScore < lowestDifferenceScore) { + lowestDifferenceScore = differenceScore; + mostOppositeUser = { userId: user.userId, username: user.username, userVector: user.userVector, GuildMember: null }; + } + } + + if (mostOppositeUser) { + const isMember = await guild.members.fetch(mostOppositeUser.userId).then(() => true).catch(() => false); + if (!isMember) { + await db.db('contrabot').collection("users").deleteOne({ userId: mostOppositeUser.userId }); + console.log(`Deleted: userId ${mostOppositeUser.userId} is no longer on the server.`); + return await findMatchingUser(userId, userResponses, guild); // Recursive call if the best match isn't a server member + } + } + + return mostOppositeUser || null; + + } catch (error) { + console.error("Error in findMatchingUser: ", error); + return null; + } } export default findMatchingUser; From d97e961faa3b9f35251d6f46b17d2daaa839b6db Mon Sep 17 00:00:00 2001 From: q-Sci Date: Mon, 9 Oct 2023 16:47:03 +0200 Subject: [PATCH 05/11] small changes --- commands/match/match-command.ts | 5 +++++ commands/test/test-command.ts | 1 + 2 files changed, 6 insertions(+) diff --git a/commands/match/match-command.ts b/commands/match/match-command.ts index a1cf74e..3ea6f0c 100644 --- a/commands/match/match-command.ts +++ b/commands/match/match-command.ts @@ -11,10 +11,15 @@ export const sendQuestion = async (interaction: any) => { let currentQuestionIndex = userContext?.currentQuestionIndex || 0; let userResponses = userContext?.userVector || []; + // TODO: user responses + // TODO: check if user has completed the test + if (currentQuestionIndex === 0) { userResponses = []; } + console.log(userContext); + const guildId = process.env.GUILD_ID; if (!guildId) throw new Error('GUILD_ID not found'); diff --git a/commands/test/test-command.ts b/commands/test/test-command.ts index fe255fb..c308953 100644 --- a/commands/test/test-command.ts +++ b/commands/test/test-command.ts @@ -239,6 +239,7 @@ export const sendQuestion = async (interaction: any) => { console.warn('No best match found'); interaction.user.send("Leider konnte zur Zeit kein geeigneter Gesprächspartner gefunden werden. Bitte versuchen Sie es später erneut."); } + // Reset context for this user in the database await db.db('contrabot').collection("users").updateOne( { userId: interaction.user.id }, From 7e1e35c1a01e80b567901d2405f4c58f2cd86de6 Mon Sep 17 00:00:00 2001 From: q-Sci Date: Sat, 14 Oct 2023 21:46:37 +0200 Subject: [PATCH 06/11] lol --- commands/match/match-command.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/commands/match/match-command.ts b/commands/match/match-command.ts index 3ea6f0c..190ae56 100644 --- a/commands/match/match-command.ts +++ b/commands/match/match-command.ts @@ -8,16 +8,10 @@ export const sendQuestion = async (interaction: any) => { const userContext = await db.db('contrabot').collection("users").findOne({ userId: interaction.user.id }); - let currentQuestionIndex = userContext?.currentQuestionIndex || 0; let userResponses = userContext?.userVector || []; - // TODO: user responses // TODO: check if user has completed the test - if (currentQuestionIndex === 0) { - userResponses = []; - } - console.log(userContext); const guildId = process.env.GUILD_ID; From e7dd0feeac6e5c5d6267423e5220d59358ec885c Mon Sep 17 00:00:00 2001 From: q-Sci Date: Sat, 14 Oct 2023 22:15:45 +0200 Subject: [PATCH 07/11] check if thest was finished --- commands/match/match-command.ts | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/commands/match/match-command.ts b/commands/match/match-command.ts index 190ae56..7ca4b74 100644 --- a/commands/match/match-command.ts +++ b/commands/match/match-command.ts @@ -1,6 +1,7 @@ import { SlashCommandBuilder, Guild } from 'discord.js'; import { client, db } from '../../common'; import 'dotenv/config'; +import questions from '../../questions'; import findMatchingUser from '../../functions/findMatchingUser'; import conversationStarter from '../../functions/conversationStarter'; @@ -10,10 +11,9 @@ export const sendQuestion = async (interaction: any) => { let userResponses = userContext?.userVector || []; + // Test discussion topics // TODO: check if user has completed the test - console.log(userContext); - const guildId = process.env.GUILD_ID; if (!guildId) throw new Error('GUILD_ID not found'); @@ -77,9 +77,23 @@ export const sendQuestion = async (interaction: any) => { export const data = new SlashCommandBuilder().setName('match').setDescription('Requests new match without retaking the test.'); export const execute = async (interaction: any) => { - await interaction.reply({ - content: 'Neues Match wird ermittelt. Bitte schaue in deinen Direktnachrichten nach :)', - ephemeral: true, - }); - sendQuestion(interaction); + const userContext = await db.db('contrabot').collection("users").findOne({ userId: interaction.user.id }); + + let userResponses = userContext?.userVector || []; + + // checks if the user has answered the test + // if not, an error hint is displayed + if (userResponses.length === questions.length) { + await interaction.reply({ + content: 'Neues Match wird ermittelt. Bitte schaue in deinen Direktnachrichten nach :)', + ephemeral: true, + }); + sendQuestion(interaction); + } else { + await interaction.reply({ + content: 'Bitte beantworte den Meinungstest vollständig, bevor du mit Anderen gematcht werden kannst! Bitte nutze dazu den Befehl `/test`.', + ephemeral: true, + }); + console.log('Invalid userVector: test was not completed!'); + } }; From a1bcb3c2a1f933d1c15432b1b7575f14748550f5 Mon Sep 17 00:00:00 2001 From: q-Sci Date: Sat, 14 Oct 2023 22:16:02 +0200 Subject: [PATCH 08/11] xtra line --- commands/match/match-command.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/commands/match/match-command.ts b/commands/match/match-command.ts index 7ca4b74..0a5f158 100644 --- a/commands/match/match-command.ts +++ b/commands/match/match-command.ts @@ -77,6 +77,7 @@ export const sendQuestion = async (interaction: any) => { export const data = new SlashCommandBuilder().setName('match').setDescription('Requests new match without retaking the test.'); export const execute = async (interaction: any) => { + const userContext = await db.db('contrabot').collection("users").findOne({ userId: interaction.user.id }); let userResponses = userContext?.userVector || []; From 7dd6e8007db6c072e8155ec295d0bbf0654a5406 Mon Sep 17 00:00:00 2001 From: q-Sci Date: Sat, 14 Oct 2023 22:16:22 +0200 Subject: [PATCH 09/11] removed comments --- commands/match/match-command.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/commands/match/match-command.ts b/commands/match/match-command.ts index 0a5f158..d9a6ae5 100644 --- a/commands/match/match-command.ts +++ b/commands/match/match-command.ts @@ -11,9 +11,6 @@ export const sendQuestion = async (interaction: any) => { let userResponses = userContext?.userVector || []; - // Test discussion topics - // TODO: check if user has completed the test - const guildId = process.env.GUILD_ID; if (!guildId) throw new Error('GUILD_ID not found'); @@ -77,7 +74,7 @@ export const sendQuestion = async (interaction: any) => { export const data = new SlashCommandBuilder().setName('match').setDescription('Requests new match without retaking the test.'); export const execute = async (interaction: any) => { - + const userContext = await db.db('contrabot').collection("users").findOne({ userId: interaction.user.id }); let userResponses = userContext?.userVector || []; From da3729e29c945169fea91f04261ec993dc83cfae Mon Sep 17 00:00:00 2001 From: Johan Trieloff Date: Sun, 22 Oct 2023 22:33:55 +0200 Subject: [PATCH 10/11] started changes --- commands/match/match-command.ts | 72 +-------------------------------- commands/test/test-command.ts | 2 +- questions.ts | 4 +- 3 files changed, 5 insertions(+), 73 deletions(-) diff --git a/commands/match/match-command.ts b/commands/match/match-command.ts index d9a6ae5..fc846b3 100644 --- a/commands/match/match-command.ts +++ b/commands/match/match-command.ts @@ -1,76 +1,8 @@ import { SlashCommandBuilder, Guild } from 'discord.js'; -import { client, db } from '../../common'; +import { db } from '../../common'; import 'dotenv/config'; import questions from '../../questions'; -import findMatchingUser from '../../functions/findMatchingUser'; -import conversationStarter from '../../functions/conversationStarter'; - -export const sendQuestion = async (interaction: any) => { - - const userContext = await db.db('contrabot').collection("users").findOne({ userId: interaction.user.id }); - - let userResponses = userContext?.userVector || []; - - const guildId = process.env.GUILD_ID; - if (!guildId) throw new Error('GUILD_ID not found'); - - const guild: Guild | undefined = client.guilds.cache.get(guildId); - if (!guild) throw new Error('Guild not found'); - - const bestMatch = await findMatchingUser(interaction.user.id, userResponses, guild); - if (bestMatch) { - const interactionGuildMember = guild.members.cache.get(interaction.user.id); - if (!interactionGuildMember) throw new Error('interactionGuildMember was nog found'); - - bestMatch.GuildMember = await guild.members.fetch(bestMatch.userId); - if (!guild) throw new Error('bestMatch.GuildMember'); - - const matchesCategory = guild.channels.cache.find((category: any) => category.name === 'matches' && category.type === 4); - - const channelName = `match-${interaction.user.username}-${bestMatch.username}`; - - const textChannel = await guild.channels.create({ - parent: matchesCategory?.id, - name: channelName.toLowerCase(), - type: 0, - }); - - await textChannel.permissionOverwrites.edit(interactionGuildMember, { - ViewChannel: true, - SendMessages: true, - }); - await textChannel.permissionOverwrites.edit(bestMatch.GuildMember, { - ViewChannel: true, - SendMessages: true, - }); - - const everyone = await guild.roles.everyone; - - await textChannel.permissionOverwrites.edit(everyone, { - ViewChannel: false, - }); - - await textChannel.send(`Hallo ${interactionGuildMember} 👋, hallo ${bestMatch.GuildMember} 👋, basierend auf unserem Algorithmus wurdet ihr als Gesprächspartner ausgewählt. Bitte vergesst nicht respektvoll zu bleiben. Viel Spaß bei eurem Match!`); - await textChannel.send(`Bei beispielsweise diesen drei Fragen seid ihr nicht einer Meinung:`); - conversationStarter(textChannel, interaction, bestMatch.userVector, userResponses); - - interaction.user.send(`Du wurdest erfolgreich mit **@${bestMatch.username}** gematcht. Schau auf den Discord-Server um mit dem Chatten zu beginnen! 😊`); - } else { - console.warn('No best match found'); - interaction.user.send("Leider konnte zur Zeit kein geeigneter Gesprächspartner gefunden werden. Bitte versuchen Sie es später erneut."); - } - - // Reset context for this user in the database - await db.db('contrabot').collection("users").updateOne( - { userId: interaction.user.id }, - { - $set: { - currentQuestionIndex: 0, // Reset to first question - completionTime: new Date().toISOString(), // Set completion time - } - } - ); -} +import { sendQuestion } from '../test/test-command'; export const data = new SlashCommandBuilder().setName('match').setDescription('Requests new match without retaking the test.'); export const execute = async (interaction: any) => { diff --git a/commands/test/test-command.ts b/commands/test/test-command.ts index c308953..28119b0 100644 --- a/commands/test/test-command.ts +++ b/commands/test/test-command.ts @@ -254,7 +254,7 @@ export const sendQuestion = async (interaction: any) => { } function verifyUser(interaction: any, guild: Guild) { - const role: Role | undefined = guild.roles.cache.get('1143590879274213486'); // Verified role: 1143590879274213486 + const role: Role | undefined = guild.roles.cache.get('1153647196449820755'); // Verified role: 1143590879274213486 if (!role) throw new Error('Role not found'); const interactionGuildMember = guild.members.cache.get(interaction.user.id); diff --git a/questions.ts b/questions.ts index f8a20c9..25938d6 100644 --- a/questions.ts +++ b/questions.ts @@ -1,7 +1,7 @@ // all questions used in the political test const questions = [ - { question: 'Auf allen Autobahnen soll ein generelles Tempolimit gelten.', tag: ['Verkehrssicherheit', ' Klimawandel'] }, + /*{ question: 'Auf allen Autobahnen soll ein generelles Tempolimit gelten.', tag: ['Verkehrssicherheit', ' Klimawandel'] }, { question: 'Deutschland soll seine Verteidigungsausgaben erhöhen.', tag: 'Verteidigungspolitik' }, { question: 'Bei Bundestagswahlen sollen auch Jugendliche ab 16 Jahren wählen dürfen.', tag: ['Wahlalter', 'Demokratie'] }, { question: 'Die Förderung von Windenenergie soll beendet werden?', tag: ['Energiepolitik', 'Klimawandel'] }, @@ -32,7 +32,7 @@ const questions = [ { question: 'Bei der Videoüberwachung öffentlicher Plätze soll Gesichtserkennungssoftware eingesetzt werden dürfen.', tag: ['Datenschutz', 'Videoüberwachung'] }, { question: 'Auch Ehepaare ohne Kinder sollen weiterhin steuerlich begünstigt werden.', tag: 'Familienpolitik' }, { question: 'Ökologische Landwirtschaft soll stärker gefördert werden als konventionelle Landwirtschaft.', tag: 'Klimawandel' }, - { question: 'Islamische Verbände sollen als Religionsgemeinschaften staatlich anerkannt werden können.', tag: ['Religionspolitik', 'Minderheitenpolitik'] }, + */{ question: 'Islamische Verbände sollen als Religionsgemeinschaften staatlich anerkannt werden können.', tag: ['Religionspolitik', 'Minderheitenpolitik'] }, { question: 'Der staatlich festgelegte Preis für den Ausstoß von CO2 beim Heizen und Autofahren soll stärker steigen als geplant.', tag: ['Klimaschutz', 'Klimawandel'] }, { question: 'Die Schuldenbremse im Grundgesetz soll beibehalten werden.', tag: 'Wirtschaftspolitik' }, { question: 'Asyl soll weiterhin nur politisch Verfolgten gewährt werden.', tag: 'Migrationspolitik' }, From d88255353a7f17ed76baf605a0999e5d7b529861 Mon Sep 17 00:00:00 2001 From: GregTCLTK Date: Mon, 23 Oct 2023 00:26:01 +0200 Subject: [PATCH 11/11] WIP breaking changes --- commands/{match => }/match-command.ts | 9 ++- commands/{test => }/test-command.ts | 28 ++++----- index.ts | 90 ++++++++++++++------------- questions.json | 40 ++++++++++++ questions.ts | 44 ------------- 5 files changed, 103 insertions(+), 108 deletions(-) rename commands/{match => }/match-command.ts (74%) rename commands/{test => }/test-command.ts (94%) create mode 100644 questions.json delete mode 100644 questions.ts diff --git a/commands/match/match-command.ts b/commands/match-command.ts similarity index 74% rename from commands/match/match-command.ts rename to commands/match-command.ts index fc846b3..16d38f3 100644 --- a/commands/match/match-command.ts +++ b/commands/match-command.ts @@ -1,11 +1,10 @@ import { SlashCommandBuilder, Guild } from 'discord.js'; -import { db } from '../../common'; +import { db } from '../common'; import 'dotenv/config'; -import questions from '../../questions'; -import { sendQuestion } from '../test/test-command'; +import questions from '../questions'; +import { sendQuestion } from './test-command'; -export const data = new SlashCommandBuilder().setName('match').setDescription('Requests new match without retaking the test.'); -export const execute = async (interaction: any) => { +export async function executeMatch(interaction: any) { const userContext = await db.db('contrabot').collection("users").findOne({ userId: interaction.user.id }); diff --git a/commands/test/test-command.ts b/commands/test-command.ts similarity index 94% rename from commands/test/test-command.ts rename to commands/test-command.ts index 28119b0..3ec2eca 100644 --- a/commands/test/test-command.ts +++ b/commands/test-command.ts @@ -1,10 +1,10 @@ import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder, SlashCommandBuilder, Guild, Role, User, TextChannel } from 'discord.js'; -import { client, db } from '../../common'; +import { client, db } from '../common'; import cron from 'cron'; import 'dotenv/config'; -import questions from '../../questions'; -import findMatchingUser from '../../functions/findMatchingUser'; -import conversationStarter from '../../functions/conversationStarter'; +import questions from '../questions'; +import findMatchingUser from '../functions/findMatchingUser'; +import conversationStarter from '../functions/conversationStarter'; const checkForFeedbackRequests = async () => { const now = new Date(); @@ -31,11 +31,11 @@ const checkForFeedbackRequests = async () => { if (discordUser) { await discordUser.send({ content: ` - Hallo 👋, vor einer Woche hast du den Test ausgefüllt. - Wir können Contraversum nur durch Feedback unserer Nutzerinnen und Nutzer verbessern. + Hallo 👋, vor einer Woche hast du den Test ausgefüllt. + Wir können Contraversum nur durch Feedback unserer Nutzerinnen und Nutzer verbessern. Daher wäre es ein wichtiger Beitrag für das Projekt und damit auch für die Depolarisierung der Gesellschaft, wenn du uns Feedback geben könntest. Es dauert weniger als 3 Minuten. Vielen Dank, dein ContraBot ❤️`, - components: [actionRow] + components: [ actionRow ] }); // Update context for this user in the database @@ -93,7 +93,7 @@ const sendTestReminder = async () => { const oneWeekAgo = new Date(); oneWeekAgo.setDate(oneWeekAgo.getDate() - 7); - for (const [userID, member] of members) { + for (const [ userID, member ] of members) { const joinDate = member.joinedAt; if (!joinDate) continue; @@ -108,7 +108,7 @@ const sendTestReminder = async () => { await member.send("Hey 👋, du hast den Test noch nicht ausgefüllt. Wir würden uns freuen, wenn du den Test noch ausfüllst, damit du mit anderen Usern gematcht werden kannst."); await member.send("Um einen Test zu starten, tippe /test in den Server ein oder klicke auf die rote Taste 'Test starten' im Channel #how-to-basics."); - // Add the user to the database and creates reminderSent status + // Add the user to the database and creates reminderSent status await db.db('contrabot').collection('users').updateOne( { userId: userID }, { @@ -143,7 +143,7 @@ export const sendQuestion = async (interaction: any) => { if (currentQuestionIndex < questions.length) { const embed = new EmbedBuilder() .setTitle("Frage: " + currentQuestionDisplay + "/38") - .setDescription(questions[currentQuestionIndex].question) + .setDescription(questions[ currentQuestionIndex ].question) .setColor('#fb2364'); const builder = new ActionRowBuilder().addComponents([ @@ -162,8 +162,8 @@ export const sendQuestion = async (interaction: any) => { ]); interaction.user.send({ - embeds: [embed], - components: [builder] + embeds: [ embed ], + components: [ builder ] }); @@ -263,12 +263,10 @@ function verifyUser(interaction: any, guild: Guild) { interactionGuildMember.roles.add(role).catch(console.error); } -export const data = new SlashCommandBuilder().setName('test').setDescription('Asks the test questions!'); -export const execute = async (interaction: any) => { +export async function executeTest(interaction: any) { await interaction.reply({ content: 'Deine Meinung ist gefragt! Bitte kommentiere die folgenden These mit 👍, 👎 oder 😐. Test wurde gestartet.\nBitte schaue in deinen Direktnachrichten nach :)', ephemeral: true, }); sendQuestion(interaction); }; - diff --git a/index.ts b/index.ts index 370fe3a..d542b6f 100644 --- a/index.ts +++ b/index.ts @@ -1,52 +1,57 @@ import 'dotenv/config' -import { Events } from 'discord.js'; -import { sendQuestion, sendTestButton } from './commands/test/test-command'; +import { Events, REST, Routes } from 'discord.js'; +import { executeTest, sendQuestion, sendTestButton } from './commands/test-command'; import { sendSurveyQuestions, Feedbackquestions } from './functions/startSurvey'; -import * as fs from 'fs'; -import path from 'path' import { google } from 'googleapis'; -import { client, db, ClientWithCommands } from './common'; +import { client, db } from './common'; +import { executeMatch } from "./commands/match-command"; -client.on(Events.ClientReady, async (c) => { - console.log(`Ready! Logged in as ${c.user.tag}`); - await db.connect(); -}); client.login(process.env.TOKEN); // Log in to the bot -client.on("ready", () => { +client.on(Events.ClientReady, async c => { + console.log(`Ready! Logged in as ${c.user.tag}`); + await db.connect(); sendTestButton() -}); + //add later + //client.user.setActivity("123", {ActivityType.Listening}) -// Load commands -const foldersPath = path.join(__dirname, 'commands'); -const commandFolders = fs.readdirSync(foldersPath); -for (const folder of commandFolders) { - const commandsPath = path.join(foldersPath, folder); - const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.ts')); - for (const file of commandFiles) { - const filePath = path.join(commandsPath, file); - const command = require(filePath); - if ('data' in command && 'execute' in command) { - client.commands.set(command.data.name, command); - } else { - console.log(`[WARNING] The command at ${filePath} is missing a required "data" or "execute" property.`); + const rest = new REST().setToken(process.env.TOKEN!); + + (async () => { + try { + console.log('Started refreshing application (/) commands.'); + + await rest.put(Routes.applicationCommands(client.user!.id), { + body: + [ + { + name: 'match', + description: 'Requests new match without retaking the test.' + }, + { + name: 'test', + description: 'Asks the test questions!' + }, + ] + }); + + console.log('Successfully reloaded application (/) commands.'); + } catch (error) { + console.error(error); } - } -} + })(); + +}); // Catch command errors -client.on(Events.InteractionCreate, async (interaction) => { +client.on(Events.InteractionCreate, async interaction => { // Handle Slash commands if (interaction.isChatInputCommand()) { - const command = (interaction.client as ClientWithCommands).commands.get(interaction.commandName); - - if (!command) { - console.error(`No command matching ${interaction.commandName} was found.`); - return; - } - try { - await command.execute(interaction); + if (interaction.commandName === 'test') + await executeTest(interaction); + else if (interaction.commandName === 'match') + await executeMatch(interaction); } catch (error) { console.error(error); if (interaction.replied || interaction.deferred) { @@ -123,7 +128,7 @@ const jwtClient = new google.auth.JWT( process.env.CLIENT_EMAIL, undefined, process.env.PRIVATE_KEY, - ['https://www.googleapis.com/auth/spreadsheets'] + [ 'https://www.googleapis.com/auth/spreadsheets' ] ); const sheets = google.sheets({ version: 'v4', auth: jwtClient }); @@ -139,7 +144,7 @@ client.on(Events.MessageCreate, async (message) => { let currentFeedbackQuestionIndex = userContext?.currentFeedbackQuestionIndex || 0; // Calculate the column where the answer should be placed. - const columnForAnswer = COLUMNS[currentFeedbackQuestionIndex + 1]; // +1 to skip the first column which might have the userID + const columnForAnswer = COLUMNS[ currentFeedbackQuestionIndex + 1 ]; // +1 to skip the first column which might have the userID // Find the row number for the current user (assuming the user's ID is in the first column) const response = await sheets.spreadsheets.values.get({ @@ -147,7 +152,7 @@ client.on(Events.MessageCreate, async (message) => { range: `${START_COLUMN}:${START_COLUMN}` // search in the first column only }); const rows = response.data.values || []; - let rowIndex = rows.findIndex((row: any) => row[0] === message.author.id.toString()) + 1; // +1 because index is 0-based and rows in Google Sheets are 1-based. + let rowIndex = rows.findIndex((row: any) => row[ 0 ] === message.author.id.toString()) + 1; // +1 because index is 0-based and rows in Google Sheets are 1-based. // If the user is not found, create a new row for them if (rowIndex === 0) { @@ -158,7 +163,7 @@ client.on(Events.MessageCreate, async (message) => { insertDataOption: 'INSERT_ROWS', resource: { values: [ - [message.author.id] // userID in the first column + [ message.author.id ] // userID in the first column ] } } as any); @@ -172,7 +177,7 @@ client.on(Events.MessageCreate, async (message) => { valueInputOption: 'RAW', resource: { values: [ - [message.content] + [ message.content ] ] } } as any); @@ -180,7 +185,7 @@ client.on(Events.MessageCreate, async (message) => { currentFeedbackQuestionIndex++; if (currentFeedbackQuestionIndex < Feedbackquestions.length) { - message.author.send(Feedbackquestions[currentFeedbackQuestionIndex]); + message.author.send(Feedbackquestions[ currentFeedbackQuestionIndex ]); await db.db('contrabot').collection("users").updateOne( { userId: message.author.id }, @@ -206,6 +211,3 @@ client.on(Events.MessageCreate, async (message) => { console.error("Error in Events.MessageCreate:", error); } }); - - -export { client, db }; \ No newline at end of file diff --git a/questions.json b/questions.json new file mode 100644 index 0000000..a723eab --- /dev/null +++ b/questions.json @@ -0,0 +1,40 @@ +[ + { "question": "Auf allen Autobahnen soll ein generelles Tempolimit gelten.", "tag": ["Verkehrssicherheit", " Klimawandel"] }, + { "question": "Deutschland soll seine Verteidigungsausgaben erhöhen.", "tag": "Verteidigungspolitik" }, + { "question": "Bei Bundestagswahlen sollen auch Jugendliche ab 16 Jahren wählen dürfen.", "tag": ["Wahlalter", "Demokratie"] }, + { "question": "Die Förderung von Windenenergie soll beendet werden?", "tag": ["Energiepolitik", "Klimawandel"] }, + { "question": "Die Möglichkeiten der Vermieterinnen und Vermieter, Wohnungsmieten zu erhöhen, sollen gesetzlich stärker begrenzt werden.", "tag": ["Mietpreisbremse", "Wohnraumkosten"] }, + { "question": "Die Ukraine soll Mitglied der Europäischen Union werden dürfen.", "tag": ["EU-Erweiterung", "Ukraine Krieg"] }, + { "question": "Der geplante Ausstieg aus der Kohleverstromung soll vorgezogen werden.", "tag": ["Energiepolitik", "Umweltschutz"] }, + { "question": "Alle Erwerbstätigen sollen in der gesetzlichen Rentenversicherung versichert sein müssen.", "tag": "Sozialpolitik" }, + { "question": "Das Recht anerkannter Flüchtlinge auf Familiennachzug soll abgeschafft werden.", "tag": "Migrationspolitik" }, + { "question": "Auf den Umsatz, der in Deutschland mit digitalen Dienstleistungen erzielt wird, soll eine nationale Steuer erhoben werden.", "tag": "Steuerpolitik" }, + { "question": "Die traditionelle Familie aus Vater, Mutter und Kindern soll stärker als andere Lebensgemeinschaften gefördert werden.", "tag": "Familienpolitik" }, + { "question": "Spenden von Unternehmen an Parteien sollen weiterhin erlaubt sein.", "tag": "Parteienfinanzierung" }, + { "question": "Migration in die Europäische Union sollte erleichtert werden.", "tag": "Migrationspolitik" }, + { "question": "Studentinnen und Studenten sollen BAföG unabhängig vom Einkommen ihrer Eltern erhalten.", "tag": "Bildungspolitik" }, + { "question": "In Deutschland soll es generell möglich sein, neben der deutschen eine zweite Staatsbürgerschaft zu haben.", "tag": ["Staatsbürgerschaft", "Migrationspolitik"] }, + { "question": "Bundesbehörden sollen in ihren Veröffentlichungen unterschiedliche Geschlechtsidentitäten sprachlich berücksichtigen müssen.", "tag": ["Genderpolitik", "Minderheitenpolitik"] }, + { "question": "Der Solidaritätszuschlag soll vollständig abgeschafft werden.", "tag": ["Steuerpolitik", "Solidaritätszuschlag"] }, + { "question": "Das Tragen eines Kopftuchs soll Beamtinnen im Dienst generell erlaubt sein.", "tag": ["Religionsfreiheit", "Minderheitenpolitik"] }, + { "question": "Die Zulassung von neuen Autos mit Verbrennungsmotor soll auch langfristig möglich sein.", "tag": "Klimawandel" }, + { "question": "Der Bund soll mehr Zuständigkeiten in der Schulpolitik erhalten.", "tag": "Bildungspolitik" }, + { "question": "Der Bund soll Projekte zur Bekämpfung des Antisemitismus stärker finanziell unterstützen.", "tag": ["Antisemitismus", "Minderheitenpolitik"] }, + { "question": "Chinesische Firmen sollen keine Aufträge für den Ausbau der Kommunikationsinfrastruktur in Deutschland erhalten dürfen.", "tag": "Wirtschaftspolitik" }, + { "question": "Der Staat soll weiterhin für Religionsgemeinschaften die Kirchensteuer einziehen.", "tag": "Kirchensteuer" }, + { "question": "Der kontrollierte Verkauf von Cannabis soll generell erlaubt sein.", "tag": "Drogenpolitik" }, + { "question": "Deutschland soll aus der Europäischen Union austreten.", "tag": "EU-Politik" }, + { "question": "Die Landeslisten der Parteien für die Wahlen zum Deutschen Bundestag sollen abwechselnd mit Frauen und Männern besetzt werden müssen.", "tag": ["Geschlechtergerechtigkeit", "Minderheitenpolitik"] }, + { "question": "Stationäre Behandlungen im Krankenhaus sollen weiterhin über eine Fallpauschale abgerechnet werden.", "tag": "Gesundheitspolitik" }, + { "question": "Auf hohe Vermögen soll wieder eine Steuer erhoben werden.", "tag": ["Steuerpolitik", "Vermögenssteuer"] }, + { "question": "Bei der Videoüberwachung öffentlicher Plätze soll Gesichtserkennungssoftware eingesetzt werden dürfen.", "tag": ["Datenschutz", "Videoüberwachung"] }, + { "question": "Auch Ehepaare ohne Kinder sollen weiterhin steuerlich begünstigt werden.", "tag": "Familienpolitik" }, + { "question": "Ökologische Landwirtschaft soll stärker gefördert werden als konventionelle Landwirtschaft.", "tag": "Klimawandel" }, + { "question": "Islamische Verbände sollen als Religionsgemeinschaften staatlich anerkannt werden können.", "tag": ["Religionspolitik", "Minderheitenpolitik"] }, + { "question": "Der staatlich festgelegte Preis für den Ausstoß von CO2 beim Heizen und Autofahren soll stärker steigen als geplant.", "tag": ["Klimaschutz", "Klimawandel"] }, + { "question": "Die Schuldenbremse im Grundgesetz soll beibehalten werden.", "tag": "Wirtschaftspolitik" }, + { "question": "Asyl soll weiterhin nur politisch Verfolgten gewährt werden.", "tag": "Migrationspolitik" }, + { "question": "Der gesetzliche Mindestlohn sollte erhöht werden.", "tag": "Sozialpolitik" }, + { "question": "Der Flugverkehr soll höher besteuert werden.", "tag": ["Flugverkehr", "Klimapolitik"] }, + { "question": "Unternehmen sollen selbst entscheiden, ob sie ihren Beschäftigten das Arbeiten im Homeoffice erlauben.", "tag": ["Arbeitsrecht", "Digitalisierung"] } +] diff --git a/questions.ts b/questions.ts deleted file mode 100644 index 25938d6..0000000 --- a/questions.ts +++ /dev/null @@ -1,44 +0,0 @@ -// all questions used in the political test - -const questions = [ - /*{ question: 'Auf allen Autobahnen soll ein generelles Tempolimit gelten.', tag: ['Verkehrssicherheit', ' Klimawandel'] }, - { question: 'Deutschland soll seine Verteidigungsausgaben erhöhen.', tag: 'Verteidigungspolitik' }, - { question: 'Bei Bundestagswahlen sollen auch Jugendliche ab 16 Jahren wählen dürfen.', tag: ['Wahlalter', 'Demokratie'] }, - { question: 'Die Förderung von Windenenergie soll beendet werden?', tag: ['Energiepolitik', 'Klimawandel'] }, - { question: 'Die Möglichkeiten der Vermieterinnen und Vermieter, Wohnungsmieten zu erhöhen, sollen gesetzlich stärker begrenzt werden.', tag: ['Mietpreisbremse', 'Wohnraumkosten'] }, - { question: 'Die Ukraine soll Mitglied der Europäischen Union werden dürfen.', tag: ['EU-Erweiterung', 'Ukraine Krieg'] }, - { question: 'Der geplante Ausstieg aus der Kohleverstromung soll vorgezogen werden.', tag: ['Energiepolitik', 'Umweltschutz'] }, - { question: 'Alle Erwerbstätigen sollen in der gesetzlichen Rentenversicherung versichert sein müssen.', tag: 'Sozialpolitik' }, - { question: 'Das Recht anerkannter Flüchtlinge auf Familiennachzug soll abgeschafft werden.', tag: 'Migrationspolitik' }, - { question: 'Auf den Umsatz, der in Deutschland mit digitalen Dienstleistungen erzielt wird, soll eine nationale Steuer erhoben werden.', tag: 'Steuerpolitik' }, - { question: 'Die traditionelle Familie aus Vater, Mutter und Kindern soll stärker als andere Lebensgemeinschaften gefördert werden.', tag: 'Familienpolitik' }, - { question: 'Spenden von Unternehmen an Parteien sollen weiterhin erlaubt sein.', tag: 'Parteienfinanzierung' }, - { question: 'Migration in die Europäische Union sollte erleichtert werden.', tag: 'Migrationspolitik' }, - { question: 'Studentinnen und Studenten sollen BAföG unabhängig vom Einkommen ihrer Eltern erhalten.', tag: 'Bildungspolitik' }, - { question: 'In Deutschland soll es generell möglich sein, neben der deutschen eine zweite Staatsbürgerschaft zu haben.', tag: ['Staatsbürgerschaft', 'Migrationspolitik'] }, - { question: 'Bundesbehörden sollen in ihren Veröffentlichungen unterschiedliche Geschlechtsidentitäten sprachlich berücksichtigen müssen.', tag: ['Genderpolitik', 'Minderheitenpolitik'] }, - { question: 'Der Solidaritätszuschlag soll vollständig abgeschafft werden.', tag: ['Steuerpolitik', 'Solidaritätszuschlag'] }, - { question: 'Das Tragen eines Kopftuchs soll Beamtinnen im Dienst generell erlaubt sein.', tag: ['Religionsfreiheit', 'Minderheitenpolitik'] }, - { question: 'Die Zulassung von neuen Autos mit Verbrennungsmotor soll auch langfristig möglich sein.', tag: 'Klimawandel' }, - { question: 'Der Bund soll mehr Zuständigkeiten in der Schulpolitik erhalten.', tag: 'Bildungspolitik' }, - { question: 'Der Bund soll Projekte zur Bekämpfung des Antisemitismus stärker finanziell unterstützen.', tag: ['Antisemitismus', 'Minderheitenpolitik'] }, - { question: 'Chinesische Firmen sollen keine Aufträge für den Ausbau der Kommunikationsinfrastruktur in Deutschland erhalten dürfen.', tag: 'Wirtschaftspolitik' }, - { question: 'Der Staat soll weiterhin für Religionsgemeinschaften die Kirchensteuer einziehen.', tag: 'Kirchensteuer' }, - { question: 'Der kontrollierte Verkauf von Cannabis soll generell erlaubt sein.', tag: 'Drogenpolitik' }, - { question: 'Deutschland soll aus der Europäischen Union austreten.', tag: 'EU-Politik' }, - { question: 'Die Landeslisten der Parteien für die Wahlen zum Deutschen Bundestag sollen abwechselnd mit Frauen und Männern besetzt werden müssen.', tag: ['Geschlechtergerechtigkeit', 'Minderheitenpolitik'] }, - { question: 'Stationäre Behandlungen im Krankenhaus sollen weiterhin über eine Fallpauschale abgerechnet werden.', tag: 'Gesundheitspolitik' }, - { question: 'Auf hohe Vermögen soll wieder eine Steuer erhoben werden.', tag: ['Steuerpolitik', 'Vermögenssteuer'] }, - { question: 'Bei der Videoüberwachung öffentlicher Plätze soll Gesichtserkennungssoftware eingesetzt werden dürfen.', tag: ['Datenschutz', 'Videoüberwachung'] }, - { question: 'Auch Ehepaare ohne Kinder sollen weiterhin steuerlich begünstigt werden.', tag: 'Familienpolitik' }, - { question: 'Ökologische Landwirtschaft soll stärker gefördert werden als konventionelle Landwirtschaft.', tag: 'Klimawandel' }, - */{ question: 'Islamische Verbände sollen als Religionsgemeinschaften staatlich anerkannt werden können.', tag: ['Religionspolitik', 'Minderheitenpolitik'] }, - { question: 'Der staatlich festgelegte Preis für den Ausstoß von CO2 beim Heizen und Autofahren soll stärker steigen als geplant.', tag: ['Klimaschutz', 'Klimawandel'] }, - { question: 'Die Schuldenbremse im Grundgesetz soll beibehalten werden.', tag: 'Wirtschaftspolitik' }, - { question: 'Asyl soll weiterhin nur politisch Verfolgten gewährt werden.', tag: 'Migrationspolitik' }, - { question: 'Der gesetzliche Mindestlohn sollte erhöht werden.', tag: 'Sozialpolitik' }, - { question: 'Der Flugverkehr soll höher besteuert werden.', tag: ['Flugverkehr', 'Klimapolitik'] }, - { question: 'Unternehmen sollen selbst entscheiden, ob sie ihren Beschäftigten das Arbeiten im Homeoffice erlauben.', tag: ['Arbeitsrecht', 'Digitalisierung'] }, -]; - -export default questions;