diff --git a/DiscordVerifier/src/Main.java b/DiscordVerifier/src/Main.java index e72bfef..f3c92e6 100755 --- a/DiscordVerifier/src/Main.java +++ b/DiscordVerifier/src/Main.java @@ -14,9 +14,12 @@ public class Main extends JavaPlugin { Thread serversocket; Thread uuidServerThread; + ServerSocket uuidServerSocket; ServerSocket chatServerSocket; + DatabaseConnection dbConn; + public void onEnable() { getLogger().info("DiscordVerifier Plugin enabled"); PluginManager pm = getServer().getPluginManager(); @@ -24,6 +27,13 @@ public class Main extends JavaPlugin { start_socketserver(); start_uuid_server(); + this.dbConn = new DatabaseConnection(); + + + RedeemCommandListeners redeemcommands = new RedeemCommandListeners(dbConn); + getCommand(redeemcommands.cmd1).setExecutor(redeemcommands); + + } public void start_uuid_server(){ diff --git a/DiscordVerifier/src/RedeemCommandListeners.java b/DiscordVerifier/src/RedeemCommandListeners.java new file mode 100644 index 0000000..21e3df8 --- /dev/null +++ b/DiscordVerifier/src/RedeemCommandListeners.java @@ -0,0 +1,52 @@ +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.event.Listener; + +public class RedeemCommandListeners implements Listener, CommandExecutor { + + public String cmd1 = "redeem"; + private DatabaseConnection dbConn; + + public RedeemCommandListeners(DatabaseConnection dbConn){ + this.dbConn = dbConn; + } + + @Override + public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args){ + + if(sender instanceof Player){ + if(cmd.getName().equalsIgnoreCase(cmd1)){ + Player p = ((Player)sender); + + String discordid = dbConn.get_discord_id(p); + if (discordid != null){ + int rewards = dbConn.get_reward(discordid); + if (rewards != -1){ + + dbConn.remove_toclaim(discordid); + Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "eco give " + p.getName() + rewards); + p.sendMessage(ChatColor.GREEN + "You received " + rewards + " dollars!"); + return true; + + }else{ + p.sendMessage(ChatColor.RED + "You have no money to claim!"); + } + }else{ + p.sendMessage(ChatColor.RED + "Your account is not linked with discord"); + } + + return true; + } + }else{ + sender.sendMessage(ChatColor.RED + "Only players can use this command!"); + return true; + } + + return false; + } + +} diff --git a/DiscordVerifier/src/plugin.yml b/DiscordVerifier/src/plugin.yml index 7eb3e50..ad77808 100755 --- a/DiscordVerifier/src/plugin.yml +++ b/DiscordVerifier/src/plugin.yml @@ -1,5 +1,9 @@ name: DiscordVerifier main: Main -version: 0.0.1 +version: 0.0.2 description: Verify Mincraftnames api-version: 1.13 +commands: + redeem: + usage: / + description: Redeems the money won in discord diff --git a/cogs/playerlink.py b/cogs/playerlink.py index 2927fae..1fd3d73 100755 --- a/cogs/playerlink.py +++ b/cogs/playerlink.py @@ -5,6 +5,7 @@ import string import socket import asyncio import threading +from functions.timer import Timer from data import constants from data.DatabaseConnection import * @@ -97,13 +98,13 @@ class PlayerLink(commands.Cog): embed.colour = discord.Colour.orange() return embed - async def update_timer(timer, message): + + async def send_timer_messages(timer, message): while (not timer.ended): - await asyncio.sleep(1) - timer.update() # maybe create a task from this because this takes some time -> timer not accurate if ((timer.minutes < 2 and timer.seconds == 59) or (timer.minutes == 0 and timer.seconds == 0)): asyncio.create_task(message.edit(embed=create_embed(ctx.author, arg, timer))) + await asyncio.sleep(1) try: @@ -111,14 +112,15 @@ class PlayerLink(commands.Cog): uuid = get_player_uuid(arg) send_chat(ctx.author.name, arg, code) #message_send_time = - timer = Timer() + timer = Timer(2, 0) + timer.start() + message = await ctx.send(embed=create_embed(ctx.author, arg, timer)) - # Start timer in background - task = asyncio.create_task(update_timer(timer, message)) + task = asyncio.create_task(send_timer_messages(timer, message)) # Wait for the code response - msg = await self.client.wait_for('message', check=check) + msg = await self.client.wait_for('message', check=check, timeout=120) if msg.content == code: @@ -126,22 +128,21 @@ class PlayerLink(commands.Cog): try: dbLinker.linkPlayer(uuid, authorid) await ctx.author.add_roles(self.get_linked_role()) - timer.ended = True + timer.stop() await message.edit(embed=create_embed(ctx.author, arg, timer, success=True)) except SQLInsertError: await message.edit(embed=create_embed(ctx.author, arg, timer)) finally: - dbLinker.closeconnections() + dbLinker.close() else: # this stops the timer task - task.cancel() - timer.ended = True + timer.stop() await message.edit(embed=create_embed(ctx.author, arg, timer, WrongCodeError())) except PlayerError: await ctx.send("Player '" + arg + "' not found") - #except: - # await ctx.send("Something went wrong") + except: + await ctx.send("Something went wrong") @commands.command(name="Unlink") async def unlink(self, ctx, arg): @@ -158,23 +159,7 @@ class PlayerLink(commands.Cog): except PlayerNotLinked: await ctx.send("Player not linked!") finally: - dbLinker.closeconnections() - - -class Timer(): - def __init__(self): - self.minutes = 2 - self.seconds = 0 - self.ended = False - - def update(self): - if (self.minutes > 0 and self.seconds == 0): - self.minutes -= 1 - self.seconds = 59 - elif (self.seconds > 0): - self.seconds -= 1 - if (self.minutes == 0 and self.seconds == 0): - self.ended = True + dbLinker.close() def setup(client): diff --git a/cogs/quiz.py b/cogs/quiz.py new file mode 100644 index 0000000..40c4f14 --- /dev/null +++ b/cogs/quiz.py @@ -0,0 +1,177 @@ +import discord +from discord.ext import commands +from data import constants +import asyncio +import threading +import random +from functions.timer import Timer +from data.DatabaseConnection import * +from functions import checks + +class QuizQuestions(commands.Cog): + def __init__(self, client): + self.client = client + + @commands.group(name="q&a",case_insensitive=True, invoke_without_command=True) + @commands.check(checks.isModPlus) + # /q&a add "What is ...." "Australia" + async def questions(self, ctx, f, *args): + if (f == "add"): + if (len(args) == 2): + await self.add_question(ctx, args[0], args[1]) + elif (len(args) == 3): + await self.add_question(ctx, args[0], args[1], args[2]) + else: + await ctx.send("Wrong amount of arguments") + elif (f == "rm"): + if (len(args) == 1): + await self.rm_question(ctx, args[0]) + else: + await ctx.send("Wrong amount of arguments") + elif (f == "show"): + if (len(args) == 0): + await self.show_questions(ctx) + else: + await ctx.send("Wrong amount of arguments") + + async def add_question(self, ctx, q, a, reward=50): + try: + quizdb = QuizDB() + q_id = quizdb.add_question(q, a, reward) + await ctx.send("question id: " + str(q_id)) + # except: + # await ctx.send("Something went wrong") + finally: + quizdb.close() + + async def rm_question(self, ctx, id): + try: + quizdb = QuizDB() + quizdb.rm_question(id) + await ctx.send("question removed") + except QuestionNotFound: + await ctx.send("No question found with id " + str(id)) + # except: + # await ctx.send("Something went wrong") + finally: + quizdb.close() + + async def show_questions(self, ctx): + try: + quizdb = QuizDB() + questions = quizdb.get_questions() + if len(questions) == 0: + await ctx.send("No questions found") + else: + message = "" + for q in questions: + message += f"id: {q[0]}, question: '{q[1]}', answer: '{q[2]}', reward: {q[3]}, used: {q[4]}\n" + await ctx.send(message) + except: + await ctx.send("Something went wrong") + finally: + quizdb.close() + +class Quiz(commands.Cog): + def __init__(self, client): + self.client = client + self.in_progress = False + #self.interval = (5, 10) + self.interval = (8*60, 30*60) + self.auto = False + + @commands.command(name="quiz") + @commands.check(checks.isModPlus) + async def quiz_bot(self, ctx, f, *args): + if (f == "auto" and not self.auto): + self.auto = True + asyncio.create_task(self.start_auto_quiz()) + elif (f == "stop" and self.auto): + self.auto = False + + async def start_auto_quiz(self): + while self.auto: + await asyncio.sleep(random.randint(self.interval[0], self.interval[1])) + await self.ask_question() + + @commands.Cog.listener() + async def on_ready(self): + self.auto = True + casyncio.create_task(self.start_auto_quiz() + + async def ask_question(self): + + self.question = self.get_random_question() + + self.increment_asked_count(self.question[0]) + + channel = self.client.get_channel(constants.QuizChannelID) + self.in_progress = True + answer_timer = Timer(1, 0) + + embed = discord.Embed() + #embed.set_author(name="Quiz") + embed.colour = discord.Colour.orange() + + embed.add_field(name="Question:", value=f"{self.question[1]}", inline=False) + embed.add_field(name="Reward:", value=f"${self.question[3]}", inline=False) + self.embed = embed + await channel.send(embed=embed) + answer_timer.start() + while not answer_timer.ended and self.in_progress: + await asyncio.sleep(1) + if (not answer_timer.ended): + answer_timer.stop() + else: + self.in_progress = False + embed.colour = discord.Colour.red() + embed.add_field(name="Answer:", value=f"{self.question[2]}", inline=False) + await channel.send(embed=embed) + + + @commands.Cog.listener() + async def on_message(self, message): + if message.author == self.client.user: + return + if self.in_progress and message.channel.id == constants.QuizChannelID: + if message.content.lower() == self.question[2].lower(): + self.in_progress = False + + self.give_reward(message.author.id, self.question[3]) + + playerdblinker = PlayerDBLinker() + self.embed.colour = discord.Colour.green() + if playerdblinker.discordidused(message.author.id): + self.embed.add_field(name="Answer:", value=f"{self.question[2]}", inline=False) + self.embed.add_field(name="Winner:", value=f"{message.author.mention} 🎉🎉", inline=False) + #self.embed.add_field(name="Claim:", value=f"Claim your reward in Minecraft by using /redeem") + self.embed.add_field(name="Claim:", value=f"Claim your reward in Minecraft when the server is online") + await message.channel.send(embed=self.embed) + else: + self.embed.add_field(name="Answer:", value=f"{self.question[2]}", inline=False) + self.embed.add_field(name="Winner:", value=f"{message.author.mention} 🎉🎉", inline=False) + #self.embed.add_field(name="Claim:", value=f"1. Link your account by using /link \n2. Claim your reward in Minecraft by using /redeem") + self.embed.add_field(name="Claim:", value=f"Claim your reward in Minecraft when the server is online") + await message.channel.send(embed=self.embed) + playerdblinker.close() + + def increment_asked_count(self, q_id): + quizdb = QuizDB() + quizdb.question_asked_increment(q_id) + quizdb.close() + + def get_random_question(self): + quizdb = QuizDB() + q = quizdb.get_random_question() + quizdb.close() + return q + + def give_reward(self, discordid, reward): + quiz_players_db = QuizPlayersDB() + quiz_players_db.player_won(discordid, reward) + quiz_players_db.close() + + +def setup(client): + client.add_cog(QuizQuestions(client)) + client.add_cog(Quiz(client)) diff --git a/data/DatabaseConnection.py b/data/DatabaseConnection.py index 72ee79c..e21b107 100755 --- a/data/DatabaseConnection.py +++ b/data/DatabaseConnection.py @@ -8,6 +8,10 @@ class UnLinkError(Exception): pass class PlayerNotLinked(Exception): pass +class QuestionNotFound(Exception): + pass +class PlayerNotFound(Exception): + pass class DatabaseConnection: # databases -> worldcraft and worldcraft_discord @@ -26,6 +30,13 @@ class DatabaseConnection: password="@fZQ6Uu3+U^WH1i2JNemgTC7", database=database ) + elif database == "s13_ecobridge": + self.mydb = mysql.connector.connect( + host="192.168.1.251", + user="u13_H9QOWK3I5x", + password="^K2HjsLeTtPTl9+Ek.Y21p7S", + database=database + ) self.cursor = self.mydb.cursor() @@ -38,6 +49,96 @@ class DatabaseConnection: def close(self): self.mydb.close() +class QuizPlayersDB: + def __init__(self, conn=None): + self.tablename = "quizplayers" + if (conn is not None): + self.discorddbconn = conn + else: + self.discorddbconn = DatabaseConnection(database="worldcraft_discord") + cursor = self.discorddbconn.get_cursor() + cursor.execute("create table IF NOT EXISTS {} (discordid tinytext NOT NULL, wins int DEFAULT 0, rewards int DEFAULT 0, toclaim int DEFAULT 0)".format(self.tablename)) + + def player_exists(self, discordid): + cursor = self.discorddbconn.get_cursor() + sql = f"SELECT count(*) FROM {self.tablename} WHERE discordid={str(discordid)}" + cursor.execute(sql) + res = cursor.fetchone() + return res[0] == 1 + + + def player_won(self, discordid, reward): + cursor = self.discorddbconn.get_cursor() + if self.player_exists(discordid): + sql = f"UPDATE {self.tablename} SET wins = wins + 1, rewards = rewards + {str(reward)}, toclaim = toclaim + {str(reward)} WHERE discordid = {str(discordid)}" + cursor.execute(sql) + else: + sql = f"INSERT INTO {self.tablename} (discordid, wins, rewards, toclaim) VALUES ({str(discordid)}, 1, {reward}, {reward})" + cursor.execute(sql) + self.discorddbconn.get_db().commit() + + def close(self): + self.discorddbconn.close() + +class QuizDB: + def __init__(self): + self.tablename = "questions" + self.discorddbconn = DatabaseConnection(database="worldcraft_discord") + cursor = self.discorddbconn.get_cursor() + cursor.execute("create table IF NOT EXISTS {} (id int NOT NULL PRIMARY KEY AUTO_INCREMENT, question text NOT NULL, answer text NOT NULL, reward int NOT NULL, asked int DEFAULT 0)".format(self.tablename)) + + def add_question(self, question, answer, reward): + cursor = self.discorddbconn.get_cursor() + sql = f"insert into {self.tablename} (question, answer, reward) VALUES ('{question}', '{answer}', {str(reward)})" + try: + cursor.execute(sql) + self.discorddbconn.get_db().commit() + return cursor.lastrowid + except: + raise SQLInsertError() + + def rm_question(self, id): + cursor = self.discorddbconn.get_cursor() + cursor.execute("select count(*) from {} where id={}".format(self.tablename, str(id))) + res = cursor.fetchone() + if res[0] == 1: + sql = f"DELETE FROM {self.tablename} WHERE id = {str(id)}" + cursor.execute(sql) + self.discorddbconn.get_db().commit() + else: + raise QuestionNotFound() + + def get_questions(self): + cursor = self.discorddbconn.get_cursor() + sql = f"SELECT * FROM {self.tablename}" + cursor.execute(sql) + return list(cursor.fetchall()) + + def count_questions(self): + cursor = self.discorddbconn.get_cursor() + cursor.execute("select count(*) from {}".format(self.tablename)) + res = cursor.fetchone() + return res[0] + + def question_asked_increment(self, q_id): + cursor = self.discorddbconn.get_cursor() + sql = f"UPDATE {self.tablename} SET asked = asked + 1 WHERE id = {str(q_id)}" + cursor.execute(sql) + self.discorddbconn.get_db().commit() + + + def get_random_question(self): + if self.count_questions() != 0: + cursor = self.discorddbconn.get_cursor() + sql = f"SELECT * FROM {self.tablename} ORDER BY RAND() LIMIT 1" + cursor.execute(sql) + return list(cursor.fetchone()) + else: + raise QuestionNotFound() + + def close(self): + self.discorddbconn.close() + # this will save the uuid of the player and discord id class PlayerDBLinker: def __init__(self): @@ -66,6 +167,12 @@ class PlayerDBLinker: res = cursor.fetchone() return res[0] >= 1 + def get_minecraftUUID(self, discordid): + cursor = self.discorddbconn.get_cursor() + cursor.execute("select minecraftUUID from {} where discordid='{}'".format(self.tablename, discordid)) + res = cursor.fetchone() + return res[0] + def linkPlayer(self, minecraftUUID, discordid): cursor = self.discorddbconn.get_cursor() sql = "insert into {} (minecraftUUID, discordid) VALUES (%s, %s)".format(self.tablename) @@ -74,10 +181,10 @@ class PlayerDBLinker: try: cursor.execute(sql, val) self.discorddbconn.get_db().commit() + except: raise SQLInsertError() - def unlinkPlayer(self, minecraftname, discordid): # get uuid from server database -> check if in linkerdatabase serverdb_cursor = self.serverdbconn.get_cursor() @@ -95,6 +202,6 @@ class PlayerDBLinker: else: raise PlayerNotLinked() - def closeconnections(self): + def close(self): self.discorddbconn.close() self.serverdbconn.close() diff --git a/data/constants.py b/data/constants.py index f9a9d52..c9ba5d4 100755 --- a/data/constants.py +++ b/data/constants.py @@ -20,3 +20,4 @@ modPlusRoles = [roleAdmin, roleMod, roleOwner] # Channels ModLogs = 760807882899193867 +QuizChannelID = 774418250665951232 diff --git a/functions/timer.py b/functions/timer.py new file mode 100644 index 0000000..e0ae1fb --- /dev/null +++ b/functions/timer.py @@ -0,0 +1,26 @@ +import asyncio + +class Timer(): + def __init__(self, minutes, seconds): + self.minutes = minutes + self.seconds = seconds + self.ended = True + + def start(self): + self.ended = False + self.timer_task = asyncio.ensure_future(self.update()) + + def stop(self): + self.timer_task.cancel() + self.endend = True + + async def update(self): + while self.ended == False: + await asyncio.sleep(1) + if (self.minutes > 0 and self.seconds == 0): + self.minutes -= 1 + self.seconds = 59 + elif (self.seconds > 0): + self.seconds -= 1 + if (self.minutes == 0 and self.seconds == 0): + self.ended = True