mirror of
https://github.com/PretendoNetwork/Yamamura.git
synced 2024-06-11 17:17:20 -04:00
make the settings table act like a key-value store and make other files utilize it
This commit is contained in:
parent
ea3369edc6
commit
0fb78bdf0e
121
core/db.py
121
core/db.py
|
@ -20,21 +20,23 @@ class Modmail:
|
|||
"""
|
||||
|
||||
# initiation function
|
||||
def __init__(self, server_info):
|
||||
def __init__(self, server_object):
|
||||
"""
|
||||
initiates the modmail class. takes one argument, a serverinfo dict (doc.py #1)
|
||||
initiates the modmail class
|
||||
:argument server_object: a discord.Guild
|
||||
"""
|
||||
# set some variables to save these
|
||||
self.server = server_info # server info, from a YAML file
|
||||
self.db = dataset.connect(
|
||||
self.server["dbPath"] # the sqlite3 database object for the server
|
||||
f"servers/{ server_object.id }/server.db" # open a connection to the server database
|
||||
)
|
||||
self.settings = utils.KeyValueTable(self.db["settings"]) # get the settings table as a key-value store
|
||||
self.modmail = self.db["modmail"] # get the modmail table
|
||||
self.log = utils.Logger(
|
||||
f"db::mail { self.server['dbName'] }",
|
||||
f"{ self.server['rootDir'] }/db_modmail.log",
|
||||
f"db::mail ({ server_object.id }/{ server_object.name })",
|
||||
f"servers/{ server_object.id }/db_modmail.log",
|
||||
)
|
||||
# notify the sysadmin of the connection
|
||||
self.log(f"connected to { self.server['dbName'] }")
|
||||
self.log(f"connected to { server_object.id }/{ server_object.name }")
|
||||
# display the current number of stored message
|
||||
self.log(f"current number of messages in database: { len(self.db['mail']) }")
|
||||
# finish it...
|
||||
|
@ -45,19 +47,20 @@ class Modmail:
|
|||
@staticmethod
|
||||
def parse(mail):
|
||||
"""
|
||||
parses a mail dict (doc.py #3). intended to be used by the modmail class but may have other uses.
|
||||
parses a mail dict. intended to be used by the modmail class but may have other uses.
|
||||
:argument mail: a mail dict
|
||||
"""
|
||||
# parse a list of mail
|
||||
if isinstance(mail, list):
|
||||
# the string to send to Discord
|
||||
return_string = """mail from { self.server }:
|
||||
return_string = f"""mail from { self.server.id }/{ self.server.name }:
|
||||
"""
|
||||
# loop through the mail list
|
||||
for x in range(0, len(mail)):
|
||||
# append the parsed message to the string
|
||||
return_string += f"""
|
||||
{mail[x]["id"]} - sent by {mail[x]["sender"]}```
|
||||
{mail[x]["message"]}```
|
||||
{ mail[x]["id"] } - sent by { mail["sender_id"] }/{ mail["sender_name"] }```
|
||||
{ mail[x]["message"] }```
|
||||
"""
|
||||
# return the string
|
||||
return return_string
|
||||
|
@ -66,8 +69,8 @@ class Modmail:
|
|||
else:
|
||||
# the string to send to Discord
|
||||
return_string = f"""
|
||||
{mail["id"]} - sent by {mail["sender"]}```
|
||||
{mail["message"]}```
|
||||
{ mail["id"] } - sent by { mail["sender_id"] }/{ mail["sender_name"] }```
|
||||
{ mail["message"] }```
|
||||
|
||||
"""
|
||||
# return the parsed message
|
||||
|
@ -76,19 +79,21 @@ class Modmail:
|
|||
# get the current modmail
|
||||
def read(self, mod):
|
||||
"""
|
||||
returns a generated parseMail string ready for sending to discord. takes one argument, a mod's discord id
|
||||
returns a string of mail ready for sending to discord
|
||||
:argument mod: a discord.Member of a mod
|
||||
:returns: a string of mail ready to send to discord
|
||||
"""
|
||||
# tell the sysadmin that we're reading mail for a mod
|
||||
self.log(f"reading mail for { mod }")
|
||||
self.log(f"reading mail for { mod.id }/{ mod.name }")
|
||||
# the unread mail list
|
||||
unread = []
|
||||
# add all of the unread mail
|
||||
for mail in self.db["mail"]:
|
||||
for mail in self.modmail:
|
||||
try:
|
||||
mail["readBy"].index(mod)
|
||||
mail["readBy"].index(mod.id)
|
||||
except ValueError:
|
||||
unread.append(mail)
|
||||
mail["readBy"].append(mod)
|
||||
mail["readBy"].append(mod.id)
|
||||
# if no mail is unread
|
||||
if not unread:
|
||||
return None
|
||||
|
@ -99,18 +104,20 @@ class Modmail:
|
|||
# send modmail
|
||||
def send(self, msg, sender):
|
||||
"""
|
||||
send mail to mods. takes two arguments, a string for the message, and a discord id for the sender
|
||||
send mail to mods
|
||||
:argument msg: a string to send as a message
|
||||
:argument sender: a discord.Member for the sender
|
||||
"""
|
||||
# tell the sysadmin that someone is sending mail
|
||||
self.log(f"{ sender } is sending modmail")
|
||||
self.log(f"{ sender.id }/{ sender.name } is sending modmail")
|
||||
# construct the message
|
||||
mail_to_send = dict(
|
||||
id=utils.whiskerflake(), sender=sender, message=msg, readBy=[]
|
||||
id=utils.whiskerflake(), sender_id=sender.id, sender_name=sender.name, message=msg, readBy=[]
|
||||
)
|
||||
# send the message
|
||||
self.db["mail"].insert(mail_to_send)
|
||||
self.modmail.insert(mail_to_send)
|
||||
# tell the sysadmin the current number of messages in the db
|
||||
self.log(f"{ sender }'s mail has been sent")
|
||||
self.log(f"{ sender.id }/{ sender.name }'s mail has been sent")
|
||||
self.log(f"current number of messages: { len(self.db['mail']) }")
|
||||
# exit the function
|
||||
return
|
||||
|
@ -122,12 +129,12 @@ class Modmail:
|
|||
"""
|
||||
# tell the sysadmin that the mail is being cleaned
|
||||
self.log(f"cleaning mail...")
|
||||
# list of moderator's usernames
|
||||
mods = self.server["mods"]
|
||||
# list of moderator's ids
|
||||
mods = self.settings["mod_ids"]
|
||||
# indexes of mail to delete
|
||||
indexes_to_delete = []
|
||||
# check if all the mods have read the mail
|
||||
for mail in self.db["mail"]:
|
||||
for mail in self.modmail:
|
||||
mail_read = True
|
||||
for y in range(0, len(mods)):
|
||||
try:
|
||||
|
@ -135,38 +142,29 @@ class Modmail:
|
|||
except ValueError:
|
||||
mail_read = False
|
||||
if mail_read:
|
||||
indexes_to_delete.append(self.db["mail"].find(id=mail["id"]))
|
||||
indexes_to_delete.append(self.modmail.find(id=mail["id"]))
|
||||
# then clean from the mail list the indexes to delete
|
||||
for x in range(0, len(indexes_to_delete)):
|
||||
self.db["mail"].delete(id=x)
|
||||
self.modmail.delete(id=x)
|
||||
# return with nothing
|
||||
return
|
||||
|
||||
# delete a specific message
|
||||
def delete(self, sid):
|
||||
"""
|
||||
deletes a specific message by it's identifier. takes one arguement, an identifier. returns none if not found,
|
||||
deletes a specific message by it's identifier. takes one argument, an identifier. returns none if not found,
|
||||
true if it was
|
||||
"""
|
||||
# tell the sysadmin that mail is being deleted
|
||||
self.log(f"searching for mail id { sid }...")
|
||||
# search the mail for a specific id
|
||||
found = False
|
||||
for mail in self.db["mail"]:
|
||||
if mail["id"] == sid:
|
||||
# tell the sysadmin this
|
||||
self.log(f"deleting mail id { sid }...")
|
||||
self.db["mail"].delete(id=mail["id"])
|
||||
found = True
|
||||
# if we couldn't find the mail
|
||||
if not found:
|
||||
# tell the sysadmin this too
|
||||
self.log(f"could not find mail id { sid }...")
|
||||
# then return none because nothing was found
|
||||
return None
|
||||
|
||||
# return at the end
|
||||
return True
|
||||
if self.modmail.find_one(id=sid):
|
||||
self.modmail.delete(id=mail["id"])
|
||||
return True
|
||||
# if we could not find this, then tell the sysadmin this too
|
||||
self.log(f"could not find mail id { sid }...")
|
||||
# then return none because nothing was found
|
||||
return None
|
||||
|
||||
# shows all mail
|
||||
def list(self):
|
||||
|
@ -176,11 +174,10 @@ class Modmail:
|
|||
# tell the sysadmin **everything**
|
||||
self.log(f"listing all mail to someone...")
|
||||
# this might happen
|
||||
if not self.db["mail"].all():
|
||||
if not self.modmail.all():
|
||||
return None
|
||||
|
||||
# the mail
|
||||
return self.parse(self.db["mail"].all())
|
||||
return self.parse(self.modmail.all())
|
||||
|
||||
# read a specific message
|
||||
def read_single(self, sid):
|
||||
|
@ -190,37 +187,36 @@ class Modmail:
|
|||
"""
|
||||
# might be useful for statistics or something
|
||||
self.log(f"searching for mail id { sid }...")
|
||||
# find the single message
|
||||
for mail in self.db["mail"]:
|
||||
# this too
|
||||
self.log(f"found mail id { sid }...")
|
||||
if mail["id"] == sid:
|
||||
message = mail
|
||||
return self.parse(message)
|
||||
|
||||
# find the message
|
||||
message = self.modmail.find_one(id=sid)
|
||||
# check if we found it
|
||||
if message:
|
||||
# return the message
|
||||
return self.parse(message)
|
||||
# debugging???
|
||||
self.log(f" could not find mail id { sid }...")
|
||||
# return None if not found
|
||||
return None
|
||||
|
||||
|
||||
"""
|
||||
# tag class for Netux's tags
|
||||
class tags:
|
||||
"""
|
||||
class Tags:
|
||||
""
|
||||
class for handling the tags system
|
||||
"""
|
||||
""
|
||||
|
||||
def __init__(self, serverInfo):
|
||||
"""
|
||||
""
|
||||
initiates the tags class. takes one argument, a serverinfo dict (doc.py #1)
|
||||
"""
|
||||
""
|
||||
# set some variables to save these
|
||||
self.server = serverInfo # server info, from a YAML file
|
||||
self.db = dataset.connect(
|
||||
self.server["dbPath"] # the sqlite3 database object for the server
|
||||
)
|
||||
self.log = utils.Logger(
|
||||
f"db::tags { self.server['dbName'] }",
|
||||
f"db::tags ({ self.server['dbName'] })",
|
||||
f"{ self.server['rootDir'] }/db_tags.log",
|
||||
)
|
||||
# notify the sysadmin of the connection
|
||||
|
@ -265,3 +261,4 @@ class tags:
|
|||
tags_file.seek(0)
|
||||
tags_file.write(json.dumps(tags))
|
||||
tags_file.truncate()
|
||||
"""
|
|
@ -6,6 +6,7 @@
|
|||
#
|
||||
# imported modules
|
||||
import core.utils as utils # import the utility package
|
||||
import dataset # database things
|
||||
import discord # dealing with some discord-related things
|
||||
|
||||
|
||||
|
@ -17,18 +18,20 @@ class Server:
|
|||
"""
|
||||
|
||||
# initiation function
|
||||
def __init__(self, server_info, server_object):
|
||||
def __init__(self, server_object):
|
||||
"""
|
||||
initiates the server class. takes two arguments, a serverinfo dict (doc.py #1), and a discord.py server object
|
||||
:param server_info: a serverinfo dict
|
||||
initiates the server class
|
||||
:param server_object: a discord.Guild class
|
||||
"""
|
||||
# set some variables to save these
|
||||
self.server_info = server_info # server info, from a YAML file
|
||||
self.db = dataset.connect(
|
||||
f"servers/{ server_object.id }/server.db" # the database
|
||||
)
|
||||
self.server_settings = utils.KeyValueTable(self.db["settings"])
|
||||
self.server = server_object # the server object
|
||||
self.log = utils.Logger(
|
||||
f"utils::server { self.server_info['name'] }",
|
||||
f"{ self.server_info['rootDir'] }/server.log",
|
||||
f"utils::server ({ self.server.id }/{ self.server.name })",
|
||||
f"servers/{ self.server.id }/server.log",
|
||||
)
|
||||
# check if the server object is actually a server object
|
||||
if type(self.server) != discord.Guild:
|
||||
|
@ -40,14 +43,14 @@ class Server:
|
|||
)
|
||||
|
||||
# add a nice log message
|
||||
self.log(f"initiated server class for { self.server_info['name'] }")
|
||||
self.log(f"initiated server class for { self.server.id }/{ self.server.name }")
|
||||
|
||||
# checking if a member is a mod
|
||||
def is_mod(self, member):
|
||||
"""
|
||||
returns true if user is a mod, false if they aren't
|
||||
:param member: a discord.Member to check for mod status on
|
||||
:returns: it returns true if the user is a mod, false if they aren't. it returns none if a type mismatch occured
|
||||
:returns: it returns true if the user is a mod, false if they aren't. it returns none if a type mismatch occurred
|
||||
"""
|
||||
# check if they are an instance of discord.Member
|
||||
if type(member) != discord.Member:
|
||||
|
@ -59,8 +62,8 @@ class Server:
|
|||
# append the id
|
||||
user_role_ids.append(str(role.id))
|
||||
# do the check
|
||||
return member.id in self.server_info["mods"] or utils.list_overlap(
|
||||
self.server_info["modRoles"], user_role_ids
|
||||
return member.id in self.server_settings["mods"] or utils.list_overlap(
|
||||
self.server_settings["mod_roles"], user_role_ids
|
||||
)
|
||||
|
||||
# get a channel by an identifier
|
||||
|
@ -137,7 +140,7 @@ class Server:
|
|||
return if a member has a role
|
||||
:param member: a discord role obj or an discord role id. the member id must be of the int type
|
||||
:param role: a discord member obj or an discord member id. the member id must be of the int type here too
|
||||
:returns: it returns none if a type mismatch occured, otherwhise it returns true or false if they have it or not
|
||||
:returns: it returns none if a type mismatch occurred, otherwise it returns true or false if they have it or not
|
||||
"""
|
||||
# first, check if the passed role is a discord role object
|
||||
# or a role id (int)
|
||||
|
@ -156,7 +159,7 @@ class Server:
|
|||
if type(member) != discord.member.Member:
|
||||
# member id (int)
|
||||
if type(member) != int:
|
||||
# you idiot
|
||||
# i guess it's neither
|
||||
return None
|
||||
|
||||
else:
|
||||
|
|
|
@ -58,6 +58,7 @@ def whiskerflake():
|
|||
# add them and return
|
||||
return epoch_hash + rand_int
|
||||
|
||||
|
||||
# check for list overlap between two lists
|
||||
def list_overlap(list1, list2):
|
||||
"""
|
||||
|
@ -76,6 +77,62 @@ def list_overlap(list1, list2):
|
|||
# return if there is overlap
|
||||
return overlap
|
||||
|
||||
|
||||
# class to make a database table like a key-value store
|
||||
class KeyValueTable:
|
||||
"""operate a database table like a key-value store"""
|
||||
|
||||
# initiate the KeyValueDB
|
||||
def __init__(self, table):
|
||||
"""
|
||||
initiate the KeyValueDB
|
||||
:param table: a dataset table
|
||||
"""
|
||||
self.table = table
|
||||
|
||||
# retrieve a key-value pair from the database
|
||||
def __getitem__(self, key):
|
||||
"""
|
||||
retrieve an item from the key-value store
|
||||
:param key: the name of the requested item
|
||||
:return: the requested item
|
||||
:raises KeyError: it raises KeyError if it cannot be found
|
||||
"""
|
||||
# attempt to find the requested item
|
||||
res = self.table.find_one(key=key)
|
||||
# check if it returned something
|
||||
if not res:
|
||||
# raise IndexError if it cannot be found
|
||||
raise KeyError(f"unable to find key-value pair with key { key }")
|
||||
else:
|
||||
# otherwise return the requested item
|
||||
return res
|
||||
|
||||
# set a key-value pair in the database
|
||||
def __setitem__(self, key, value):
|
||||
"""
|
||||
set an item in the key-value store
|
||||
:param key: the key to set
|
||||
:param value: the value for the key to have
|
||||
"""
|
||||
# upsert it (insert if it doesn't exist, update it if it does)
|
||||
self.table.upsert(dict(key=key, value=value), ["key"])
|
||||
|
||||
# delete a key-value pair in the database
|
||||
def __delitem__(self, key):
|
||||
"""
|
||||
delete a value in the key-value store if it exists
|
||||
:param key: the key to delete
|
||||
"""
|
||||
# attempt to delete it
|
||||
self.table.delete(key=key)
|
||||
|
||||
# when the key is missing
|
||||
def __missing__(self, key):
|
||||
# just return none
|
||||
return None
|
||||
|
||||
|
||||
"""
|
||||
def coo(channel, target_user, response):
|
||||
target_part = f"{ target_user.mention }, " if target_user is not None else ""
|
||||
|
|
Loading…
Reference in a new issue