Switch database type to PostgreSQL

This commit is contained in:
Noikoio 2018-11-01 19:05:21 -07:00
parent 2735fcb454
commit b57a7b9b37
5 changed files with 56 additions and 46 deletions

View file

@ -7,6 +7,6 @@ A common problem since the beginning of the Internet: You find yourself in an on
This bot aims to answer the age-old question, "What time is it for everyone?" Users specify their time zones. Others users can then ask the bot what time it is for a person in particular, or get an overview of the most common time zones amongst recently active members.
## Setup
1. Install the necessary dependencies: `pytz`, `sqlite3`, and `discord.py` (rewrite branch).
2. Copy `settings_default.py` to `settings.py` and set your bot token.
3. Run `worldtime.py` using Python 3.
1. Install the necessary dependencies: `pytz`, `psycopg2`, and `discord.py` (rewrite branch).
2. Copy `settings_default.py` to `settings.py` and configure as needed.
3. Run `worldtime.py`.

View file

@ -12,7 +12,7 @@ from commands import WtCommands
class WorldTime(discord.Client):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.userdb = UserDatabase('users.db')
self.userdb = UserDatabase(settings.PgConnectionString)
self.commands = WtCommands(self.userdb, self)
self.bg_task = self.loop.create_task(self.periodic_report())

View file

@ -1,4 +1,8 @@
# WorldTime instance settings
# Bot token. Required to run.
BotToken = ''
BotToken = ''
# PostgreSQL connection string.
# More information: https://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING
PgConnectionString = ''

View file

@ -1,18 +1,22 @@
# User database abstractions
import sqlite3
import psycopg2
class UserDatabase:
def __init__(self, dbname):
def __init__(self, connstr):
'''
Sets up the SQLite session for the user database.
Sets up the PostgreSQL connection to be used by this instance.
'''
self.db = sqlite3.connect(dbname)
self.db = psycopg2.connect(connstr)
cur = self.db.cursor()
cur.execute('''CREATE TABLE IF NOT EXISTS users(
guild TEXT, user TEXT, zone TEXT, lastactive INTEGER,
PRIMARY KEY (guild, user)
)''')
cur.execute("""
CREATE TABLE IF NOT EXISTS userdata (
guild_id BIGINT,
user_id BIGINT,
zone TEXT NOT NULL,
last_active TIMESTAMPTZ NOT NULL DEFAULT now(),
PRIMARY KEY (guild_id, user_id)
)""")
self.db.commit()
cur.close()
@ -21,10 +25,10 @@ class UserDatabase:
If a user exists in the database, updates their last activity timestamp.
'''
c = self.db.cursor()
c.execute('''
UPDATE users SET lastactive = strftime('%s', 'now')
WHERE guild = '{0}' AND user = '{1}'
'''.format(serverid, authorid))
c.execute("""
UPDATE userdata SET last_active = now()
WHERE guild_id = %s AND user_id = %s
""", (serverid, authorid))
self.db.commit()
c.close()
@ -33,10 +37,10 @@ class UserDatabase:
Deletes existing user from the database.
'''
c = self.db.cursor()
c.execute('''
DELETE FROM users
WHERE guild = '{0}' AND user = '{1}'
'''.format(serverid, authorid))
c.execute("""
DELETE FROM userdata
WHERE guild_id = %s AND user_id = %s
""", (serverid, authorid))
self.db.commit()
c.close()
@ -48,10 +52,12 @@ class UserDatabase:
'''
self.delete_user(serverid, authorid)
c = self.db.cursor()
c.execute('''
INSERT INTO users VALUES
('{0}', '{1}', '{2}', strftime('%s', 'now'))
'''.format(serverid, authorid, zone))
c.execute("""
INSERT INTO userdata (guild_id, user_id, zone) VALUES
(%s, %s, %s)
ON CONFLICT (guild_id, user_id)
DO UPDATE SET zone = EXCLUDED.zone
""", (serverid, authorid, zone))
self.db.commit()
c.close()
@ -62,18 +68,18 @@ class UserDatabase:
'''
c = self.db.cursor()
if userid is None:
c.execute('''
SELECT zone, count(*) as ct FROM users
WHERE guild = '{0}'
AND lastactive >= strftime('%s','now') - (72 * 60 * 60) -- only users active in the last 72 hrs
c.execute("""
SELECT zone, count(*) as ct FROM userdata
WHERE guild_id = %s
AND last_active >= now() - INTERVAL '72 HOURS' -- only users active in the last 72 hrs
GROUP BY zone -- separate by popularity
ORDER BY ct DESC LIMIT 10 -- top 10 zones are given
'''.format(serverid))
""", (serverid))
else:
c.execute('''
SELECT zone, '0' as ct FROM users
WHERE guild = '{0}' AND user = '{1}'
'''.format(serverid, userid))
c.execute("""
SELECT zone, '0' as ct FROM userdata
WHERE guild_id = %s AND user_id = %s
""", (serverid, userid))
results = c.fetchall()
c.close()
@ -85,23 +91,23 @@ class UserDatabase:
Returns a dictionary. Keys are zone name, values are arrays with user IDs.
'''
c = self.db.cursor()
c.execute('''
SELECT zone, user
FROM users
c.execute("""
SELECT zone, user_id
FROM userdata
WHERE
lastactive >= strftime('%s','now') - (72 * 60 * 60) -- only users active in the last 72 hrs
AND guild = '{0}'
last_active >= now() - INTERVAL '72 HOURS' -- only users active in the last 72 hrs
AND guild_id = %(guild)s
AND zone in (SELECT zone from (
SELECT zone, count(*) as ct
FROM users
FROM userdata
WHERE
guild = '{0}'
AND lastactive >= strftime('%s','now') - (72 * 60 * 60)
guild_id = %(guild)s
AND last_active >= now() - INTERVAL '72 HOURS'
GROUP BY zone
LIMIT 10
))
) as pop_zones)
ORDER BY RANDOM() -- Randomize display order (done by consumer)
'''.format(serverid))
""", {'guild': serverid})
result = {}
for row in c:
inlist = result.get(row[0])
@ -117,7 +123,7 @@ class UserDatabase:
Gets the number of unique time zones in the database.
'''
c = self.db.cursor()
c.execute('SELECT COUNT(DISTINCT zone) FROM users')
c.execute('SELECT COUNT(DISTINCT zone) FROM userdata')
result = c.fetchall()
c.close()
return result[0][0]

View file

@ -5,7 +5,7 @@
# - https://bots.discord.pw/bots/447266583459528715
# Dependencies (install via pip or other means):
# pytz, sqlite3, discord.py@rewrite
# pytz, psycopg2, discord.py@rewrite
# How to install the latter: pip install -U git+https://github.com/Rapptz/discord.py@rewrite
from discord import Game