Răsfoiți Sursa

Stuck on ascyncpg issue not present in psycopg2

Double-Vee 3 ani în urmă
părinte
comite
5aedc75d69

+ 4 - 1
README.md

@@ -13,7 +13,10 @@ A Discord robot for the Angels Discord written in Python.
 1. Activate virutal environment: `source bin/activate`
 1. Install required packages: `pip3 install -r requirements.txt`
 
-## Run
+### Web interface
+Expose django to the web. (TODO: more details)
+
+## Run bot
 1. Activate virutal environment: `source bin/activate`
 1. Change into the bot directory: `cd bot`
 1. `python rotbot.py`

+ 20 - 7
bot/commands/admin.py

@@ -1,8 +1,12 @@
 #import discord
 import secrets
 from discord.ext import commands
-import local_settings as settings
+from local_settings import WEB_SCHEME, WEB_HOST
+from query.guild_access_token import get_active_token, upsert_token
+from common.datetime import plus10min
 
+def setup(bot: commands.Bot):
+	bot.add_cog(Admin(bot))
 
 class Admin(commands.Cog):
 	"""Administrative functionality."""
@@ -15,9 +19,18 @@ class Admin(commands.Cog):
 		brief="Set channel specific settings via the webgui",
 		help="Sends a single-use time based token to the webportal"
 	)
-	async def chanset(self, ctx: commands.Context, *, text: str):
-		pass
-		token = secrets.token_urlsafe(40)[:40]
-		# Check for active token
-		# Upsert token 
-		#await "%s://%s/foo/%s", setting.WEB_SCHEME, setting.WEB_HOST, token
+	async def chanset(self, ctx: commands.Context):
+		
+
+		#id, token, user_id, created = get_active_token(self.bot.pg, ctx.guild.id)
+		record = await get_active_token(self.bot.pg, ctx.guild.id)
+		print(record)
+
+		if record:	# Check for active token
+			await ctx.send(f"Token {record['id']} is in use by {record['user']} until {plus10min(record['created'])}.")
+		else: 
+			token = secrets.token_urlsafe(40)[:40]
+			await upsert_token(self.bot.pg, ctx.guild.id, ctx.author.id, token)
+
+			await ctx.author.send(f"{WEB_SCHEME}://{WEB_HOST}/config/channel-settings/{token}")	# DM token
+			await ctx.send("Your access token has been sent to you in a private DM.")

+ 1 - 0
bot/commands/games.py

@@ -79,5 +79,6 @@ class Games(commands.Cog):
 				"Ask again later.",
 				"I don't know.",
 				"Unpredictable.",
+				"Unkown",
 			]
 		await ctx.send(random.choice(messages))

+ 7 - 0
bot/common/datetime.py

@@ -0,0 +1,7 @@
+import datetime
+
+def min10min(before):
+	return before - datetime.timedelta(minutes=10)
+
+def plus10min(after):
+	return after + datetime.timedelta(minutes=10)

+ 6 - 3
bot/events/general.py

@@ -37,9 +37,12 @@ class General(commands.Cog):
 			await upsert_total_messages(self.bot.pg,message.channel.id, message.author.id)
 		except asyncpg.exceptions.ForeignKeyViolationError:
 			try:
+				print(message)
+				print(message.channel)
+				print(message.guild)
 				await insert_channel(self.bot.pg, message.channel.id, message.guild.id)
 			except asyncpg.exceptions.ForeignKeyViolationError:
-				await update_guild(self.bot.pg, message.guild)
+				await update_guild(self.bot.pg, message.guild.id)
 		
 		# Do not respond to one self.
 		if self.bot.user == message.author:
@@ -49,8 +52,8 @@ class General(commands.Cog):
 		if self.bot.user.mentioned_in(message):
 			print("mentioned in ")
 			print(message.channel)
