(core): Add app-global setting storage.
New `AppConfig` key-value table for arbitrary app config. New `KeyValueData` setting data mixin. New `AppSettings` settings group. Attached `AppSettings` as `client.settings`. Migrated sponsor settings to `AppSettings`.
This commit is contained in:
@@ -11,6 +11,9 @@ meta = RowTable(
|
|||||||
attach_as='meta',
|
attach_as='meta',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# TODO: Consider converting to RowTable for per-shard config caching
|
||||||
|
app_config = Table('AppConfig')
|
||||||
|
|
||||||
|
|
||||||
user_config = RowTable(
|
user_config = RowTable(
|
||||||
'user_config',
|
'user_config',
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ from data import tables
|
|||||||
|
|
||||||
import core # noqa
|
import core # noqa
|
||||||
|
|
||||||
|
# Note: This MUST be imported after core, due to table definition orders
|
||||||
|
from settings import AppSettings
|
||||||
|
|
||||||
import modules # noqa
|
import modules # noqa
|
||||||
|
|
||||||
# Load and attach app specific data
|
# Load and attach app specific data
|
||||||
@@ -15,6 +18,8 @@ client.appdata = core.data.meta.fetch_or_create(appname)
|
|||||||
|
|
||||||
client.data = tables
|
client.data = tables
|
||||||
|
|
||||||
|
client.settings = AppSettings(conf.bot['data_appid'])
|
||||||
|
|
||||||
# Initialise all modules
|
# Initialise all modules
|
||||||
client.initialise_modules()
|
client.initialise_modules()
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
from cmdClient.checks import is_owner
|
from cmdClient.checks import is_owner
|
||||||
|
|
||||||
from .module import module
|
from .module import module
|
||||||
from .config import settings
|
|
||||||
|
|
||||||
|
|
||||||
@module.cmd(
|
@module.cmd(
|
||||||
@@ -18,10 +17,10 @@ async def cmd_sponsors(ctx, flags):
|
|||||||
if await is_owner.run(ctx) and any(flags.values()):
|
if await is_owner.run(ctx) and any(flags.values()):
|
||||||
if flags['edit']:
|
if flags['edit']:
|
||||||
# Run edit setting command
|
# Run edit setting command
|
||||||
await settings.sponsor_message.command(ctx, 0)
|
await ctx.client.settings.sponsor_message.command(ctx, ctx.client.conf.bot['data_appid'])
|
||||||
elif flags['prompt']:
|
elif flags['prompt']:
|
||||||
# Run prompt setting command
|
# Run prompt setting command
|
||||||
await settings.sponsor_prompt.command(ctx, 0)
|
await ctx.client.settings.sponsor_prompt.command(ctx, ctx.client.conf.bot['data_appid'])
|
||||||
else:
|
else:
|
||||||
# Display message
|
# Display message
|
||||||
await ctx.reply(**settings.sponsor_message.args(ctx))
|
await ctx.reply(**ctx.client.settings.sponsor_message.args(ctx))
|
||||||
|
|||||||
@@ -1,23 +1,16 @@
|
|||||||
from cmdClient.checks import is_owner
|
from cmdClient.checks import is_owner
|
||||||
|
|
||||||
from settings.base import Setting, ColumnData, ObjectSettings
|
from settings import AppSettings, Setting, KeyValueData, ListData
|
||||||
from settings.setting_types import Message, String
|
from settings.setting_types import Message, String
|
||||||
|
|
||||||
from meta import client
|
from meta import client
|
||||||
from utils.lib import DotDict
|
from core.data import app_config
|
||||||
|
|
||||||
from .data import sponsor_text
|
|
||||||
|
|
||||||
|
|
||||||
class SponsorSettings(ObjectSettings):
|
@AppSettings.attach_setting
|
||||||
settings = DotDict()
|
class sponsor_prompt(String, KeyValueData, Setting):
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
@SponsorSettings.attach_setting
|
|
||||||
class sponsor_prompt(String, ColumnData, Setting):
|
|
||||||
attr_name = 'sponsor_prompt'
|
attr_name = 'sponsor_prompt'
|
||||||
_default = "Type {prefix}sponsors to check our wonderful partners!"
|
_default = None
|
||||||
|
|
||||||
write_ward = is_owner
|
write_ward = is_owner
|
||||||
|
|
||||||
@@ -30,11 +23,11 @@ class sponsor_prompt(String, ColumnData, Setting):
|
|||||||
|
|
||||||
_quote = False
|
_quote = False
|
||||||
|
|
||||||
_data_column = 'prompt_text'
|
_table_interface = app_config
|
||||||
_table_interface = sponsor_text
|
_id_column = 'appid'
|
||||||
_id_column = 'ID'
|
_key_column = 'key'
|
||||||
_upsert = True
|
_value_column = 'value'
|
||||||
_create_row = True
|
_key = 'sponsor_prompt'
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _data_to_value(cls, id, data, **kwargs):
|
def _data_to_value(cls, id, data, **kwargs):
|
||||||
@@ -44,8 +37,8 @@ class sponsor_prompt(String, ColumnData, Setting):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
@SponsorSettings.attach_setting
|
@AppSettings.attach_setting
|
||||||
class sponsor_message(Message, ColumnData, Setting):
|
class sponsor_message(Message, KeyValueData, Setting):
|
||||||
attr_name = 'sponsor_message'
|
attr_name = 'sponsor_message'
|
||||||
_default = '{"content": "Coming Soon!"}'
|
_default = '{"content": "Coming Soon!"}'
|
||||||
|
|
||||||
@@ -58,13 +51,10 @@ class sponsor_message(Message, ColumnData, Setting):
|
|||||||
"Message to reply with when a user runs the `sponsors` command."
|
"Message to reply with when a user runs the `sponsors` command."
|
||||||
)
|
)
|
||||||
|
|
||||||
_data_column = 'command_response'
|
_table_interface = app_config
|
||||||
_table_interface = sponsor_text
|
_id_column = 'appid'
|
||||||
_id_column = 'ID'
|
_key_column = 'key'
|
||||||
_upsert = True
|
_value_column = 'value'
|
||||||
_create_row = True
|
_key = 'sponsor_message'
|
||||||
|
|
||||||
_cmd_str = "{prefix}sponsors --edit"
|
_cmd_str = "{prefix}sponsors --edit"
|
||||||
|
|
||||||
|
|
||||||
settings = SponsorSettings(0)
|
|
||||||
|
|||||||
@@ -5,8 +5,6 @@ from LionContext import LionContext
|
|||||||
|
|
||||||
from meta import client
|
from meta import client
|
||||||
|
|
||||||
from .config import settings
|
|
||||||
|
|
||||||
|
|
||||||
module = LionModule("Sponsor")
|
module = LionModule("Sponsor")
|
||||||
|
|
||||||
@@ -18,7 +16,7 @@ sponsored_commands = {'profile', 'stats', 'weekly', 'monthly'}
|
|||||||
async def sponsor_reply_wrapper(func, ctx: LionContext, *args, **kwargs):
|
async def sponsor_reply_wrapper(func, ctx: LionContext, *args, **kwargs):
|
||||||
if ctx.cmd and ctx.cmd.name in sponsored_commands:
|
if ctx.cmd and ctx.cmd.name in sponsored_commands:
|
||||||
sponsor_hint = discord.Embed(
|
sponsor_hint = discord.Embed(
|
||||||
description=settings.sponsor_prompt.value,
|
description=ctx.client.settings.sponsor_prompt.value,
|
||||||
colour=discord.Colour.dark_theme()
|
colour=discord.Colour.dark_theme()
|
||||||
)
|
)
|
||||||
if 'embed' not in kwargs:
|
if 'embed' not in kwargs:
|
||||||
|
|||||||
5
bot/settings/app_settings.py
Normal file
5
bot/settings/app_settings.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import settings
|
||||||
|
from utils.lib import DotDict
|
||||||
|
|
||||||
|
class AppSettings(settings.ObjectSettings):
|
||||||
|
settings = DotDict()
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import json
|
||||||
import discord
|
import discord
|
||||||
from cmdClient.cmdClient import cmdClient
|
from cmdClient.cmdClient import cmdClient
|
||||||
from cmdClient.lib import SafeCancellation
|
from cmdClient.lib import SafeCancellation
|
||||||
@@ -459,5 +460,55 @@ class ListData:
|
|||||||
cls._cache[id] = data
|
cls._cache[id] = data
|
||||||
|
|
||||||
|
|
||||||
|
class KeyValueData:
|
||||||
|
"""
|
||||||
|
Mixin for settings implemented in a Key-Value table.
|
||||||
|
The underlying table should have a Unique constraint on the `(_id_column, _key_column)` pair.
|
||||||
|
"""
|
||||||
|
_table_interface: Table = None
|
||||||
|
|
||||||
|
_id_column: str = None
|
||||||
|
|
||||||
|
_key_column: str = None
|
||||||
|
|
||||||
|
_value_column: str = None
|
||||||
|
|
||||||
|
_key: str = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _reader(cls, id: ..., **kwargs):
|
||||||
|
params = {
|
||||||
|
"select_columns": (cls._value_column, ),
|
||||||
|
cls._id_column: id,
|
||||||
|
cls._key_column: cls._key
|
||||||
|
}
|
||||||
|
|
||||||
|
row = cls._table_interface.select_one_where(**params)
|
||||||
|
data = row[cls._value_column] if row else None
|
||||||
|
|
||||||
|
if data is not None:
|
||||||
|
data = json.loads(data)
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _writer(cls, id: ..., data: ..., **kwargs):
|
||||||
|
params = {
|
||||||
|
cls._id_column: id,
|
||||||
|
cls._key_column: cls._key
|
||||||
|
}
|
||||||
|
if data is not None:
|
||||||
|
values = {
|
||||||
|
cls._value_column: json.dumps(data)
|
||||||
|
}
|
||||||
|
cls._table_interface.upsert(
|
||||||
|
constraint=f"{cls._id_column}, {cls._key_column}",
|
||||||
|
**params,
|
||||||
|
**values
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
cls._table_interface.delete_where(**params)
|
||||||
|
|
||||||
|
|
||||||
class UserInputError(SafeCancellation):
|
class UserInputError(SafeCancellation):
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -1,8 +1,22 @@
|
|||||||
|
-- App Config Data {{{
|
||||||
|
CREATE TABLE AppConfig(
|
||||||
|
appid TEXT,
|
||||||
|
key TEXT,
|
||||||
|
value TEXT,
|
||||||
|
PRIMARY KEY(appid, key)
|
||||||
|
);
|
||||||
|
-- }}}
|
||||||
|
|
||||||
|
|
||||||
-- Sponsor Data {{{
|
-- Sponsor Data {{{
|
||||||
CREATE TABLE sponsor_text(
|
CREATE TABLE sponsor_guild_whitelist(
|
||||||
ID INTEGER PRIMARY KEY DEFAULT 0,
|
guildid INTEGER PRIMARY KEY
|
||||||
prompt_text TEXT,
|
);
|
||||||
command_response TEXT
|
-- }}}
|
||||||
|
|
||||||
|
-- Topgg Data {{{
|
||||||
|
CREATE TABLE topgg_guild_whitelist(
|
||||||
|
guildid INTEGER PRIMARY KEY
|
||||||
);
|
);
|
||||||
-- }}}
|
-- }}}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,13 @@ CREATE TABLE AppData(
|
|||||||
last_study_badge_scan TIMESTAMP
|
last_study_badge_scan TIMESTAMP
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE AppConfig(
|
||||||
|
appid TEXT,
|
||||||
|
key TEXT,
|
||||||
|
value TEXT,
|
||||||
|
PRIMARY KEY(appid, key)
|
||||||
|
);
|
||||||
|
|
||||||
CREATE TABLE global_user_blacklist(
|
CREATE TABLE global_user_blacklist(
|
||||||
userid BIGINT PRIMARY KEY,
|
userid BIGINT PRIMARY KEY,
|
||||||
ownerid BIGINT NOT NULL,
|
ownerid BIGINT NOT NULL,
|
||||||
@@ -37,16 +44,6 @@ CREATE TABLE global_guild_blacklist(
|
|||||||
);
|
);
|
||||||
-- }}}
|
-- }}}
|
||||||
|
|
||||||
|
|
||||||
-- Sponsor Data {{{
|
|
||||||
CREATE TABLE sponsor_text(
|
|
||||||
ID INTEGER PRIMARY KEY DEFAULT 0,
|
|
||||||
prompt_text TEXT,
|
|
||||||
command_response TEXT
|
|
||||||
);
|
|
||||||
-- }}}
|
|
||||||
|
|
||||||
|
|
||||||
-- User configuration data {{{
|
-- User configuration data {{{
|
||||||
CREATE TABLE user_config(
|
CREATE TABLE user_config(
|
||||||
userid BIGINT PRIMARY KEY,
|
userid BIGINT PRIMARY KEY,
|
||||||
@@ -808,6 +805,16 @@ create TABLE topgg(
|
|||||||
boostedTimestamp TIMESTAMPTZ NOT NULL
|
boostedTimestamp TIMESTAMPTZ NOT NULL
|
||||||
);
|
);
|
||||||
CREATE INDEX topgg_userid_timestamp ON topgg (userid, boostedTimestamp);
|
CREATE INDEX topgg_userid_timestamp ON topgg (userid, boostedTimestamp);
|
||||||
|
|
||||||
|
CREATE TABLE topgg_guild_whitelist(
|
||||||
|
guildid INTEGER PRIMARY KEY
|
||||||
|
);
|
||||||
|
-- }}}
|
||||||
|
|
||||||
|
-- Sponsor Data {{{
|
||||||
|
CREATE TABLE sponsor_guild_whitelist(
|
||||||
|
guildid INTEGER PRIMARY KEY
|
||||||
|
);
|
||||||
-- }}}
|
-- }}}
|
||||||
|
|
||||||
-- vim: set fdm=marker:
|
-- vim: set fdm=marker:
|
||||||
|
|||||||
Reference in New Issue
Block a user