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. 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 ## Setup
1. Install the necessary dependencies: `pytz`, `sqlite3`, and `discord.py` (rewrite branch). 1. Install the necessary dependencies: `pytz`, `psycopg2`, and `discord.py` (rewrite branch).
2. Copy `settings_default.py` to `settings.py` and set your bot token. 2. Copy `settings_default.py` to `settings.py` and configure as needed.
3. Run `worldtime.py` using Python 3. 3. Run `worldtime.py`.

View file

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

View file

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

View file

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