-			#interact = get_interact
-			print(interact)
+			#interact = get_interact()
+			#print(interact)
 			#if interact:
 			if get_interact(self.bot.pg, message.channel.id):
 				messages = [

+ 68 - 67
bot/main.py

@@ -4,94 +4,94 @@ from os.path import exists
 
 # Hint how to edit the settings and quit
 def hint_quit():
-    logging.info("")
-    logging.info("    edit local_settings.py")
-    logging.info("")
-    quit()
+	logging.info("")
+	logging.info("    edit local_settings.py")
+	logging.info("")
+	quit()
 
 # Copy or create settings file if missing
 def missing_config():
-    logging.basicConfig(level=logging.DEBUG)
-    if not exists("local_settings.py"):
-        logging.error("Settings file not found.")
-        logging.info("Copying local_settings_example.py to local_settings.py")
-        try:
-            os.rename("local_settings_example.py", "local_settings.py")
-        except FileNotFoundError:
-            logging.info("local_settings_example.py not found, creating local_settings.py")
-            with open("local_settings.py", "w") as settings_file:
-                settings_file.writelines(
-                    [
-                        "import logging",
-                        "LOG_LEVEL = logging.INFO	# Options: CRITICAL, ERROR, WARNING, INFO, and DEBUG",
-                        "",
-                        "DATABASE_NAME = \"\"",
-                        "DATABASE_USER = \"\"",
-                        "DATABASE_HOST = \"\"",
-                        "DATABASE_PASSWORD = \"\"",
-                        "",
-                        "WEB_HOST = \"\"",
-                        "WEB_SCHEME = \"\"",
-                        "",
-                        "DISCORD_TOKEN = \"\"",
-                        "COMMAND_PREFIX = \"\"",
-                    ]
-                )
-    logging.error("Settings undefined.")
-    logging.info("Configure the settings:")
-    hint_quit()
+	logging.basicConfig(level=logging.DEBUG)
+	if not exists("local_settings.py"):
+		logging.error("Settings file not found.")
+		logging.info("Copying local_settings_example.py to local_settings.py")
+		try:
+			os.rename("local_settings_example.py", "local_settings.py")
+		except FileNotFoundError:
+			logging.info("local_settings_example.py not found, creating local_settings.py")
+			with open("local_settings.py", "w") as settings_file:
+				settings_file.writelines(
+					[
+						"import logging",
+						"LOG_LEVEL = logging.INFO	# Options: CRITICAL, ERROR, WARNING, INFO, and DEBUG",
+						"",
+						"DATABASE_NAME = \"\"",
+						"DATABASE_USER = \"\"",
+						"DATABASE_HOST = \"\"",
+						"DATABASE_PASSWORD = \"\"",
+						"",
+						"WEB_HOST = \"\"",
+						"WEB_SCHEME = \"\"",
+						"",
+						"DISCORD_TOKEN = \"\"",
+						"COMMAND_PREFIX = \"\"",
+					]
+				)
+	logging.error("Settings undefined.")
+	logging.info("Configure the settings:")
+	hint_quit()
 
 # Hint to correct specific setting and quit
 def correct_setting(setting):
-    logging.info("Correct the %s in local_settings.py", setting)
-    hint_quit()
+	logging.info("Correct the %s in local_settings.py", setting)
+	hint_quit()
 
 # Import settings
 try:
-    import local_settings as settings   # Environment dependant settings stored in local_settings.py, untracked by .gitinore
+	import local_settings as settings   # Environment dependant settings stored in local_settings.py, untracked by .gitinore
 except ModuleNotFoundError:
-    missing_config()
+	missing_config()
 
 # Check additional settings
 if not settings.WEB_HOST:
-    logging.error("Web host undefinded.")
-    correct_setting("WEB_HOST")
-    
+	logging.error("Web host undefinded.")
+	correct_setting("WEB_HOST")
+	
 if not settings.WEB_SCHEME:
-    logging.error("Web scheme undefinded.")
-    correct_setting("WEB_SCHEME")
+	logging.error("Web scheme undefinded.")
+	correct_setting("WEB_SCHEME")
 
 # Set loglevel
 try:
-    logging.basicConfig(level=settings.LOG_LEVEL)
+	logging.basicConfig(level=settings.LOG_LEVEL)
 except AttributeError:
-    missing_config()
+	missing_config()
 
 # Define database pool
 import asyncpg
 async def create_db_pool():
-    try:
-        bot.pg = await asyncpg.create_pool(
-            database=settings.DATABASE_NAME,
-            user=settings.DATABASE_USER,
-            host=settings.DATABASE_HOST,
-            password=settings.DATABASE_PASSWORD,
-        )
-    except AttributeError:
-        missing_config()
+	try:
+		bot.pg = await asyncpg.create_pool(
+			database=settings.DATABASE_NAME,
+			user=settings.DATABASE_USER,
+			host=settings.DATABASE_HOST,
+			password=settings.DATABASE_PASSWORD,
+		)
+	except AttributeError:
+		missing_config()
 
 # Create robot
 import discord
 from discord.ext import commands
 try:
-    bot = commands.Bot(
-        command_prefix = settings.COMMAND_PREFIX,
-        description = "Charlie's Angels bot",
-        intents = discord.Intents.default(),    # Required: Guilds
-        case_insensitive = True,
-    )
+	bot = commands.Bot(
+		command_prefix = settings.COMMAND_PREFIX,
+		description = "Charlie's Angels bot",
+		intents = discord.Intents.default(),    # Required: Guilds
+		case_insensitive = True,
+	)
 except AttributeError:
-    missing_config()
+	missing_config()
 
 # Create database pool
 bot.loop.run_until_complete(create_db_pool())
@@ -102,18 +102,19 @@ bot.loop.run_until_complete(init_db(bot.pg))
 
 # Load extensions
 default_extensions = [
-  "commands.general",
-  "commands.games",
-  "events.general",
+	"commands.admin",
+	"commands.games",
+	"commands.general",
+	"events.general",
 ]
 for ext in default_extensions:
   bot.load_extension(ext)
 
 # Run robot
 try:
-    bot.run(settings.DISCORD_TOKEN)
+	bot.run(settings.DISCORD_TOKEN)
 except AttributeError:
-    missing_config()
+	missing_config()
 except discord.errors.LoginFailure:
-    logging.error("Invalid discord token.")
-    correct_setting("DISCORD_TOKEN")
+	logging.error("Invalid discord token.")
+	correct_setting("DISCORD_TOKEN")

+ 0 - 2
bot/query/access_token.py

@@ -1,2 +0,0 @@
-#async def insert_channel(pg,):
-#	await pg.execute("INSERT INTO access_token(channel_id, guild) VALUES($1, $2)", channel_id, guild_id)

+ 17 - 0
bot/query/guild_access_token.py

@@ -0,0 +1,17 @@
+import datetime, asyncpg
+from common.datetime import min10min
+from query.guild import update_guild
+
+async def get_active_token(pg, guild_id):
+	return await pg.fetchrow("SELECT * FROM guild_access_token WHERE guild=$1 AND created > $2", guild_id, min10min(datetime.datetime.now()))
+
+async def upsert_token(pg, guild_id, user_id, token):
+	print(type(token))
+	print(token)
+	try:
+		await pg.execute("INSERT INTO guild_access_token(guild, \"user\", token) VALUES($1, $2, $3)", guild_id, user_id, token).bindparams(bindparam("token", type_=String))
+		# ON CONFLICT() DO UPDATE SET \"user\"=$1 AND token=$2", user_id, token)
+	except asyncpg.exceptions.ForeignKeyViolationError:
+		await update_guild(self.bot.pg, message.guild)
+		await pg.execute("INSERT INTO guild_access_token(guild, \"user\", token) VALUES($1, $2, $3)", guild_id, user_id, token)
+		# ON CONFLICT() DO UPDATE SET \"user\"=$1 AND token=$2", user_id, token)

+ 1 - 1
bot/query/initialise_database.py

@@ -4,7 +4,7 @@ async def init_db(pg):
         "CREATE TABLE IF NOT EXISTS channel (id SERIAL PRIMARY KEY, channel_id BIGINT UNIQUE NOT NULL, guild BIGINT REFERENCES guild (guild_id))",
         "CREATE TABLE IF NOT EXISTS channel_settings (id SERIAL PRIMARY KEY, channel BIGINT UNIQUE NOT NULL REFERENCES channel (channel_id), guild BIGINT REFERENCES guild (guild_id), interact BOOL DEFAULT FALSE)",
         "CREATE TABLE IF NOT EXISTS \"user\" (id SERIAL PRIMARY KEY, user_id BIGINT UNIQUE NOT NULL)",
-        "CREATE TABLE IF NOT EXISTS access_token (id SERIAL PRIMARY KEY, guild BIGINT REFERENCES guild (guild_id), \"user\" BIGINT NOT NULL REFERENCES \"user\" (user_id), token char[40] UNIQUE NOT NULL, created TIMESTAMP NOT NULL DEFAULT now())",
+        "CREATE TABLE IF NOT EXISTS guild_access_token (id SERIAL PRIMARY KEY, guild BIGINT REFERENCES guild (guild_id), \"user\" BIGINT NOT NULL REFERENCES \"user\" (user_id), token varchar[40] UNIQUE NOT NULL, created TIMESTAMP NOT NULL DEFAULT now())",
         "CREATE TABLE IF NOT EXISTS channel_user (id SERIAL PRIMARY KEY, channel BIGINT NOT NULL REFERENCES channel (channel_id), \"user\" BIGINT NOT NULL REFERENCES \"user\" (user_id), total_messages BIGINT DEFAULT 1, UNIQUE (channel, \"user\"))",
     ]
     for query in queries: