Move message content to message_json

This commit is contained in:
jude committed 2026-10-11 12:43:43 +01:00
1 parent 644adc3f87
commit 2665c61d33
33 files changed
+1036 -290

No files matched your search

@@ -0,0 +1,84 @@
{
"db_name": "MySQL",
"query": "\n SELECT id, channel, nudge, webhook_id, webhook_token, paused,\n paused_until\n FROM channels\n WHERE channel = ?\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": {
"type": "Long",
"flags": "NOT_NULL | PRIMARY_KEY | UNIQUE_KEY | UNSIGNED | AUTO_INCREMENT",
"max_size": 10
}
},
{
"ordinal": 1,
"name": "channel",
"type_info": {
"type": "LongLong",
"flags": "NOT_NULL | UNIQUE_KEY | UNSIGNED | NO_DEFAULT_VALUE",
"max_size": 20
}
},
{
"ordinal": 2,
"name": "nudge",
"type_info": {
"type": "Short",
"flags": "NOT_NULL",
"max_size": 6
}
},
{
"ordinal": 3,
"name": "webhook_id",
"type_info": {
"type": "LongLong",
"flags": "UNIQUE_KEY | UNSIGNED",
"max_size": 20
}
},
{
"ordinal": 4,
"name": "webhook_token",
"type_info": {
"type": "Blob",
"flags": "BLOB",
"max_size": 262140
}
},
{
"ordinal": 5,
"name": "paused",
"type_info": {
"type": "Tiny",
"flags": "NOT_NULL",
"max_size": 1
}
},
{
"ordinal": 6,
"name": "paused_until",
"type_info": {
"type": "Timestamp",
"flags": "BINARY",
"max_size": 19
}
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
false,
false,
true,
true,
false,
true
]
},
"hash": "017b3f73101926a3fe029ed75c412ec902aa74fee334c23fd75fe0cde1e324ca"
}
@@ -1,19 +1,10 @@
{
"db_name": "MySQL",
"query": "\n SELECT reminders.attachment,\n reminders.attachment_name,\n reminders.content,\n reminders.embed_author,\n reminders.embed_author_url,\n reminders.embed_color,\n reminders.embed_description,\n reminders.embed_footer,\n reminders.embed_footer_url,\n reminders.embed_image_url,\n reminders.embed_thumbnail_url,\n reminders.embed_title,\n reminders.embed_fields,\n reminders.enabled,\n reminders.expires,\n reminders.interval_seconds,\n reminders.interval_days,\n reminders.interval_months,\n reminders.name,\n reminders.tts,\n reminders.uid,\n reminders.utc_time\n FROM reminders\n LEFT JOIN channels ON channels.id = reminders.channel_id\n WHERE uid = ?\n ",
"query": "\n SELECT\n reminders.attachment_name,\n reminders.avatar,\n channels.channel,\n reminders.message_json,\n reminders.content,\n reminders.embed_author,\n reminders.embed_author_url,\n reminders.embed_color,\n reminders.embed_description,\n reminders.embed_footer,\n reminders.embed_footer_url,\n reminders.embed_image_url,\n reminders.embed_thumbnail_url,\n reminders.embed_title,\n reminders.embed_fields,\n reminders.enabled,\n reminders.expires,\n reminders.interval_seconds,\n reminders.interval_days,\n reminders.interval_months,\n reminders.name,\n reminders.restartable,\n reminders.tts,\n reminders.uid,\n reminders.username,\n reminders.utc_time\n FROM reminders\n LEFT JOIN channels ON channels.id = reminders.channel_id\n WHERE uid = ?",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "attachment",
"type_info": {
"type": "Blob",
"flags": "BLOB | BINARY",
"max_size": 16777215
}
},
{
"ordinal": 1,
"name": "attachment_name",
"type_info": {
"type": "VarString",
@@ -21,8 +12,35 @@
"max_size": 1040
}
},
{
"ordinal": 1,
"name": "avatar",
"type_info": {
"type": "VarString",
"flags": "",
"max_size": 2048
}
},
{
"ordinal": 2,
"name": "channel",
"type_info": {
"type": "LongLong",
"flags": "UNIQUE_KEY | UNSIGNED | NO_DEFAULT_VALUE",
"max_size": 20
}
},
{
"ordinal": 3,
"name": "message_json",
"type_info": {
"type": "Json",
"flags": "BLOB | BINARY",
"max_size": 4294967295
}
},
{
"ordinal": 4,
"name": "content",
"type_info": {
"type": "VarString",
@@ -31,7 +49,7 @@
}
},
{
"ordinal": 3,
"ordinal": 5,
"name": "embed_author",
"type_info": {
"type": "VarString",
@@ -40,7 +58,7 @@
}
},
{
"ordinal": 4,
"ordinal": 6,
"name": "embed_author_url",
"type_info": {
"type": "VarString",
@@ -49,7 +67,7 @@
}
},
{
"ordinal": 5,
"ordinal": 7,
"name": "embed_color",
"type_info": {
"type": "Long",
@@ -58,7 +76,7 @@
}
},
{
"ordinal": 6,
"ordinal": 8,
"name": "embed_description",
"type_info": {
"type": "VarString",
@@ -67,7 +85,7 @@
}
},
{
"ordinal": 7,
"ordinal": 9,
"name": "embed_footer",
"type_info": {
"type": "VarString",
@@ -76,7 +94,7 @@
}
},
{
"ordinal": 8,
"ordinal": 10,
"name": "embed_footer_url",
"type_info": {
"type": "VarString",
@@ -85,7 +103,7 @@
}
},
{
"ordinal": 9,
"ordinal": 11,
"name": "embed_image_url",
"type_info": {
"type": "VarString",
@@ -94,7 +112,7 @@
}
},
{
"ordinal": 10,
"ordinal": 12,
"name": "embed_thumbnail_url",
"type_info": {
"type": "VarString",
@@ -103,7 +121,7 @@
}
},
{
"ordinal": 11,
"ordinal": 13,
"name": "embed_title",
"type_info": {
"type": "VarString",
@@ -112,7 +130,7 @@
}
},
{
"ordinal": 12,
"ordinal": 14,
"name": "embed_fields",
"type_info": {
"type": "Json",
@@ -121,7 +139,7 @@
}
},
{
"ordinal": 13,
"ordinal": 15,
"name": "enabled",
"type_info": {
"type": "Tiny",
@@ -130,7 +148,7 @@
}
},
{
"ordinal": 14,
"ordinal": 16,
"name": "expires",
"type_info": {
"type": "Datetime",
@@ -139,7 +157,7 @@
}
},
{
"ordinal": 15,
"ordinal": 17,
"name": "interval_seconds",
"type_info": {
"type": "Long",
@@ -148,7 +166,7 @@
}
},
{
"ordinal": 16,
"ordinal": 18,
"name": "interval_days",
"type_info": {
"type": "Long",
@@ -157,7 +175,7 @@
}
},
{
"ordinal": 17,
"ordinal": 19,
"name": "interval_months",
"type_info": {
"type": "Long",
@@ -166,7 +184,7 @@
}
},
{
"ordinal": 18,
"ordinal": 20,
"name": "name",
"type_info": {
"type": "VarString",
@@ -175,7 +193,16 @@
}
},
{
"ordinal": 19,
"ordinal": 21,
"name": "restartable",
"type_info": {
"type": "Tiny",
"flags": "NOT_NULL",
"max_size": 1
}
},
{
"ordinal": 22,
"name": "tts",
"type_info": {
"type": "Tiny",
@@ -184,7 +211,7 @@
}
},
{
"ordinal": 20,
"ordinal": 23,
"name": "uid",
"type_info": {
"type": "VarString",
@@ -193,7 +220,16 @@
}
},
{
"ordinal": 21,
"ordinal": 24,
"name": "username",
"type_info": {
"type": "VarString",
"flags": "",
"max_size": 128
}
},
{
"ordinal": 25,
"name": "utc_time",
"type_info": {
"type": "Datetime",
@@ -206,6 +242,8 @@
"Right": 1
},
"nullable": [
true,
true,
true,
true,
false,
@@ -227,8 +265,10 @@
false,
false,
false,
false,
true,
false
]
},
"hash": "ecbea4acb61da864a4f83004b1163391068456a366fee95daff5f46413bcf494"
"hash": "168e34b942db6025a5674dca06ac154309cc8f86341272e7c771abfad1b61003"
}
@@ -0,0 +1,84 @@
{
"db_name": "MySQL",
"query": "\n SELECT id, channel, nudge, webhook_id, webhook_token, paused, paused_until\n FROM channels\n WHERE channel = ?\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": {
"type": "Long",
"flags": "NOT_NULL | PRIMARY_KEY | UNIQUE_KEY | UNSIGNED | AUTO_INCREMENT",
"max_size": 10
}
},
{
"ordinal": 1,
"name": "channel",
"type_info": {
"type": "LongLong",
"flags": "NOT_NULL | UNIQUE_KEY | UNSIGNED | NO_DEFAULT_VALUE",
"max_size": 20
}
},
{
"ordinal": 2,
"name": "nudge",
"type_info": {
"type": "Short",
"flags": "NOT_NULL",
"max_size": 6
}
},
{
"ordinal": 3,
"name": "webhook_id",
"type_info": {
"type": "LongLong",
"flags": "UNIQUE_KEY | UNSIGNED",
"max_size": 20
}
},
{
"ordinal": 4,
"name": "webhook_token",
"type_info": {
"type": "Blob",
"flags": "BLOB",
"max_size": 262140
}
},
{
"ordinal": 5,
"name": "paused",
"type_info": {
"type": "Tiny",
"flags": "NOT_NULL",
"max_size": 1
}
},
{
"ordinal": 6,
"name": "paused_until",
"type_info": {
"type": "Timestamp",
"flags": "BINARY",
"max_size": 19
}
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
false,
false,
true,
true,
false,
true
]
},
"hash": "21b660ecbeffcac31ef283f59e420360a28b344759407024a11dc4a04da9341d"
}
@@ -1,12 +1,12 @@
{
"db_name": "MySQL",
"query": "\n INSERT INTO reminders (\n `uid`,\n `channel_id`,\n `thread_id`,\n `utc_time`,\n `timezone`,\n `interval_seconds`,\n `interval_days`,\n `interval_months`,\n `expires`,\n `content`,\n `tts`,\n `attachment_name`,\n `attachment`,\n `set_by`\n ) VALUES (\n ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?\n )\n ",
"query": "\n INSERT INTO reminders (\n `uid`,\n `channel_id`,\n `thread_id`,\n `utc_time`,\n `timezone`,\n `interval_seconds`,\n `interval_days`,\n `interval_months`,\n `expires`,\n `message_json`,\n `attachment_name`,\n `attachment`,\n `set_by`\n ) VALUES (\n ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?\n )\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 14
"Right": 13
},
"nullable": []
},
"hash": "f9d2d9f6809b6c852297e5c60b6c356af5176c6b81b86cd701c1b8af8212f194"
"hash": "22ea7fbff927d2696e5c3dc78f714d1cb5dadcc560854e22f15def122c64fc0c"
}
@@ -1,6 +1,6 @@
{
"db_name": "MySQL",
"query": "\n SELECT\n reminders.id,\n reminders.uid,\n channels.channel,\n reminders.utc_time,\n reminders.interval_seconds,\n reminders.interval_days,\n reminders.interval_months,\n reminders.expires,\n reminders.enabled,\n reminders.content,\n reminders.embed_description,\n reminders.set_by\n FROM\n reminders\n INNER JOIN\n channels\n ON\n reminders.channel_id = channels.id\n WHERE\n reminders.id = ?\n ",
"query": "\n SELECT\n reminders.id,\n reminders.uid,\n channels.channel,\n reminders.utc_time,\n reminders.interval_seconds,\n reminders.interval_days,\n reminders.interval_months,\n reminders.expires,\n reminders.enabled,\n reminders.message_json,\n reminders.content,\n reminders.embed_description,\n reminders.set_by\n FROM\n reminders\n INNER JOIN\n channels\n ON\n reminders.channel_id = channels.id\n WHERE\n reminders.id = ?\n ",
"describe": {
"columns": [
{
@@ -86,6 +86,15 @@
},
{
"ordinal": 9,
"name": "message_json",
"type_info": {
"type": "Json",
"flags": "BLOB | BINARY",
"max_size": 4294967295
}
},
{
"ordinal": 10,
"name": "content",
"type_info": {
"type": "VarString",
@@ -94,7 +103,7 @@
}
},
{
"ordinal": 10,
"ordinal": 11,
"name": "embed_description",
"type_info": {
"type": "VarString",
@@ -103,7 +112,7 @@
}
},
{
"ordinal": 11,
"ordinal": 12,
"name": "set_by",
"type_info": {
"type": "LongLong",
@@ -125,10 +134,11 @@
true,
true,
false,
true,
false,
false,
true
]
},
"hash": "67b970d7b85f7bf3e71a58af10bedf7281cf0d8601b149383037d604a22a64c7"
"hash": "2753eb51d5f4b51771b696555752cc59d8d0c78737fc35210c5f6108d32f3540"
}
@@ -1,6 +1,6 @@
{
"db_name": "MySQL",
"query": "\n SELECT\n reminders.id,\n reminders.uid,\n channels.channel,\n reminders.utc_time,\n reminders.interval_seconds,\n reminders.interval_days,\n reminders.interval_months,\n reminders.expires,\n reminders.enabled,\n reminders.content,\n reminders.embed_description,\n reminders.set_by\n FROM\n reminders\n INNER JOIN\n channels\n ON\n reminders.channel_id = channels.id\n WHERE\n reminders.uid = ?\n ",
"query": "\n SELECT\n reminders.id,\n reminders.uid,\n channels.channel,\n reminders.utc_time,\n reminders.interval_seconds,\n reminders.interval_days,\n reminders.interval_months,\n reminders.expires,\n reminders.enabled,\n reminders.message_json,\n reminders.content,\n reminders.embed_description,\n reminders.set_by\n FROM\n reminders\n INNER JOIN\n channels\n ON\n reminders.channel_id = channels.id\n WHERE\n reminders.uid = ?\n ",
"describe": {
"columns": [
{
@@ -86,6 +86,15 @@
},
{
"ordinal": 9,
"name": "message_json",
"type_info": {
"type": "Json",
"flags": "BLOB | BINARY",
"max_size": 4294967295
}
},
{
"ordinal": 10,
"name": "content",
"type_info": {
"type": "VarString",
@@ -94,7 +103,7 @@
}
},
{
"ordinal": 10,
"ordinal": 11,
"name": "embed_description",
"type_info": {
"type": "VarString",
@@ -103,7 +112,7 @@
}
},
{
"ordinal": 11,
"ordinal": 12,
"name": "set_by",
"type_info": {
"type": "LongLong",
@@ -125,10 +134,11 @@
true,
true,
false,
true,
false,
false,
true
]
},
"hash": "d7f469dd1c7f37f1aca643e9018083b48da1cf988030b9efeae451e77e54a23d"
"hash": "40ceeb037b5266e743a77a4a657d222b769e871b521d3a1745caed0292e9e6cc"
}
@@ -1,12 +0,0 @@
{
"db_name": "MySQL",
"query": "INSERT INTO reminders (\n uid,\n attachment,\n attachment_name,\n channel_id,\n avatar,\n content,\n embed_author,\n embed_author_url,\n embed_color,\n embed_description,\n embed_footer,\n embed_footer_url,\n embed_image_url,\n embed_thumbnail_url,\n embed_title,\n embed_fields,\n enabled,\n expires,\n interval_seconds,\n interval_days,\n interval_months,\n name,\n restartable,\n tts,\n username,\n `utc_time`\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
"describe": {
"columns": [],
"parameters": {
"Right": 26
},
"nullable": []
},
"hash": "4cc3ff2bbdf8502f6e739a002c7aa16df8c4f24de0966b26b268efab97e205e3"
}
@@ -1,6 +1,6 @@
{
"db_name": "MySQL",
"query": "\n SELECT\n reminders.id,\n reminders.uid,\n channels.channel,\n reminders.utc_time,\n reminders.interval_seconds,\n reminders.interval_days,\n reminders.interval_months,\n reminders.expires,\n reminders.enabled,\n reminders.content,\n reminders.embed_description,\n reminders.set_by\n FROM\n reminders\n INNER JOIN\n channels\n ON\n channels.id = reminders.channel_id\n WHERE\n `status` = 'pending' AND\n channels.id = (SELECT dm_channel FROM users WHERE id = ?)\n ",
"query": "\n SELECT\n reminders.id,\n reminders.uid,\n channels.channel,\n reminders.utc_time,\n reminders.interval_seconds,\n reminders.interval_days,\n reminders.interval_months,\n reminders.expires,\n reminders.enabled,\n reminders.message_json,\n reminders.content,\n reminders.embed_description,\n reminders.set_by\n FROM\n reminders\n INNER JOIN\n channels\n ON\n channels.id = reminders.channel_id\n WHERE\n `status` = 'pending' AND\n channels.id = (SELECT dm_channel FROM users WHERE id = ?)\n ",
"describe": {
"columns": [
{
@@ -86,6 +86,15 @@
},
{
"ordinal": 9,
"name": "message_json",
"type_info": {
"type": "Json",
"flags": "BLOB | BINARY",
"max_size": 4294967295
}
},
{
"ordinal": 10,
"name": "content",
"type_info": {
"type": "VarString",
@@ -94,7 +103,7 @@
}
},
{
"ordinal": 10,
"ordinal": 11,
"name": "embed_description",
"type_info": {
"type": "VarString",
@@ -103,7 +112,7 @@
}
},
{
"ordinal": 11,
"ordinal": 12,
"name": "set_by",
"type_info": {
"type": "LongLong",
@@ -125,10 +134,11 @@
true,
true,
false,
true,
false,
false,
true
]
},
"hash": "45e555a2a0664662f55cc738f91abf8c51648fb687f9568c4dd5f48e9273253a"
"hash": "5575971e2a460476adcc70147810caa91fb07f52d788af0f7ec319a15ee5020c"
}
@@ -0,0 +1,12 @@
{
"db_name": "MySQL",
"query": "INSERT IGNORE INTO channels (channel, guild_id) VALUES (?, (SELECT id FROM guilds WHERE guild = ?))",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
},
"hash": "5d7a787e3a6f487c3fe00bd39d308c9350c82e58b0ad1aae0b92824375786f02"
}
@@ -1,6 +1,6 @@
{
"db_name": "MySQL",
"query": "\n SELECT\n reminders.id,\n reminders.uid,\n channels.channel,\n reminders.utc_time,\n reminders.interval_seconds,\n reminders.interval_days,\n reminders.interval_months,\n reminders.expires,\n reminders.enabled,\n reminders.content,\n reminders.embed_description,\n reminders.set_by\n FROM\n reminders\n LEFT JOIN\n channels\n ON\n channels.id = reminders.channel_id\n WHERE\n `status` = 'pending' AND\n channels.guild_id = (SELECT id FROM guilds WHERE guild = ?)\n ",
"query": "\n SELECT\n reminders.id,\n reminders.uid,\n channels.channel,\n reminders.utc_time,\n reminders.interval_seconds,\n reminders.interval_days,\n reminders.interval_months,\n reminders.expires,\n reminders.enabled,\n reminders.message_json,\n reminders.content,\n reminders.embed_description,\n reminders.set_by\n FROM\n reminders\n LEFT JOIN\n channels\n ON\n channels.id = reminders.channel_id\n WHERE\n `status` = 'pending' AND\n channels.guild_id = (SELECT id FROM guilds WHERE guild = ?)\n ",
"describe": {
"columns": [
{
@@ -86,6 +86,15 @@
},
{
"ordinal": 9,
"name": "message_json",
"type_info": {
"type": "Json",
"flags": "BLOB | BINARY",
"max_size": 4294967295
}
},
{
"ordinal": 10,
"name": "content",
"type_info": {
"type": "VarString",
@@ -94,7 +103,7 @@
}
},
{
"ordinal": 10,
"ordinal": 11,
"name": "embed_description",
"type_info": {
"type": "VarString",
@@ -103,7 +112,7 @@
}
},
{
"ordinal": 11,
"ordinal": 12,
"name": "set_by",
"type_info": {
"type": "LongLong",
@@ -125,10 +134,11 @@
true,
true,
false,
true,
false,
false,
true
]
},
"hash": "4dc78a4ebdad0d9fb721389013537093dd814c313bc8ecc80fc9767420afb798"
"hash": "5efa565633215c62ae826b670140c2f36ccc019d56db7a0182ec00f1a2713562"
}
@@ -1,6 +1,6 @@
{
"db_name": "MySQL",
"query": "\n SELECT\n reminders.`id` AS id,\n\n channels.`channel` AS channel_id,\n reminders.`thread_id` AS thread_id,\n channels.`webhook_id` AS webhook_id,\n channels.`webhook_token` AS webhook_token,\n\n channels.`paused` AS 'channel_paused',\n channels.`paused_until` AS 'channel_paused_until',\n reminders.`enabled` AS 'enabled',\n\n reminders.`tts` AS tts,\n reminders.`pin` AS pin,\n reminders.`content` AS content,\n reminders.`attachment` AS attachment,\n reminders.`attachment_name` AS attachment_name,\n\n reminders.`utc_time` AS 'utc_time',\n reminders.`timezone` AS timezone,\n reminders.`restartable` AS restartable,\n reminders.`expires` AS 'expires',\n reminders.`interval_seconds` AS 'interval_seconds',\n reminders.`interval_days` AS 'interval_days',\n reminders.`interval_months` AS 'interval_months',\n\n reminders.`avatar` AS avatar,\n reminders.`username` AS username\n FROM\n reminders\n INNER JOIN\n channels\n ON\n reminders.channel_id = channels.id\n WHERE\n reminders.`status` = 'pending' AND\n reminders.`id` IN (\n SELECT\n MIN(id)\n FROM\n reminders\n WHERE\n reminders.`utc_time` <= NOW() AND\n `status` = 'pending' AND\n (\n reminders.`interval_seconds` IS NOT NULL\n OR reminders.`interval_months` IS NOT NULL\n OR reminders.`interval_days` IS NOT NULL\n OR reminders.enabled\n )\n GROUP BY channel_id\n )\n ",
"query": "\n SELECT\n reminders.`id` AS id,\n\n channels.`channel` AS channel_id,\n reminders.`thread_id` AS thread_id,\n channels.`webhook_id` AS webhook_id,\n channels.`webhook_token` AS webhook_token,\n\n channels.`paused` AS 'channel_paused',\n channels.`paused_until` AS 'channel_paused_until',\n reminders.`enabled` AS 'enabled',\n\n reminders.`tts` AS tts,\n reminders.`pin` AS pin,\n reminders.`content` AS content,\n reminders.`message_json` AS message_json,\n reminders.`attachment` AS attachment,\n reminders.`attachment_name` AS attachment_name,\n\n reminders.`utc_time` AS 'utc_time',\n reminders.`timezone` AS timezone,\n reminders.`restartable` AS restartable,\n reminders.`expires` AS 'expires',\n reminders.`interval_seconds` AS 'interval_seconds',\n reminders.`interval_days` AS 'interval_days',\n reminders.`interval_months` AS 'interval_months',\n\n reminders.`avatar` AS avatar,\n reminders.`username` AS username\n FROM\n reminders\n INNER JOIN\n channels\n ON\n reminders.channel_id = channels.id\n WHERE\n reminders.`status` = 'pending' AND\n reminders.`id` IN (\n SELECT\n MIN(id)\n FROM\n reminders\n WHERE\n reminders.`utc_time` <= NOW() AND\n `status` = 'pending' AND\n (\n reminders.`interval_seconds` IS NOT NULL\n OR reminders.`interval_months` IS NOT NULL\n OR reminders.`interval_days` IS NOT NULL\n OR reminders.enabled\n )\n GROUP BY channel_id\n )\n ",
"describe": {
"columns": [
{
@@ -104,6 +104,15 @@
},
{
"ordinal": 11,
"name": "message_json",
"type_info": {
"type": "Json",
"flags": "BLOB | BINARY",
"max_size": 4294967295
}
},
{
"ordinal": 12,
"name": "attachment",
"type_info": {
"type": "Blob",
@@ -112,7 +121,7 @@
}
},
{
"ordinal": 12,
"ordinal": 13,
"name": "attachment_name",
"type_info": {
"type": "VarString",
@@ -121,7 +130,7 @@
}
},
{
"ordinal": 13,
"ordinal": 14,
"name": "utc_time",
"type_info": {
"type": "Datetime",
@@ -130,7 +139,7 @@
}
},
{
"ordinal": 14,
"ordinal": 15,
"name": "timezone",
"type_info": {
"type": "String",
@@ -139,7 +148,7 @@
}
},
{
"ordinal": 15,
"ordinal": 16,
"name": "restartable",
"type_info": {
"type": "Tiny",
@@ -148,7 +157,7 @@
}
},
{
"ordinal": 16,
"ordinal": 17,
"name": "expires",
"type_info": {
"type": "Datetime",
@@ -157,7 +166,7 @@
}
},
{
"ordinal": 17,
"ordinal": 18,
"name": "interval_seconds",
"type_info": {
"type": "Long",
@@ -166,7 +175,7 @@
}
},
{
"ordinal": 18,
"ordinal": 19,
"name": "interval_days",
"type_info": {
"type": "Long",
@@ -175,7 +184,7 @@
}
},
{
"ordinal": 19,
"ordinal": 20,
"name": "interval_months",
"type_info": {
"type": "Long",
@@ -184,7 +193,7 @@
}
},
{
"ordinal": 20,
"ordinal": 21,
"name": "avatar",
"type_info": {
"type": "VarString",
@@ -193,7 +202,7 @@
}
},
{
"ordinal": 21,
"ordinal": 22,
"name": "username",
"type_info": {
"type": "VarString",
@@ -219,6 +228,7 @@
false,
true,
true,
true,
false,
false,
false,
@@ -230,5 +240,5 @@
true
]
},
"hash": "a33ef7167746183766b6a9b4e31784dd3712fa2b4f72482d4b681e0a9fdbaf1d"
"hash": "6cc6fafaa4dab75639c6e5348d2a836bc6be510e76534c36df709883a4694859"
}
@@ -1,12 +0,0 @@
{
"db_name": "MySQL",
"query": "INSERT INTO reminders (\n uid,\n attachment,\n attachment_name,\n channel_id,\n content,\n embed_author,\n embed_author_url,\n embed_color,\n embed_description,\n embed_footer,\n embed_footer_url,\n embed_image_url,\n embed_thumbnail_url,\n embed_title,\n embed_fields,\n enabled,\n expires,\n interval_seconds,\n interval_days,\n interval_months,\n name,\n tts,\n `utc_time`\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
"describe": {
"columns": [],
"parameters": {
"Right": 23
},
"nullable": []
},
"hash": "7f44451c441507ccd7f8d41633fb156f95a28389fcc9c489fdb228446f88342e"
}
@@ -0,0 +1,12 @@
{
"db_name": "MySQL",
"query": "INSERT INTO reminders (\n uid, attachment, attachment_name, channel_id, message_json,\n enabled, expires, interval_seconds, interval_days, interval_months,\n name, restartable, `utc_time`\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
"describe": {
"columns": [],
"parameters": {
"Right": 13
},
"nullable": []
},
"hash": "8051034e8334a31d5c8ffca9893f85b689955c1e3d144e1162d4c991a47d9852"
}
@@ -1,10 +1,19 @@
{
"db_name": "MySQL",
"query": "\n SELECT\n reminders.attachment_name,\n reminders.avatar,\n channels.channel,\n reminders.content,\n reminders.embed_author,\n reminders.embed_author_url,\n reminders.embed_color,\n reminders.embed_description,\n reminders.embed_footer,\n reminders.embed_footer_url,\n reminders.embed_image_url,\n reminders.embed_thumbnail_url,\n reminders.embed_title,\n reminders.embed_fields,\n reminders.enabled,\n reminders.expires,\n reminders.interval_seconds,\n reminders.interval_days,\n reminders.interval_months,\n reminders.name,\n reminders.restartable,\n reminders.tts,\n reminders.uid,\n reminders.username,\n reminders.utc_time\n FROM reminders\n LEFT JOIN channels ON channels.id = reminders.channel_id\n WHERE uid = ?",
"query": "\n SELECT reminders.attachment,\n reminders.attachment_name,\n reminders.message_json,\n reminders.content,\n reminders.embed_author,\n reminders.embed_author_url,\n reminders.embed_color,\n reminders.embed_description,\n reminders.embed_footer,\n reminders.embed_footer_url,\n reminders.embed_image_url,\n reminders.embed_thumbnail_url,\n reminders.embed_title,\n reminders.embed_fields,\n reminders.enabled,\n reminders.expires,\n reminders.interval_seconds,\n reminders.interval_days,\n reminders.interval_months,\n reminders.name,\n reminders.tts,\n reminders.uid,\n reminders.utc_time\n FROM reminders\n LEFT JOIN channels ON channels.id = reminders.channel_id\n WHERE uid = ?\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "attachment",
"type_info": {
"type": "Blob",
"flags": "BLOB | BINARY",
"max_size": 16777215
}
},
{
"ordinal": 1,
"name": "attachment_name",
"type_info": {
"type": "VarString",
@@ -12,22 +21,13 @@
"max_size": 1040
}
},
{
"ordinal": 1,
"name": "avatar",
"type_info": {
"type": "VarString",
"flags": "",
"max_size": 2048
}
},
{
"ordinal": 2,
"name": "channel",
"name": "message_json",
"type_info": {
"type": "LongLong",
"flags": "UNIQUE_KEY | UNSIGNED | NO_DEFAULT_VALUE",
"max_size": 20
"type": "Json",
"flags": "BLOB | BINARY",
"max_size": 4294967295
}
},
{
@@ -185,15 +185,6 @@
},
{
"ordinal": 20,
"name": "restartable",
"type_info": {
"type": "Tiny",
"flags": "NOT_NULL",
"max_size": 1
}
},
{
"ordinal": 21,
"name": "tts",
"type_info": {
"type": "Tiny",
@@ -202,7 +193,7 @@
}
},
{
"ordinal": 22,
"ordinal": 21,
"name": "uid",
"type_info": {
"type": "VarString",
@@ -211,16 +202,7 @@
}
},
{
"ordinal": 23,
"name": "username",
"type_info": {
"type": "VarString",
"flags": "",
"max_size": 128
}
},
{
"ordinal": 24,
"ordinal": 22,
"name": "utc_time",
"type_info": {
"type": "Datetime",
@@ -255,10 +237,8 @@
false,
false,
false,
false,
true,
false
]
},
"hash": "fa58f079f00bec4c3f9cbb2ee0a607f63c5b586654c541bff6b99eff83ae0a44"
"hash": "8e5e68f6cc7549dc3c1e777def9f6fd8a6b61c6790ee9594ca20c5504ca834fa"
}
@@ -1,6 +1,6 @@
{
"db_name": "MySQL",
"query": "\n SELECT\n reminders.attachment_name,\n reminders.avatar,\n channels.channel,\n reminders.content,\n reminders.embed_author,\n reminders.embed_author_url,\n reminders.embed_color,\n reminders.embed_description,\n reminders.embed_footer,\n reminders.embed_footer_url,\n reminders.embed_image_url,\n reminders.embed_thumbnail_url,\n reminders.embed_title,\n reminders.embed_fields,\n reminders.enabled,\n reminders.expires,\n reminders.interval_seconds,\n reminders.interval_days,\n reminders.interval_months,\n reminders.name,\n reminders.restartable,\n reminders.tts,\n reminders.uid,\n reminders.username,\n reminders.utc_time\n FROM reminders\n LEFT JOIN channels ON channels.id = reminders.channel_id\n WHERE uid = ?",
"query": "\n SELECT\n reminders.attachment_name,\n reminders.avatar,\n channels.channel,\n reminders.message_json,\n reminders.content,\n reminders.embed_author,\n reminders.embed_author_url,\n reminders.embed_color,\n reminders.embed_description,\n reminders.embed_footer,\n reminders.embed_footer_url,\n reminders.embed_image_url,\n reminders.embed_thumbnail_url,\n reminders.embed_title,\n reminders.embed_fields,\n reminders.enabled,\n reminders.expires,\n reminders.interval_seconds,\n reminders.interval_days,\n reminders.interval_months,\n reminders.name,\n reminders.restartable,\n reminders.tts,\n reminders.uid,\n reminders.username,\n reminders.utc_time\n FROM reminders\n LEFT JOIN channels ON channels.id = reminders.channel_id\n WHERE uid = ?",
"describe": {
"columns": [
{
@@ -32,6 +32,15 @@
},
{
"ordinal": 3,
"name": "message_json",
"type_info": {
"type": "Json",
"flags": "BLOB | BINARY",
"max_size": 4294967295
}
},
{
"ordinal": 4,
"name": "content",
"type_info": {
"type": "VarString",
@@ -40,7 +49,7 @@
}
},
{
"ordinal": 4,
"ordinal": 5,
"name": "embed_author",
"type_info": {
"type": "VarString",
@@ -49,7 +58,7 @@
}
},
{
"ordinal": 5,
"ordinal": 6,
"name": "embed_author_url",
"type_info": {
"type": "VarString",
@@ -58,7 +67,7 @@
}
},
{
"ordinal": 6,
"ordinal": 7,
"name": "embed_color",
"type_info": {
"type": "Long",
@@ -67,7 +76,7 @@
}
},
{
"ordinal": 7,
"ordinal": 8,
"name": "embed_description",
"type_info": {
"type": "VarString",
@@ -76,7 +85,7 @@
}
},
{
"ordinal": 8,
"ordinal": 9,
"name": "embed_footer",
"type_info": {
"type": "VarString",
@@ -85,7 +94,7 @@
}
},
{
"ordinal": 9,
"ordinal": 10,
"name": "embed_footer_url",
"type_info": {
"type": "VarString",
@@ -94,7 +103,7 @@
}
},
{
"ordinal": 10,
"ordinal": 11,
"name": "embed_image_url",
"type_info": {
"type": "VarString",
@@ -103,7 +112,7 @@
}
},
{
"ordinal": 11,
"ordinal": 12,
"name": "embed_thumbnail_url",
"type_info": {
"type": "VarString",
@@ -112,7 +121,7 @@
}
},
{
"ordinal": 12,
"ordinal": 13,
"name": "embed_title",
"type_info": {
"type": "VarString",
@@ -121,7 +130,7 @@
}
},
{
"ordinal": 13,
"ordinal": 14,
"name": "embed_fields",
"type_info": {
"type": "Json",
@@ -130,7 +139,7 @@
}
},
{
"ordinal": 14,
"ordinal": 15,
"name": "enabled",
"type_info": {
"type": "Tiny",
@@ -139,7 +148,7 @@
}
},
{
"ordinal": 15,
"ordinal": 16,
"name": "expires",
"type_info": {
"type": "Datetime",
@@ -148,7 +157,7 @@
}
},
{
"ordinal": 16,
"ordinal": 17,
"name": "interval_seconds",
"type_info": {
"type": "Long",
@@ -157,7 +166,7 @@
}
},
{
"ordinal": 17,
"ordinal": 18,
"name": "interval_days",
"type_info": {
"type": "Long",
@@ -166,7 +175,7 @@
}
},
{
"ordinal": 18,
"ordinal": 19,
"name": "interval_months",
"type_info": {
"type": "Long",
@@ -175,7 +184,7 @@
}
},
{
"ordinal": 19,
"ordinal": 20,
"name": "name",
"type_info": {
"type": "VarString",
@@ -184,7 +193,7 @@
}
},
{
"ordinal": 20,
"ordinal": 21,
"name": "restartable",
"type_info": {
"type": "Tiny",
@@ -193,7 +202,7 @@
}
},
{
"ordinal": 21,
"ordinal": 22,
"name": "tts",
"type_info": {
"type": "Tiny",
@@ -202,7 +211,7 @@
}
},
{
"ordinal": 22,
"ordinal": 23,
"name": "uid",
"type_info": {
"type": "VarString",
@@ -211,7 +220,7 @@
}
},
{
"ordinal": 23,
"ordinal": 24,
"name": "username",
"type_info": {
"type": "VarString",
@@ -220,7 +229,7 @@
}
},
{
"ordinal": 24,
"ordinal": 25,
"name": "utc_time",
"type_info": {
"type": "Datetime",
@@ -236,6 +245,7 @@
true,
true,
true,
true,
false,
false,
true,
@@ -260,5 +270,5 @@
false
]
},
"hash": "53db321bc70b45800f696115b65da8550de208104017f8e0d0a163781488a534"
"hash": "8e8d6ebf8b5e69d246a73ef3b746ed3dc5dc6f8204f69aeb55dc5e2ae17319aa"
}
@@ -0,0 +1,12 @@
{
"db_name": "MySQL",
"query": "INSERT INTO reminders (\n uid, attachment, attachment_name, channel_id, message_json,\n enabled, expires, interval_seconds, interval_days, interval_months,\n name, `utc_time`\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
"describe": {
"columns": [],
"parameters": {
"Right": 12
},
"nullable": []
},
"hash": "992666a8cec803ab31a5a86266a07daa4fdf26eeb0969abd4d7987f9672dfae8"
}
@@ -0,0 +1,12 @@
{
"db_name": "MySQL",
"query": "\n UPDATE channels\n SET\n nudge = ?,\n webhook_id = ?,\n webhook_token = ?,\n paused = ?,\n paused_until = ?\n WHERE id = ?\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 6
},
"nullable": []
},
"hash": "af08f3524c316f438feb62a24c67b96197e3655a87efe128914ed386be20d900"
}
@@ -1,6 +1,6 @@
{
"db_name": "MySQL",
"query": "SELECT\n reminders.attachment,\n reminders.attachment_name,\n reminders.content,\n reminders.embed_author,\n reminders.embed_author_url,\n reminders.embed_color,\n reminders.embed_description,\n reminders.embed_footer,\n reminders.embed_footer_url,\n reminders.embed_image_url,\n reminders.embed_thumbnail_url,\n reminders.embed_title,\n reminders.embed_fields,\n reminders.enabled,\n reminders.expires,\n reminders.interval_seconds,\n reminders.interval_days,\n reminders.interval_months,\n reminders.name,\n reminders.tts,\n reminders.uid,\n reminders.utc_time\n FROM reminders\n WHERE uid = ?",
"query": "SELECT\n reminders.attachment,\n reminders.attachment_name,\n reminders.message_json,\n reminders.content,\n reminders.embed_author,\n reminders.embed_author_url,\n reminders.embed_color,\n reminders.embed_description,\n reminders.embed_footer,\n reminders.embed_footer_url,\n reminders.embed_image_url,\n reminders.embed_thumbnail_url,\n reminders.embed_title,\n reminders.embed_fields,\n reminders.enabled,\n reminders.expires,\n reminders.interval_seconds,\n reminders.interval_days,\n reminders.interval_months,\n reminders.name,\n reminders.tts,\n reminders.uid,\n reminders.utc_time\n FROM reminders\n WHERE uid = ?",
"describe": {
"columns": [
{
@@ -23,6 +23,15 @@
},
{
"ordinal": 2,
"name": "message_json",
"type_info": {
"type": "Json",
"flags": "BLOB | BINARY",
"max_size": 4294967295
}
},
{
"ordinal": 3,
"name": "content",
"type_info": {
"type": "VarString",
@@ -31,7 +40,7 @@
}
},
{
"ordinal": 3,
"ordinal": 4,
"name": "embed_author",
"type_info": {
"type": "VarString",
@@ -40,7 +49,7 @@
}
},
{
"ordinal": 4,
"ordinal": 5,
"name": "embed_author_url",
"type_info": {
"type": "VarString",
@@ -49,7 +58,7 @@
}
},
{
"ordinal": 5,
"ordinal": 6,
"name": "embed_color",
"type_info": {
"type": "Long",
@@ -58,7 +67,7 @@
}
},
{
"ordinal": 6,
"ordinal": 7,
"name": "embed_description",
"type_info": {
"type": "VarString",
@@ -67,7 +76,7 @@
}
},
{
"ordinal": 7,
"ordinal": 8,
"name": "embed_footer",
"type_info": {
"type": "VarString",
@@ -76,7 +85,7 @@
}
},
{
"ordinal": 8,
"ordinal": 9,
"name": "embed_footer_url",
"type_info": {
"type": "VarString",
@@ -85,7 +94,7 @@
}
},
{
"ordinal": 9,
"ordinal": 10,
"name": "embed_image_url",
"type_info": {
"type": "VarString",
@@ -94,7 +103,7 @@
}
},
{
"ordinal": 10,
"ordinal": 11,
"name": "embed_thumbnail_url",
"type_info": {
"type": "VarString",
@@ -103,7 +112,7 @@
}
},
{
"ordinal": 11,
"ordinal": 12,
"name": "embed_title",
"type_info": {
"type": "VarString",
@@ -112,7 +121,7 @@
}
},
{
"ordinal": 12,
"ordinal": 13,
"name": "embed_fields",
"type_info": {
"type": "Json",
@@ -121,7 +130,7 @@
}
},
{
"ordinal": 13,
"ordinal": 14,
"name": "enabled",
"type_info": {
"type": "Tiny",
@@ -130,7 +139,7 @@
}
},
{
"ordinal": 14,
"ordinal": 15,
"name": "expires",
"type_info": {
"type": "Datetime",
@@ -139,7 +148,7 @@
}
},
{
"ordinal": 15,
"ordinal": 16,
"name": "interval_seconds",
"type_info": {
"type": "Long",
@@ -148,7 +157,7 @@
}
},
{
"ordinal": 16,
"ordinal": 17,
"name": "interval_days",
"type_info": {
"type": "Long",
@@ -157,7 +166,7 @@
}
},
{
"ordinal": 17,
"ordinal": 18,
"name": "interval_months",
"type_info": {
"type": "Long",
@@ -166,7 +175,7 @@
}
},
{
"ordinal": 18,
"ordinal": 19,
"name": "name",
"type_info": {
"type": "VarString",
@@ -175,7 +184,7 @@
}
},
{
"ordinal": 19,
"ordinal": 20,
"name": "tts",
"type_info": {
"type": "Tiny",
@@ -184,7 +193,7 @@
}
},
{
"ordinal": 20,
"ordinal": 21,
"name": "uid",
"type_info": {
"type": "VarString",
@@ -193,7 +202,7 @@
}
},
{
"ordinal": 21,
"ordinal": 22,
"name": "utc_time",
"type_info": {
"type": "Datetime",
@@ -206,6 +215,7 @@
"Right": 1
},
"nullable": [
true,
true,
true,
false,
@@ -230,5 +240,5 @@
false
]
},
"hash": "2613618c00941649726b31f7c50b5ef50d85323a73def5c87bab2a58c80bf6cd"
"hash": "b708e057ab42c09c36fdc71bda77970fe04e8c066fd9c2701ac25afb059c32b6"
}
@@ -1,6 +1,6 @@
{
"db_name": "MySQL",
"query": "\n SELECT\n reminders.attachment,\n reminders.attachment_name,\n reminders.content,\n reminders.embed_author,\n reminders.embed_author_url,\n reminders.embed_color,\n reminders.embed_description,\n reminders.embed_footer,\n reminders.embed_footer_url,\n reminders.embed_image_url,\n reminders.embed_thumbnail_url,\n reminders.embed_title,\n IFNULL(reminders.embed_fields, '[]') AS embed_fields,\n reminders.enabled,\n reminders.expires,\n reminders.interval_seconds,\n reminders.interval_days,\n reminders.interval_months,\n reminders.name,\n reminders.tts,\n reminders.uid,\n reminders.utc_time\n FROM reminders\n INNER JOIN channels ON channels.id = reminders.channel_id\n WHERE `status` = 'pending' AND channels.channel = ?\n ",
"query": "\n SELECT\n reminders.attachment,\n reminders.attachment_name,\n reminders.message_json,\n reminders.content,\n reminders.embed_author,\n reminders.embed_author_url,\n reminders.embed_color,\n reminders.embed_description,\n reminders.embed_footer,\n reminders.embed_footer_url,\n reminders.embed_image_url,\n reminders.embed_thumbnail_url,\n reminders.embed_title,\n IFNULL(reminders.embed_fields, '[]') AS embed_fields,\n reminders.enabled,\n reminders.expires,\n reminders.interval_seconds,\n reminders.interval_days,\n reminders.interval_months,\n reminders.name,\n reminders.tts,\n reminders.uid,\n reminders.utc_time\n FROM reminders\n INNER JOIN channels ON channels.id = reminders.channel_id\n WHERE `status` = 'pending' AND channels.channel = ?\n ",
"describe": {
"columns": [
{
@@ -23,6 +23,15 @@
},
{
"ordinal": 2,
"name": "message_json",
"type_info": {
"type": "Json",
"flags": "BLOB | BINARY",
"max_size": 4294967295
}
},
{
"ordinal": 3,
"name": "content",
"type_info": {
"type": "VarString",
@@ -31,7 +40,7 @@
}
},
{
"ordinal": 3,
"ordinal": 4,
"name": "embed_author",
"type_info": {
"type": "VarString",
@@ -40,7 +49,7 @@
}
},
{
"ordinal": 4,
"ordinal": 5,
"name": "embed_author_url",
"type_info": {
"type": "VarString",
@@ -49,7 +58,7 @@
}
},
{
"ordinal": 5,
"ordinal": 6,
"name": "embed_color",
"type_info": {
"type": "Long",
@@ -58,7 +67,7 @@
}
},
{
"ordinal": 6,
"ordinal": 7,
"name": "embed_description",
"type_info": {
"type": "VarString",
@@ -67,7 +76,7 @@
}
},
{
"ordinal": 7,
"ordinal": 8,
"name": "embed_footer",
"type_info": {
"type": "VarString",
@@ -76,7 +85,7 @@
}
},
{
"ordinal": 8,
"ordinal": 9,
"name": "embed_footer_url",
"type_info": {
"type": "VarString",
@@ -85,7 +94,7 @@
}
},
{
"ordinal": 9,
"ordinal": 10,
"name": "embed_image_url",
"type_info": {
"type": "VarString",
@@ -94,7 +103,7 @@
}
},
{
"ordinal": 10,
"ordinal": 11,
"name": "embed_thumbnail_url",
"type_info": {
"type": "VarString",
@@ -103,7 +112,7 @@
}
},
{
"ordinal": 11,
"ordinal": 12,
"name": "embed_title",
"type_info": {
"type": "VarString",
@@ -112,7 +121,7 @@
}
},
{
"ordinal": 12,
"ordinal": 13,
"name": "embed_fields",
"type_info": {
"type": "VarString",
@@ -121,7 +130,7 @@
}
},
{
"ordinal": 13,
"ordinal": 14,
"name": "enabled",
"type_info": {
"type": "Tiny",
@@ -130,7 +139,7 @@
}
},
{
"ordinal": 14,
"ordinal": 15,
"name": "expires",
"type_info": {
"type": "Datetime",
@@ -139,7 +148,7 @@
}
},
{
"ordinal": 15,
"ordinal": 16,
"name": "interval_seconds",
"type_info": {
"type": "Long",
@@ -148,7 +157,7 @@
}
},
{
"ordinal": 16,
"ordinal": 17,
"name": "interval_days",
"type_info": {
"type": "Long",
@@ -157,7 +166,7 @@
}
},
{
"ordinal": 17,
"ordinal": 18,
"name": "interval_months",
"type_info": {
"type": "Long",
@@ -166,7 +175,7 @@
}
},
{
"ordinal": 18,
"ordinal": 19,
"name": "name",
"type_info": {
"type": "VarString",
@@ -175,7 +184,7 @@
}
},
{
"ordinal": 19,
"ordinal": 20,
"name": "tts",
"type_info": {
"type": "Tiny",
@@ -184,7 +193,7 @@
}
},
{
"ordinal": 20,
"ordinal": 21,
"name": "uid",
"type_info": {
"type": "VarString",
@@ -193,7 +202,7 @@
}
},
{
"ordinal": 21,
"ordinal": 22,
"name": "utc_time",
"type_info": {
"type": "Datetime",
@@ -206,6 +215,7 @@
"Right": 1
},
"nullable": [
true,
true,
true,
false,
@@ -230,5 +240,5 @@
false
]
},
"hash": "48a9268e9106a3a05e86ab36551944ba855a07b0241e912c6b1adee779c6f0ea"
"hash": "d9e0f517df37a6c03868b6e1470169eaf06d2e6f1a9df62165656d3e97dbe929"
}
@@ -1,6 +1,6 @@
{
"db_name": "MySQL",
"query": "\n SELECT\n reminders.id,\n reminders.uid,\n channels.channel,\n reminders.utc_time,\n reminders.interval_seconds,\n reminders.interval_days,\n reminders.interval_months,\n reminders.expires,\n reminders.enabled,\n reminders.content,\n reminders.embed_description,\n reminders.set_by\n FROM\n reminders\n INNER JOIN\n channels\n ON\n reminders.channel_id = channels.id\n WHERE\n `status` = 'pending' AND\n channels.channel = ? AND\n reminders.enabled >= ?\n ORDER BY\n reminders.utc_time\n ",
"query": "\n SELECT\n reminders.id,\n reminders.uid,\n channels.channel,\n reminders.utc_time,\n reminders.interval_seconds,\n reminders.interval_days,\n reminders.interval_months,\n reminders.expires,\n reminders.enabled,\n reminders.message_json,\n reminders.content,\n reminders.embed_description,\n reminders.set_by\n FROM\n reminders\n INNER JOIN\n channels\n ON\n reminders.channel_id = channels.id\n WHERE\n `status` = 'pending' AND\n channels.channel = ? AND\n reminders.enabled >= ?\n ORDER BY\n reminders.utc_time\n ",
"describe": {
"columns": [
{
@@ -86,6 +86,15 @@
},
{
"ordinal": 9,
"name": "message_json",
"type_info": {
"type": "Json",
"flags": "BLOB | BINARY",
"max_size": 4294967295
}
},
{
"ordinal": 10,
"name": "content",
"type_info": {
"type": "VarString",
@@ -94,7 +103,7 @@
}
},
{
"ordinal": 10,
"ordinal": 11,
"name": "embed_description",
"type_info": {
"type": "VarString",
@@ -103,7 +112,7 @@
}
},
{
"ordinal": 11,
"ordinal": 12,
"name": "set_by",
"type_info": {
"type": "LongLong",
@@ -125,10 +134,11 @@
true,
true,
false,
true,
false,
false,
true
]
},
"hash": "d2921961627fef0e12892dbbcd4b891e58c0e52c20897aab3d95365774c01bda"
"hash": "ec12254245aa433f8d31711c2942254d91c61f6b47a5b427c43a8cac468379a3"
}
@@ -0,0 +1 @@
ALTER TABLE reminders ADD COLUMN message_json JSON DEFAULT NULL;
+1
View File
@@ -10,6 +10,7 @@ mod event_handlers;
#[cfg(not(test))]
mod hooks;
mod interval_parser;
mod message;
mod metrics;
#[cfg(not(test))]
mod models;
+387
View File
@@ -0,0 +1,387 @@
//! Conversion between the dashboard's message fields and Discord webhook payloads.
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
use sqlx::{types::Json, FromRow, MySqlConnection};
#[derive(Default, Deserialize, Serialize, FromRow)]
#[serde(default)]
struct MessageFields {
content: String,
tts: bool,
username: Option<String>,
avatar: Option<String>,
embed_title: String,
embed_description: String,
embed_author: String,
embed_author_url: Option<String>,
embed_footer: String,
embed_footer_url: Option<String>,
embed_image_url: Option<String>,
embed_thumbnail_url: Option<String>,
embed_color: u32,
embed_fields: Option<Json<Value>>,
message_json: Option<Json<Value>>,
attachment_name: Option<String>,
has_attachment: bool,
}
const EMBED_PATHS: &[(&str, &[&str])] = &[
("embed_title", &["title"]),
("embed_description", &["description"]),
("embed_author", &["author", "name"]),
("embed_author_url", &["author", "icon_url"]),
("embed_footer", &["footer", "text"]),
("embed_footer_url", &["footer", "icon_url"]),
("embed_image_url", &["image", "url"]),
("embed_thumbnail_url", &["thumbnail", "url"]),
("embed_color", &["color"]),
("embed_fields", &["fields"]),
];
fn set_path(target: &mut Value, path: &[&str], value: Value) {
if !target.is_object() {
*target = json!({});
}
let object = target.as_object_mut().unwrap();
if path.len() == 1 {
if value.is_null() {
object.remove(path[0]);
} else {
object.insert(path[0].to_string(), value);
}
} else {
set_path(object.entry(path[0]).or_insert_with(|| json!({})), &path[1..], value);
}
}
fn embed_has_content(embed: &Value) -> bool {
["/title", "/description", "/author/name", "/footer/text", "/footer/icon_url",
"/image/url", "/thumbnail/url"]
.iter()
.any(|path| embed.pointer(path).and_then(Value::as_str).is_some_and(|s| !s.trim().is_empty()))
|| embed["fields"].as_array().is_some_and(|fields| !fields.is_empty())
// Preserve payload features the dashboard does not edit.
|| embed.as_object().is_some_and(|object| object.keys().any(|key|
!["title", "description", "author", "footer", "image", "thumbnail", "color", "fields"].contains(&key.as_str())))
}
fn discord_fields(value: &Value) -> Value {
match value.as_array() {
Some(fields) => Value::Array(
fields
.iter()
.map(|field| {
json!({
"name": field["title"], "value": field["value"], "inline": field["inline"]
})
})
.collect(),
),
None => json!([]),
}
}
/// Use an explicit payload verbatim, or build one from existing dashboard fields.
pub fn payload(reminder: &impl Serialize) -> Value {
let fields = serde_json::to_value(reminder).expect("Reminder fields are serializable");
if !fields["message_json"].is_null() {
return fields["message_json"].clone();
}
let mut payload = json!({ "content": fields["content"], "tts": fields["tts"] });
if fields["username"].as_str().is_some_and(|s| !s.is_empty()) {
payload["username"] = fields["username"].clone();
}
if !fields["avatar"].is_null() {
payload["avatar_url"] = fields["avatar"].clone();
}
let mut embed = json!({});
for (field, path) in EMBED_PATHS {
let value = if *field == "embed_fields" {
discord_fields(&fields[*field])
} else {
fields[*field].clone()
};
set_path(&mut embed, path, value);
}
if embed_has_content(&embed) {
payload["embeds"] = json!([embed]);
}
if (!fields["attachment"].is_null() || fields["has_attachment"].as_bool() == Some(true))
&& fields["attachment_name"].is_string()
{
payload["attachments"] = json!([{ "id": 0, "filename": fields["attachment_name"] }]);
}
payload
}
/// Present the first embed through the existing dashboard controls.
pub fn response(reminder: impl Serialize) -> Value {
let mut reminder = serde_json::to_value(reminder).expect("Reminder fields are serializable");
if let Some(reminders) = reminder.as_array_mut() {
for reminder in reminders {
*reminder = response(&*reminder);
}
return reminder;
}
let payload = reminder
.as_object_mut()
.and_then(|object| object.remove("message_json"))
.unwrap_or(Value::Null);
if payload.is_null() {
return reminder;
}
reminder["content"] = payload["content"].as_str().unwrap_or_default().into();
reminder["tts"] = payload["tts"].as_bool().unwrap_or(false).into();
reminder["username"] = payload["username"].clone();
reminder["avatar"] = payload["avatar_url"].clone();
for (field, path) in EMBED_PATHS {
let value = payload["embeds"][0]
.pointer(&format!("/{}", path.join("/")))
.cloned()
.unwrap_or(Value::Null);
reminder[*field] = match *field {
"embed_fields" => Value::Array(value.as_array().map(|fields| fields.iter().map(|field| json!({
"title": field["name"], "value": field["value"], "inline": field["inline"].as_bool().unwrap_or(false)
})).collect()).unwrap_or_default()),
"embed_color" => value.as_u64().unwrap_or(0).into(),
"embed_title" | "embed_description" | "embed_author" | "embed_footer" => value.as_str().unwrap_or_default().into(),
_ => value,
};
}
reminder
}
pub fn is_message_field(field: &str) -> bool {
["content", "tts", "username", "avatar"].contains(&field)
|| EMBED_PATHS.iter().any(|(name, _)| *name == field)
}
fn patch(payload: &mut Value, field: &str, mut value: Value) {
if let Some((_, path)) = EMBED_PATHS.iter().find(|(name, _)| *name == field) {
if !payload["embeds"].is_array() {
payload["embeds"] = json!([]);
}
let embeds = payload["embeds"].as_array_mut().unwrap();
if embeds.is_empty() {
embeds.push(json!({}));
}
if field == "embed_fields" {
value = discord_fields(&value);
}
set_path(&mut embeds[0], path, value);
if !embed_has_content(&embeds[0]) {
embeds.remove(0);
}
} else {
if field == "username" && value.as_str() == Some("") {
value = Value::Null;
}
set_path(payload, &[if field == "avatar" { "avatar_url" } else { field }], value);
}
}
/// Convert legacy rows on first edit and preserve unedited payload keys.
pub async fn update_field(
connection: &mut MySqlConnection,
uid: &str,
field: &str,
value: &impl Serialize,
) -> Result<(), sqlx::Error> {
let fields = sqlx::query_as::<_, MessageFields>(
"SELECT content, tts, username, avatar, embed_title, embed_description,
embed_author, embed_author_url, embed_footer, embed_footer_url, embed_image_url,
embed_thumbnail_url, embed_color, embed_fields, message_json, attachment_name,
attachment IS NOT NULL AS has_attachment FROM reminders WHERE uid = ? FOR UPDATE",
)
.bind(uid)
.fetch_one(&mut *connection)
.await?;
let mut message = payload(&fields);
let value = if field == "attachments" {
if fields.has_attachment {
fields
.attachment_name
.as_ref()
.map(|name| json!([{ "id": 0, "filename": name }]))
.unwrap_or_else(|| json!([]))
} else {
json!([])
}
} else {
serde_json::to_value(value).map_err(|e| sqlx::Error::Encode(e.into()))?
};
patch(&mut message, field, value);
sqlx::query("UPDATE reminders SET message_json = ? WHERE uid = ?")
.bind(Json(message))
.bind(uid)
.execute(connection)
.await?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn builds_discord_payload_and_omits_empty_embed() {
assert_eq!(
payload(&json!({"content": "hello", "tts": true})),
json!({"content": "hello", "tts": true})
);
let message = payload(&json!({"content": "", "tts": false, "embed_description": "body",
"embed_fields": [{"title": "heading", "value": "value", "inline": true}],
"attachment": "bytes", "attachment_name": "file.txt"}));
assert_eq!(message["embeds"][0]["fields"][0]["name"], "heading");
assert_eq!(message["attachments"], json!([{ "id": 0, "filename": "file.txt" }]));
assert_eq!(response(json!({"message_json": message}))["embed_description"], "body");
}
#[test]
fn explicit_payload_is_exact() {
let exact = json!({"content": "<<timenow:UTC:%Y>>", "flags": 32768, "components": [], "custom": true});
assert_eq!(
payload(&json!({"message_json": exact, "content": "ignored", "tts": true})),
exact
);
}
#[test]
fn null_payload_falls_back_to_legacy_fields() {
let legacy = json!({
"message_json": null, "content": "legacy", "tts": false,
"username": "Reminder", "avatar": "https://example.com/avatar.png"
});
assert_eq!(
payload(&legacy),
json!({
"content": "legacy", "tts": false, "username": "Reminder",
"avatar_url": "https://example.com/avatar.png"
})
);
let mut expected_response = legacy.clone();
expected_response.as_object_mut().unwrap().remove("message_json");
assert_eq!(response(legacy), expected_response);
}
#[test]
fn dashboard_response_uses_payload_and_preserves_schedule() {
let reminder = response(json!({
"uid": "reminder-id", "utc_time": "2026-10-12T12:00:00", "enabled": true,
"content": "stale", "embed_description": "stale", "tts": false,
"message_json": {
"content": "current", "tts": true,
"embeds": [{"description": "body", "fields": [{"name": "heading", "value": "value"}]}]
}
}));
assert_eq!(reminder["content"], "current");
assert_eq!(reminder["tts"], true);
assert_eq!(reminder["embed_description"], "body");
assert_eq!(
reminder["embed_fields"],
json!([{"title": "heading", "value": "value", "inline": false}])
);
assert_eq!(reminder["uid"], "reminder-id");
assert_eq!(reminder["utc_time"], "2026-10-12T12:00:00");
assert_eq!(reminder["enabled"], true);
assert!(reminder.get("message_json").is_none());
}
#[test]
fn clearing_webhook_identity_preserves_other_payload_keys() {
let mut message = json!({
"content": "hello", "username": "Reminder",
"avatar_url": "https://example.com/avatar.png", "flags": 4
});
patch(&mut message, "username", json!(""));
patch(&mut message, "avatar", Value::Null);
assert_eq!(message, json!({"content": "hello", "flags": 4}));
}
#[test]
fn edits_preserve_extra_payload_features() {
let mut message = json!({"flags": 4, "embeds": [{"description": "before", "url": "https://example.com"}, {"title": "second"}]});
patch(&mut message, "embed_description", json!("after"));
patch(&mut message, "embed_author_url", json!("https://example.com/icon.png"));
assert_eq!(message["flags"], 4);
assert_eq!(message["embeds"][0]["description"], "after");
assert_eq!(message["embeds"][0]["url"], "https://example.com");
assert_eq!(message["embeds"][1]["title"], "second");
patch(&mut message, "embed_author_url", Value::Null);
assert!(message["embeds"][0]["author"]["icon_url"].is_null());
}
#[test]
fn clearing_last_embed_content_removes_embed() {
let mut message = json!({"embeds": [{"description": "body", "color": 123}]});
patch(&mut message, "embed_description", json!(""));
assert_eq!(message["embeds"], json!([]));
}
#[tokio::test]
#[ignore = "requires MESSAGE_JSON_TEST_DATABASE_URL pointing to an isolated MySQL database"]
async fn database_edits_convert_legacy_messages_and_preserve_payload() {
let pool =
sqlx::MySqlPool::connect(&std::env::var("MESSAGE_JSON_TEST_DATABASE_URL").unwrap())
.await
.unwrap();
let mut transaction = pool.begin().await.unwrap();
let channel = sqlx::query("INSERT INTO channels (channel) VALUES (?)")
.bind(rand::random::<u64>())
.execute(&mut *transaction)
.await
.unwrap()
.last_insert_id();
let uid = format!("message-json-test-{}", rand::random::<u64>());
sqlx::query("INSERT INTO reminders (uid, channel_id, `utc_time`, content, embed_description, attachment, attachment_name) VALUES (?, ?, NOW(), 'legacy', 'embed', 'bytes', 'file.txt')")
.bind(&uid).bind(channel).execute(&mut *transaction).await.unwrap();
update_field(&mut transaction, &uid, "content", &"edited").await.unwrap();
let stored: (Json<Value>, String) =
sqlx::query_as("SELECT message_json, content FROM reminders WHERE uid = ?")
.bind(&uid)
.fetch_one(&mut *transaction)
.await
.unwrap();
assert_eq!(stored.0["content"], "edited");
assert_eq!(stored.0["embeds"][0]["description"], "embed");
assert_eq!(stored.0["attachments"][0]["filename"], "file.txt");
assert_eq!(stored.1, "legacy");
let exact = json!({"content": "exact", "custom": [1, 2], "embeds": [{"description": "first"}, {"description": "second"}]});
sqlx::query("UPDATE reminders SET message_json = ? WHERE uid = ?")
.bind(Json(exact))
.bind(&uid)
.execute(&mut *transaction)
.await
.unwrap();
update_field(&mut transaction, &uid, "tts", &true).await.unwrap();
update_field(&mut transaction, &uid, "embed_description", &"updated").await.unwrap();
let stored: (Json<Value>,) =
sqlx::query_as("SELECT message_json FROM reminders WHERE uid = ?")
.bind(&uid)
.fetch_one(&mut *transaction)
.await
.unwrap();
assert_eq!(stored.0["tts"], true);
assert_eq!(stored.0["custom"], json!([1, 2]));
assert_eq!(stored.0["embeds"][0]["description"], "updated");
assert_eq!(stored.0["embeds"][1]["description"], "second");
sqlx::query("UPDATE reminders SET attachment = NULL WHERE uid = ?")
.bind(&uid)
.execute(&mut *transaction)
.await
.unwrap();
update_field(&mut transaction, &uid, "attachments", &()).await.unwrap();
let stored: (Json<Value>,) =
sqlx::query_as("SELECT message_json FROM reminders WHERE uid = ?")
.bind(&uid)
.fetch_one(&mut *transaction)
.await
.unwrap();
assert_eq!(stored.0["attachments"], json!([]));
transaction.rollback().await.unwrap();
}
}
+10 -6
View File
@@ -6,7 +6,7 @@ use poise::serenity_prelude::{
model::id::{ChannelId, GuildId, UserId},
ChannelType,
};
use sqlx::MySqlPool;
use sqlx::{types::Json, MySqlPool};
use crate::{
consts::{DAY, MAX_TIME, MIN_INTERVAL},
@@ -76,6 +76,12 @@ impl ReminderBuilder {
if utc_time < (Utc::now() - TimeDelta::try_minutes(1).unwrap()).naive_local() {
Err(ReminderError::PastTime)
} else {
let mut message_json =
serde_json::json!({"content": self.content, "tts": self.tts});
if let (Some(_), Some(name)) = (&self.attachment, &self.attachment_name) {
message_json["attachments"] =
serde_json::json!([{ "id": 0, "filename": name }]);
}
sqlx::query!(
"
INSERT INTO reminders (
@@ -88,13 +94,12 @@ impl ReminderBuilder {
`interval_days`,
`interval_months`,
`expires`,
`content`,
`tts`,
`message_json`,
`attachment_name`,
`attachment`,
`set_by`
) VALUES (
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
)
",
self.uid,
@@ -106,8 +111,7 @@ impl ReminderBuilder {
self.interval_days,
self.interval_months,
self.expires,
self.content,
self.tts,
Json(message_json),
self.attachment_name,
self.attachment,
self.set_by
+14
View File
@@ -49,6 +49,7 @@ pub struct Reminder {
pub interval_months: Option<u32>,
pub expires: Option<NaiveDateTime>,
pub enabled: bool,
pub message_json: Option<sqlx::types::Json<serde_json::Value>>,
pub content: String,
pub embed_description: String,
pub set_by: Option<u64>,
@@ -83,6 +84,7 @@ impl Reminder {
reminders.interval_months,
reminders.expires,
reminders.enabled,
reminders.message_json,
reminders.content,
reminders.embed_description,
reminders.set_by
@@ -116,6 +118,7 @@ impl Reminder {
reminders.interval_months,
reminders.expires,
reminders.enabled,
reminders.message_json,
reminders.content,
reminders.embed_description,
reminders.set_by
@@ -156,6 +159,7 @@ impl Reminder {
reminders.interval_months,
reminders.expires,
reminders.enabled,
reminders.message_json,
reminders.content,
reminders.embed_description,
reminders.set_by
@@ -215,6 +219,7 @@ impl Reminder {
reminders.interval_months,
reminders.expires,
reminders.enabled,
reminders.message_json,
reminders.content,
reminders.embed_description,
reminders.set_by
@@ -251,6 +256,7 @@ impl Reminder {
reminders.interval_months,
reminders.expires,
reminders.enabled,
reminders.message_json,
reminders.content,
reminders.embed_description,
reminders.set_by
@@ -284,6 +290,7 @@ impl Reminder {
reminders.interval_months,
reminders.expires,
reminders.enabled,
reminders.message_json,
reminders.content,
reminders.embed_description,
reminders.set_by
@@ -321,6 +328,13 @@ impl Reminder {
}
pub fn display_content(&self) -> &str {
if let Some(message) = &self.message_json {
let content = message["content"].as_str().unwrap_or_default();
if !content.is_empty() {
return content;
}
return message["embeds"][0]["description"].as_str().unwrap_or_default();
}
if self.content.is_empty() {
&self.embed_description
} else {
+54 -1
View File
@@ -17,6 +17,7 @@ use poise::serenity_prelude::{
Error, Result,
};
use regex::{Captures, Regex};
use secrecy::ExposeSecret;
use serde::Deserialize;
use sqlx::{
types::{
@@ -341,6 +342,7 @@ pub struct Reminder {
tts: bool,
pin: bool,
content: String,
message_json: Option<Json<serde_json::Value>>,
attachment: Option<Vec<u8>>,
attachment_name: Option<String>,
@@ -376,6 +378,7 @@ impl Reminder {
reminders.`tts` AS tts,
reminders.`pin` AS pin,
reminders.`content` AS content,
reminders.`message_json` AS message_json,
reminders.`attachment` AS attachment,
reminders.`attachment_name` AS attachment_name,
@@ -585,6 +588,15 @@ impl Reminder {
let _ = http.as_ref().pin_message(self.channel_id.into(), message_id.into(), None).await;
}
fn files(&self) -> Vec<CreateAttachment> {
match (&self.attachment, &self.attachment_name) {
(Some(attachment), Some(name)) => {
vec![CreateAttachment::bytes(attachment.clone(), name)]
}
_ => vec![],
}
}
pub async fn send(
&self,
pool: impl Executor<'_, Database = Database> + Copy,
@@ -595,6 +607,22 @@ impl Reminder {
reminder: &Reminder,
embed: Option<CreateEmbed>,
) -> Result<()> {
if let Some(payload) = &reminder.message_json {
let files = reminder.files();
let message = cache_http
.http()
.send_message(
ChannelId::new(reminder.thread_id.unwrap_or(reminder.channel_id)),
files,
&payload.0,
)
.await?;
if reminder.pin {
reminder.pin_message(message.id, cache_http.http()).await;
}
return Ok(());
}
let channel = if let Some(thread_id) = reminder.thread_id {
ChannelId::new(thread_id).to_channel(&cache_http).await
} else {
@@ -650,6 +678,27 @@ impl Reminder {
webhook: Webhook,
embed: Option<CreateEmbed>,
) -> Result<()> {
if let Some(payload) = &reminder.message_json {
let token = webhook.token.as_ref().ok_or(Error::Other("Webhook token missing"))?;
let message = cache_http
.http()
.execute_webhook(
webhook.id,
reminder.thread_id.map(ChannelId::new),
token.expose_secret(),
reminder.pin || reminder.restartable,
reminder.files(),
&payload.0,
)
.await?;
if reminder.pin {
if let Some(message) = message {
reminder.pin_message(message.id, cache_http.http()).await;
}
}
return Ok(());
}
let mut builder = if let Some(thread_id) = reminder.thread_id {
ExecuteWebhook::new()
.content(&reminder.content)
@@ -712,7 +761,11 @@ impl Reminder {
.execute(pool)
.await;
let embed = Embed::from_id(pool, self.id).await.map(|e| e.into());
let embed = if self.message_json.is_none() {
Embed::from_id(pool, self.id).await.map(|e| e.into())
} else {
None
};
let result = if let (Some(webhook_id), Some(webhook_token)) =
(self.webhook_id, &self.webhook_token)
+1 -1
View File
@@ -10,7 +10,7 @@ use crate::Database;
pub struct Transaction<'a>(sqlx::Transaction<'a, Database>);
impl Transaction<'_> {
pub fn executor(&mut self) -> impl sqlx::Executor<'_, Database = Database> {
pub fn executor(&mut self) -> &mut sqlx::MySqlConnection {
&mut *(self.0)
}
+12 -2
View File
@@ -57,7 +57,10 @@ macro_rules! check_url_opt {
macro_rules! update_field {
($pool:expr, $error:ident, $reminder:ident.[$field:ident]) => {
if let Some(value) = &$reminder.$field {
match sqlx::query(concat!(
let result = if crate::message::is_message_field(stringify!($field)) {
crate::message::update_field($pool, &$reminder.uid, stringify!($field), value).await
} else {
let result = sqlx::query(concat!(
"UPDATE reminders SET `",
stringify!($field),
"` = ? WHERE uid = ?"
@@ -66,7 +69,14 @@ macro_rules! update_field {
.bind(&$reminder.uid)
.execute($pool)
.await
{
.map(|_| ());
if result.is_ok() && ["attachment", "attachment_name"].contains(&stringify!($field)) {
crate::message::update_field($pool, &$reminder.uid, "attachments", &()).await
} else {
result
}
};
match result {
Ok(_) => {}
Err(e) => {
warn!(
@@ -83,6 +83,7 @@ pub async fn get_reminders(
reminders.attachment_name,
reminders.avatar,
channels.channel,
reminders.message_json,
reminders.content,
reminders.embed_author,
reminders.embed_author_url,
@@ -121,7 +122,7 @@ pub async fn get_reminders(
query
.fetch_all(pool.inner())
.await
.map(|reminders| Ok(json!(reminders)))
.map(|reminders| Ok(crate::message::response(reminders)))
.unwrap_or_else(|e| {
warn!("Failed to complete SQL query: {:?}", e);
@@ -349,6 +350,7 @@ pub async fn edit_reminder(
reminders.attachment_name,
reminders.avatar,
channels.channel,
reminders.message_json,
reminders.content,
reminders.embed_author,
reminders.embed_author_url,
@@ -379,7 +381,9 @@ pub async fn edit_reminder(
.fetch_one(pool.inner())
.await
{
Ok(reminder) => Ok(json!({"reminder": reminder, "errors": error})),
Ok(reminder) => {
Ok(json!({"reminder": crate::message::response(reminder), "errors": error}))
}
Err(e) => {
warn!("Error exiting `edit_reminder': {:?}", e);
+21 -37
View File
@@ -24,17 +24,24 @@ use crate::web::{
#[derive(Serialize, Deserialize)]
pub struct Reminder {
pub message_json: Option<Json<serde_json::Value>>,
pub attachment: Option<Attachment>,
pub attachment_name: Option<String>,
#[serde(default)]
pub content: String,
#[serde(default)]
pub embed_author: String,
pub embed_author_url: Option<String>,
#[serde(default)]
pub embed_color: u32,
#[serde(default)]
pub embed_description: String,
#[serde(default)]
pub embed_footer: String,
pub embed_footer_url: Option<String>,
pub embed_image_url: Option<String>,
pub embed_thumbnail_url: Option<String>,
#[serde(default)]
pub embed_title: String,
pub embed_fields: Option<Json<Vec<EmbedField>>>,
pub enabled: bool,
@@ -44,6 +51,7 @@ pub struct Reminder {
pub interval_months: Option<u32>,
#[serde(default = "name_default")]
pub name: String,
#[serde(default)]
pub tts: bool,
#[serde(default)]
pub uid: String,
@@ -79,6 +87,10 @@ pub async fn create_reminder(
let channel = channel.unwrap();
if reminder.message_json.as_ref().is_some_and(|message| !message.is_object()) {
return Err(json!({"error": "message_json must be an object"}));
}
// validate lengths
check_length!(MAX_NAME_LENGTH, reminder.name);
check_length!(MAX_CONTENT_LENGTH, reminder.content);
@@ -139,55 +151,26 @@ pub async fn create_reminder(
let name = if reminder.name.is_empty() { name_default() } else { reminder.name.clone() };
let new_uid = generate_uid();
let message_json = Json(crate::message::payload(&reminder));
// write to db
match sqlx::query!(
"INSERT INTO reminders (
uid,
attachment,
attachment_name,
channel_id,
content,
embed_author,
embed_author_url,
embed_color,
embed_description,
embed_footer,
embed_footer_url,
embed_image_url,
embed_thumbnail_url,
embed_title,
embed_fields,
enabled,
expires,
interval_seconds,
interval_days,
interval_months,
name,
tts,
`utc_time`
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
uid, attachment, attachment_name, channel_id, message_json,
enabled, expires, interval_seconds, interval_days, interval_months,
name, `utc_time`
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
new_uid,
reminder.attachment,
reminder.attachment_name,
channel,
reminder.content,
reminder.embed_author,
reminder.embed_author_url,
reminder.embed_color,
reminder.embed_description,
reminder.embed_footer,
reminder.embed_footer_url,
reminder.embed_image_url,
reminder.embed_thumbnail_url,
reminder.embed_title,
reminder.embed_fields,
message_json,
reminder.enabled,
reminder.expires,
reminder.interval_seconds,
reminder.interval_days,
reminder.interval_months,
name,
reminder.tts,
reminder.utc_time,
)
.execute(transaction.executor())
@@ -198,6 +181,7 @@ pub async fn create_reminder(
"SELECT
reminders.attachment,
reminders.attachment_name,
reminders.message_json,
reminders.content,
reminders.embed_author,
reminders.embed_author_url,
@@ -224,7 +208,7 @@ pub async fn create_reminder(
)
.fetch_one(transaction.executor())
.await
.map(|r| Ok(json!(r)))
.map(|r| Ok(crate::message::response(r)))
.unwrap_or_else(|e| {
warn!("Failed to complete SQL query: {:?}", e);
@@ -69,6 +69,7 @@ pub async fn get_reminders(
SELECT
reminders.attachment,
reminders.attachment_name,
reminders.message_json,
reminders.content,
reminders.embed_author,
reminders.embed_author_url,
@@ -97,7 +98,7 @@ pub async fn get_reminders(
)
.fetch_all(pool.inner())
.await
.map(|r| Ok(json!(r)))
.map(|r| Ok(crate::message::response(r)))
.unwrap_or_else(|e| {
warn!("Failed to complete SQL query: {:?}", e);
@@ -246,6 +247,7 @@ pub async fn edit_reminder(
"
SELECT reminders.attachment,
reminders.attachment_name,
reminders.message_json,
reminders.content,
reminders.embed_author,
reminders.embed_author_url,
@@ -275,7 +277,9 @@ pub async fn edit_reminder(
.fetch_one(pool.inner())
.await
{
Ok(reminder) => Ok(json!({"reminder": reminder, "errors": error})),
Ok(reminder) => {
Ok(json!({"reminder": crate::message::response(reminder), "errors": error}))
}
Err(e) => {
warn!("Error exiting `edit_reminder': {:?}", e);
@@ -48,6 +48,7 @@ pub async fn export(
reminders.attachment_name,
reminders.avatar,
CONCAT('#', channels.channel) AS channel,
CAST(reminders.message_json AS CHAR) AS message_json,
reminders.content,
reminders.embed_author,
reminders.embed_author_url,
@@ -150,6 +151,11 @@ pub async fn import(
match channel_id.parse::<u64>() {
Ok(channel_id) => {
let reminder = CreateReminder {
message_json: record
.message_json
.map(|s| serde_json::from_str(&s).map(sqlx::types::Json))
.transpose()
.map_err(|_| json!({"error": "Invalid message_json"}))?,
attachment: record.attachment,
attachment_name: record.attachment_name,
avatar: record.avatar,
+24 -48
View File
@@ -148,22 +148,29 @@ pub struct EmbedField {
inline: bool,
}
#[derive(Deserialize)]
#[derive(Serialize, Deserialize)]
pub struct CreateReminder {
message_json: Option<Json<serde_json::Value>>,
attachment: Option<Attachment>,
attachment_name: Option<String>,
avatar: Option<String>,
#[serde(with = "string")]
channel: u64,
#[serde(default)]
content: String,
#[serde(default)]
embed_author: String,
embed_author_url: Option<String>,
#[serde(default)]
embed_color: u32,
#[serde(default)]
embed_description: String,
#[serde(default)]
embed_footer: String,
embed_footer_url: Option<String>,
embed_image_url: Option<String>,
embed_thumbnail_url: Option<String>,
#[serde(default)]
embed_title: String,
embed_fields: Option<Json<Vec<EmbedField>>>,
enabled: bool,
@@ -174,6 +181,7 @@ pub struct CreateReminder {
#[serde(default = "name_default")]
name: String,
restartable: bool,
#[serde(default)]
tts: bool,
username: Option<String>,
utc_time: NaiveDateTime,
@@ -181,6 +189,7 @@ pub struct CreateReminder {
#[derive(Serialize, FromRow)]
pub struct GetReminder {
message_json: Option<Json<serde_json::Value>>,
attachment_name: Option<String>,
avatar: Option<String>,
#[serde(with = "string")]
@@ -213,6 +222,8 @@ pub struct GetReminder {
#[derive(Serialize, Deserialize, FromRow)]
pub struct ReminderCsv {
#[serde(default)]
message_json: Option<String>,
attachment: Option<Attachment>,
attachment_name: Option<String>,
avatar: Option<String>,
@@ -422,6 +433,10 @@ pub(crate) async fn create_reminder(
let channel = channel.unwrap();
if reminder.message_json.as_ref().is_some_and(|message| !message.is_object()) {
return Err(json!({"error": "message_json must be an object"}));
}
// validate lengths
check_length!(MAX_NAME_LENGTH, reminder.name);
check_length!(MAX_CONTENT_LENGTH, reminder.content);
@@ -483,60 +498,22 @@ pub(crate) async fn create_reminder(
}
let name = if reminder.name.is_empty() { name_default() } else { reminder.name.clone() };
let username = if reminder.username.as_ref().map(|s| s.is_empty()).unwrap_or(true) {
None
} else {
reminder.username
};
let message_json = Json(crate::message::payload(&reminder));
let new_uid = generate_uid();
// write to db
match sqlx::query!(
"INSERT INTO reminders (
uid,
attachment,
attachment_name,
channel_id,
avatar,
content,
embed_author,
embed_author_url,
embed_color,
embed_description,
embed_footer,
embed_footer_url,
embed_image_url,
embed_thumbnail_url,
embed_title,
embed_fields,
enabled,
expires,
interval_seconds,
interval_days,
interval_months,
name,
restartable,
tts,
username,
`utc_time`
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
uid, attachment, attachment_name, channel_id, message_json,
enabled, expires, interval_seconds, interval_days, interval_months,
name, restartable, `utc_time`
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
new_uid,
reminder.attachment,
reminder.attachment_name,
channel,
reminder.avatar,
reminder.content,
reminder.embed_author,
reminder.embed_author_url,
reminder.embed_color,
reminder.embed_description,
reminder.embed_footer,
reminder.embed_footer_url,
reminder.embed_image_url,
reminder.embed_thumbnail_url,
reminder.embed_title,
reminder.embed_fields,
message_json,
reminder.enabled,
reminder.expires,
reminder.interval_seconds,
@@ -544,8 +521,6 @@ pub(crate) async fn create_reminder(
reminder.interval_months,
name,
reminder.restartable,
reminder.tts,
username,
reminder.utc_time,
)
.execute(transaction.executor())
@@ -558,6 +533,7 @@ pub(crate) async fn create_reminder(
reminders.attachment_name,
reminders.avatar,
channels.channel,
reminders.message_json,
reminders.content,
reminders.embed_author,
reminders.embed_author_url,
@@ -587,7 +563,7 @@ pub(crate) async fn create_reminder(
)
.fetch_one(transaction.executor())
.await
.map(|r| Ok(json!(r)))
.map(|r| Ok(crate::message::response(r)))
.unwrap_or_else(|e| {
warn!("Failed to complete SQL query: {:?}", e);