From e42aadb6d01c38999225f7e83ae47f97bbc75f4a Mon Sep 17 00:00:00 2001 From: Luna <508270-luna@users.noreply.gitlab.com> Date: Tue, 4 Feb 2020 20:50:40 +0000 Subject: [PATCH] migration.command: dont split on migration 0 (it's a hack) --- Pipfile | 2 +- Pipfile.lock | 215 +++++++++--------- litecord/blueprints/channel/reactions.py | 93 ++++---- litecord/blueprints/guild/members.py | 4 +- litecord/common/guilds.py | 17 ++ litecord/common/users.py | 1 + litecord/storage.py | 10 +- manage/cmd/migration/command.py | 32 ++- manage/cmd/migration/scripts/0_base.sql | 13 ++ .../migration/scripts/4_fix_constraints.sql | 136 +++++++++++ 10 files changed, 369 insertions(+), 154 deletions(-) create mode 100644 manage/cmd/migration/scripts/4_fix_constraints.sql diff --git a/Pipfile b/Pipfile index c95e7ee..95f5117 100644 --- a/Pipfile +++ b/Pipfile @@ -6,7 +6,7 @@ name = "pypi" [packages] bcrypt = "==3.1.7" itsdangerous = "==1.1.0" -asyncpg = "==0.18.3" +asyncpg = "==0.20.1" websockets = "==8.0.2" Earl-ETF = "==2.1.2" logbook = "==1.5.2" diff --git a/Pipfile.lock b/Pipfile.lock index 14da2d0..256740a 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "a9198ca2f39a0eb436204c2175d85eb72a402e4d184d3ad0ada9713b78f5008b" + "sha256": "bdd693f88f93f57b4a6eca42e0c8f053e500ddc40e344d888af86143c1904751" }, "pipfile-spec": 6, "requires": { @@ -52,25 +52,30 @@ }, "asyncpg": { "hashes": [ - "sha256:0677714b26b48d63db728867b812ef365ec3879d2be6fa1c9cf4328503f9a464", - "sha256:2dee4fb251139f1c1ee4bd9959d516f930f4da37a2f33b07c2b902b837a76666", - "sha256:378a7ef11ce7b35f11eb816e5252bc1e779119f7583a872233b45a76effac02e", - "sha256:4539bc2e63600a1ee999086bbb59bf717ab32ea771ac20b5b792a2234633b5fb", - "sha256:4a779a85302241782bed8ed0f2bcb38544805b3e107b16ee7489c5818d8f4228", - "sha256:51a3d67a3fa43112b17ec510338723932e1e0611ad99a146acc9960d32210196", - "sha256:58a5eccaac60fd326e32683226efe1046bfea558fa043360bdd1708e0e812c67", - "sha256:814343dc2baa489a11521ff9fad68f337a05c9ae0461fdf9f1ec7ac3541c13a9", - "sha256:84084f7dfed0b2d397a0c2fd7eaf29b01904c74f4320e5fe95ad3042042cf188", - "sha256:89e727fdba05d90a0156d9d18932fd44a2baa84e90e3368573f432a308ad8fd7", - "sha256:ab8b9d367e3ef48f35a059642940714a2bda7a7fce8b017b21bfbc4f8fbf8f5f", - "sha256:c1fe1f0ef848f0f17bf63b90a4c3f446a14e4c899d8531ea988109cc0de014e5", - "sha256:cc7aa61bf41273ee5d4c11e0e72c0d9340e9c4dbf752464ae2b6816abadaabce", - "sha256:d5450bdf8631fa1200c08a2e70cab06c2e8c09ef608629908531513444d12858", - "sha256:fd2d13da29f55c2c71b1acc9d9f107c7a5176fffb3f62ff503f2b300f7ecd74e", - "sha256:fd35a8082b97d5b97d26bcd1b010fdd65a56311d7a02bf2a7e2c56810b9961a7" + "sha256:058baec9d6b75612412baa872a1aa47317d0ff88c318a49f9c4a2389043d5a8d", + "sha256:0c336903c3b08e970f8af2f606332f1738dba156bca83ed0467dc2f5c70da796", + "sha256:1388caa456070dab102be874205e3ae8fd1de2577d5de9fa22e65ba5c0f8b110", + "sha256:25edb0b947eb632b6b53e5a4b36cba5677297bb34cbaba270019714d0a5fed76", + "sha256:2af6a5a705accd36e13292ea43d08c20b15e52d684beb522cb3a7d3c9c8f3f48", + "sha256:391aea89871df8c1560750af6c7170f2772c2d133b34772acf3637e3cf4db93e", + "sha256:394bf19bdddbba07a38cd6fb526ebf66e120444d6b3097332b78efd5b26495b0", + "sha256:5664d1bd8abe64fc60a0e701eb85fa1d8c9a4a8018a5a59164d27238f2caf395", + "sha256:57666dfae38f4dbf84ffbf0c5c0f78733fef0e8e083230275dcb9ccad1d5ee09", + "sha256:74510234c294c6a6767089ba9c938f09a491426c24405634eb357bd91dffd734", + "sha256:95cd2df61ee00b789bdcd04a080e6d9188693b841db2bf9a87ebaed9e53147e0", + "sha256:a981500bf6947926e53c48f4d60ae080af1b4ad7fa78e363465a5b5ad4f2b65e", + "sha256:a9e6fd6f0f9e8bd77e9a4e1ef9a4f83a80674d9136a754ae3603e915da96b627", + "sha256:ad5ba062e09673b1a4b8d0facaf5a6d9719bf7b337440d10b07fe994d90a9552", + "sha256:ba90d3578bc6dddcbce461875672fd9bdb34f0b8215b68612dd3b65a956ff51c", + "sha256:c773c7dbe2f4d3ebc9e3030e94303e45d6742e6c2fc25da0c46a56ea3d83caeb", + "sha256:da238592235717419a6a7b5edc8564da410ebfd056ca4ecc41e70b1b5df86fba", + "sha256:e39aac2b3a2f839ce65aa255ce416de899c58b7d38d601d24ca35558e13b48e3", + "sha256:ec6e7046c98730cb2ba4df41387e10cb8963a3ac2918f69ae416f8aab9ca7b1b", + "sha256:f0c9719ac00615f097fe91082b785bce36dbf02a5ec4115ede0ebfd2cd9500cb", + "sha256:f7184689177eeb5a11fa1b2baf3f6f2e26bfd7a85acf4de1a3adbd0867d7c0e2" ], "index": "pypi", - "version": "==0.18.3" + "version": "==0.20.1" }, "attrs": { "hashes": [ @@ -233,10 +238,10 @@ }, "jinja2": { "hashes": [ - "sha256:74320bb91f31270f9551d46522e33af46a80c3d619f4a4bf42b3164d30b5911f", - "sha256:9fe95f19286cfefaa917656583d020be14e7859c6b0252588391e47db34527de" + "sha256:93187ffbc7808079673ef52771baa950426fd664d3aad1d0fa3e95644360e250", + "sha256:b0eaf100007721b5c16c1fc1eecb87409464edc10469ddc9a22a27a99123be49" ], - "version": "==2.10.3" + "version": "==2.11.1" }, "logbook": { "hashes": [ @@ -259,13 +264,16 @@ "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161", "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235", "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5", + "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42", "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff", "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b", "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1", "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e", "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183", "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66", + "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b", "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1", + "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15", "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1", "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e", "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b", @@ -282,31 +290,33 @@ "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6", "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f", "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f", - "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7" + "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2", + "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7", + "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be" ], "version": "==1.1.1" }, "multidict": { "hashes": [ - "sha256:0f04bf4c15d8417401a10a650c349ccc0285943681bfd87d3690587d7714a9b4", - "sha256:15a61c0df2d32487e06f6084eabb48fd9e8b848315e397781a70caf9670c9d78", - "sha256:3c5e2dcbe6b04cbb4303e47a896757a77b676c5e5db5528be7ff92f97ba7ab95", - "sha256:5d2b32b890d9e933d3ced417924261802a857abdee9507b68c75014482145c03", - "sha256:5e5fb8bfebf87f2e210306bf9dd8de2f1af6782b8b78e814060ae9254ab1f297", - "sha256:63ba2be08d82ea2aa8b0f7942a74af4908664d26cb4ff60c58eadb1e33e7da00", - "sha256:73740fcdb38f0adcec85e97db7557615b50ec4e5a3e73e35878720bcee963382", - "sha256:78bed18e7f1eb21f3d10ff3acde900b4d630098648fe1d65bb4abfb3e22c4900", - "sha256:a02fade7b5476c4f88efe9593ff2f3286698d8c6d715ba4f426954f73f382026", - "sha256:aacbde3a8875352a640efa2d1b96e5244a29b0f8df79cbf1ec6470e86fd84697", - "sha256:be813fb9e5ce41a5a99a29cdb857144a1bd6670883586f995b940a4878dc5238", - "sha256:bfcad6da0b8839f01a819602aaa5c5a5b4c85ecbfae9b261a31df3d9262fb31e", - "sha256:c2bfc0db3166e68515bc4a2b9164f4f75ae9c793e9635f8651f2c9ffc65c8dad", - "sha256:c66d11870ae066499a3541963e6ce18512ca827c2aaeaa2f4e37501cee39ac5d", - "sha256:cc7f2202b753f880c2e4123f9aacfdb94560ba893e692d24af271dac41f8b8d9", - "sha256:d1f45e5bb126662ba66ee579831ce8837b1fd978115c9657e32eb3c75b92973d", - "sha256:ed5f3378c102257df9e2dc9ce6468dabf68bee9ec34969cfdc472631aba00316" + "sha256:13f3ebdb5693944f52faa7b2065b751cb7e578b8dd0a5bb8e4ab05ad0188b85e", + "sha256:26502cefa86d79b86752e96639352c7247846515c864d7c2eb85d036752b643c", + "sha256:4fba5204d32d5c52439f88437d33ad14b5f228e25072a192453f658bddfe45a7", + "sha256:527124ef435f39a37b279653ad0238ff606b58328ca7989a6df372fd75d7fe26", + "sha256:5414f388ffd78c57e77bd253cf829373721f450613de53dc85a08e34d806e8eb", + "sha256:5eee66f882ab35674944dfa0d28b57fa51e160b4dce0ce19e47f495fdae70703", + "sha256:63810343ea07f5cd86ba66ab66706243a6f5af075eea50c01e39b4ad6bc3c57a", + "sha256:6bd10adf9f0d6a98ccc792ab6f83d18674775986ba9bacd376b643fe35633357", + "sha256:83c6ddf0add57c6b8a7de0bc7e2d656be3eefeff7c922af9a9aae7e49f225625", + "sha256:93166e0f5379cf6cd29746989f8a594fa7204dcae2e9335ddba39c870a287e1c", + "sha256:9a7b115ee0b9b92d10ebc246811d8f55d0c57e82dbb6a26b23c9a9a6ad40ce0c", + "sha256:a38baa3046cce174a07a59952c9f876ae8875ef3559709639c17fdf21f7b30dd", + "sha256:a6d219f49821f4b2c85c6d426346a5d84dab6daa6f85ca3da6c00ed05b54022d", + "sha256:a8ed33e8f9b67e3b592c56567135bb42e7e0e97417a4b6a771e60898dfd5182b", + "sha256:d7d428488c67b09b26928950a395e41cc72bb9c3d5abfe9f0521940ee4f796d4", + "sha256:dcfed56aa085b89d644af17442cdc2debaa73388feba4b8026446d168ca8dad7", + "sha256:f29b885e4903bd57a7789f09fe9d60b6475a6c1a4c0eca874d8558f00f9d4b51" ], - "version": "==4.7.3" + "version": "==4.7.4" }, "pillow": { "hashes": [ @@ -359,10 +369,10 @@ }, "six": { "hashes": [ - "sha256:1f1b7d42e254082a9db6279deae68afb421ceba6158efa6131de7b3003ee93fd", - "sha256:30f610279e8b2578cab6db20741130331735c781b56053c59c4076da27f06b66" + "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a", + "sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c" ], - "version": "==1.13.0" + "version": "==1.14.0" }, "sortedcontainers": { "hashes": [ @@ -406,7 +416,7 @@ "winter": { "editable": true, "git": "https://gitlab.com/elixire/winter.git", - "ref": "c265df768899da0be2e25333444b73f58dae6523" + "ref": "988c6ca438663c30c6b617bdb16fd6be6c4226ba" }, "wsproto": { "hashes": [ @@ -546,11 +556,11 @@ }, "importlib-metadata": { "hashes": [ - "sha256:073a852570f92da5f744a3472af1b61e28e9f78ccf0c9117658dc32b15de7b45", - "sha256:d95141fbfa7ef2ec65cfd945e2af7e5a6ddbd7c8d9a25e66ff3be8e3daf9f60f" + "sha256:06f5b3a99029c7134207dd882428a66992a9de2bef7c2b699b5641f9886c3302", + "sha256:b97607a1a18a5100839aec1dc26a1ea17ee0d93b20b0f008d80a5a050afb200b" ], "markers": "python_version < '3.8'", - "version": "==1.3.0" + "version": "==1.5.0" }, "mccabe": { "hashes": [ @@ -561,10 +571,10 @@ }, "more-itertools": { "hashes": [ - "sha256:b84b238cce0d9adad5ed87e745778d20a3f8487d0f0cb8b8a586816c7496458d", - "sha256:c833ef592a0324bcc6a60e48440da07645063c453880c9477ceb22490aec1564" + "sha256:5dd8bcf33e5f9513ffa06d5ad33d78f31e1931ac9a18f33d37e77a180d393a7c", + "sha256:b1ddb932186d8a6ac451e1d95844b382f55e12686d51ca0c68b6f61f2ab7a507" ], - "version": "==8.0.2" + "version": "==8.2.0" }, "mypy": { "hashes": [ @@ -595,10 +605,10 @@ }, "packaging": { "hashes": [ - "sha256:aec3fdbb8bc9e4bb65f0634b9f551ced63983a529d6a8931817d52fdd0816ddb", - "sha256:fe1d8331dfa7cc0a883b49d75fc76380b2ab2734b220fbb87d774e4fd4b851f8" + "sha256:170748228214b70b672c581a3dd610ee51f733018650740e98c7df862a583f73", + "sha256:e665345f9eef0c621aa0bf2f8d78cf6d21904eef16a93f020240b704a57f1334" ], - "version": "==20.0" + "version": "==20.1" }, "pathspec": { "hashes": [ @@ -661,36 +671,36 @@ }, "regex": { "hashes": [ - "sha256:032fdcc03406e1a6485ec09b826eac78732943840c4b29e503b789716f051d8d", - "sha256:0e6cf1e747f383f52a0964452658c04300a9a01e8a89c55ea22813931b580aa8", - "sha256:106e25a841921d8259dcef2a42786caae35bc750fb996f830065b3dfaa67b77e", - "sha256:1768cf42a78a11dae63152685e7a1d90af7a8d71d2d4f6d2387edea53a9e0588", - "sha256:27d1bd20d334f50b7ef078eba0f0756a640fd25f5f1708d3b5bed18a5d6bced9", - "sha256:29b20f66f2e044aafba86ecf10a84e611b4667643c42baa004247f5dfef4f90b", - "sha256:4850c78b53acf664a6578bba0e9ebeaf2807bb476c14ec7e0f936f2015133cae", - "sha256:57eacd38a5ec40ed7b19a968a9d01c0d977bda55664210be713e750dd7b33540", - "sha256:724eb24b92fc5fdc1501a1b4df44a68b9c1dda171c8ef8736799e903fb100f63", - "sha256:77ae8d926f38700432807ba293d768ba9e7652df0cbe76df2843b12f80f68885", - "sha256:78b3712ec529b2a71731fbb10b907b54d9c53a17ca589b42a578bc1e9a2c82ea", - "sha256:7bbbdbada3078dc360d4692a9b28479f569db7fc7f304b668787afc9feb38ec8", - "sha256:8d9ef7f6c403e35e73b7fc3cde9f6decdc43b1cb2ff8d058c53b9084bfcb553e", - "sha256:a83049eb717ae828ced9cf607845929efcb086a001fc8af93ff15c50012a5716", - "sha256:adc35d38952e688535980ae2109cad3a109520033642e759f987cf47fe278aa1", - "sha256:c29a77ad4463f71a506515d9ec3a899ed026b4b015bf43245c919ff36275444b", - "sha256:cfd31b3300fefa5eecb2fe596c6dee1b91b3a05ece9d5cfd2631afebf6c6fadd", - "sha256:d3ee0b035816e0520fac928de31b6572106f0d75597f6fa3206969a02baba06f", - "sha256:d508875793efdf6bab3d47850df8f40d4040ae9928d9d80864c1768d6aeaf8e3", - "sha256:ef0b828a7e22e58e06a1cceddba7b4665c6af8afeb22a0d8083001330572c147", - "sha256:faad39fdbe2c2ccda9846cd21581063086330efafa47d87afea4073a08128656" + "sha256:07b39bf943d3d2fe63d46281d8504f8df0ff3fe4c57e13d1656737950e53e525", + "sha256:0932941cdfb3afcbc26cc3bcf7c3f3d73d5a9b9c56955d432dbf8bbc147d4c5b", + "sha256:0e182d2f097ea8549a249040922fa2b92ae28be4be4895933e369a525ba36576", + "sha256:10671601ee06cf4dc1bc0b4805309040bb34c9af423c12c379c83d7895622bb5", + "sha256:23e2c2c0ff50f44877f64780b815b8fd2e003cda9ce817a7fd00dea5600c84a0", + "sha256:26ff99c980f53b3191d8931b199b29d6787c059f2e029b2b0c694343b1708c35", + "sha256:27429b8d74ba683484a06b260b7bb00f312e7c757792628ea251afdbf1434003", + "sha256:3e77409b678b21a056415da3a56abfd7c3ad03da71f3051bbcdb68cf44d3c34d", + "sha256:4e8f02d3d72ca94efc8396f8036c0d3bcc812aefc28ec70f35bb888c74a25161", + "sha256:4eae742636aec40cf7ab98171ab9400393360b97e8f9da67b1867a9ee0889b26", + "sha256:6a6ae17bf8f2d82d1e8858a47757ce389b880083c4ff2498dba17c56e6c103b9", + "sha256:6a6ba91b94427cd49cd27764679024b14a96874e0dc638ae6bdd4b1a3ce97be1", + "sha256:7bcd322935377abcc79bfe5b63c44abd0b29387f267791d566bbb566edfdd146", + "sha256:98b8ed7bb2155e2cbb8b76f627b2fd12cf4b22ab6e14873e8641f266e0fb6d8f", + "sha256:bd25bb7980917e4e70ccccd7e3b5740614f1c408a642c245019cff9d7d1b6149", + "sha256:d0f424328f9822b0323b3b6f2e4b9c90960b24743d220763c7f07071e0778351", + "sha256:d58e4606da2a41659c84baeb3cfa2e4c87a74cec89a1e7c56bee4b956f9d7461", + "sha256:e3cd21cc2840ca67de0bbe4071f79f031c81418deb544ceda93ad75ca1ee9f7b", + "sha256:e6c02171d62ed6972ca8631f6f34fa3281d51db8b326ee397b9c83093a6b7242", + "sha256:e7c7661f7276507bce416eaae22040fd91ca471b5b33c13f8ff21137ed6f248c", + "sha256:ecc6de77df3ef68fee966bb8cb4e067e84d4d1f397d0ef6fce46913663540d77" ], - "version": "==2019.12.20" + "version": "==2020.1.8" }, "six": { "hashes": [ - "sha256:1f1b7d42e254082a9db6279deae68afb421ceba6158efa6131de7b3003ee93fd", - "sha256:30f610279e8b2578cab6db20741130331735c781b56053c59c4076da27f06b66" + "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a", + "sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c" ], - "version": "==1.13.0" + "version": "==1.14.0" }, "toml": { "hashes": [ @@ -701,28 +711,29 @@ }, "typed-ast": { "hashes": [ - "sha256:1170afa46a3799e18b4c977777ce137bb53c7485379d9706af8a59f2ea1aa161", - "sha256:18511a0b3e7922276346bcb47e2ef9f38fb90fd31cb9223eed42c85d1312344e", - "sha256:262c247a82d005e43b5b7f69aff746370538e176131c32dda9cb0f324d27141e", - "sha256:2b907eb046d049bcd9892e3076c7a6456c93a25bebfe554e931620c90e6a25b0", - "sha256:354c16e5babd09f5cb0ee000d54cfa38401d8b8891eefa878ac772f827181a3c", - "sha256:48e5b1e71f25cfdef98b013263a88d7145879fbb2d5185f2a0c79fa7ebbeae47", - "sha256:4e0b70c6fc4d010f8107726af5fd37921b666f5b31d9331f0bd24ad9a088e631", - "sha256:630968c5cdee51a11c05a30453f8cd65e0cc1d2ad0d9192819df9978984529f4", - "sha256:66480f95b8167c9c5c5c87f32cf437d585937970f3fc24386f313a4c97b44e34", - "sha256:71211d26ffd12d63a83e079ff258ac9d56a1376a25bc80b1cdcdf601b855b90b", - "sha256:7954560051331d003b4e2b3eb822d9dd2e376fa4f6d98fee32f452f52dd6ebb2", - "sha256:838997f4310012cf2e1ad3803bce2f3402e9ffb71ded61b5ee22617b3a7f6b6e", - "sha256:95bd11af7eafc16e829af2d3df510cecfd4387f6453355188342c3e79a2ec87a", - "sha256:bc6c7d3fa1325a0c6613512a093bc2a2a15aeec350451cbdf9e1d4bffe3e3233", - "sha256:cc34a6f5b426748a507dd5d1de4c1978f2eb5626d51326e43280941206c209e1", - "sha256:d755f03c1e4a51e9b24d899561fec4ccaf51f210d52abdf8c07ee2849b212a36", - "sha256:d7c45933b1bdfaf9f36c579671fec15d25b06c8398f113dab64c18ed1adda01d", - "sha256:d896919306dd0aa22d0132f62a1b78d11aaf4c9fc5b3410d3c666b818191630a", - "sha256:fdc1c9bbf79510b76408840e009ed65958feba92a88833cdceecff93ae8fff66", - "sha256:ffde2fbfad571af120fcbfbbc61c72469e72f550d676c3342492a9dfdefb8f12" + "sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355", + "sha256:0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919", + "sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa", + "sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652", + "sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75", + "sha256:4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01", + "sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d", + "sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1", + "sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907", + "sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c", + "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3", + "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b", + "sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614", + "sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb", + "sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b", + "sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41", + "sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6", + "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34", + "sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe", + "sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4", + "sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7" ], - "version": "==1.4.0" + "version": "==1.4.1" }, "typing-extensions": { "hashes": [ @@ -741,10 +752,10 @@ }, "zipp": { "hashes": [ - "sha256:3718b1cbcd963c7d4c5511a8240812904164b7f381b647143a89d3b98f9bcd8e", - "sha256:f06903e9f1f43b12d371004b4ac7b06ab39a44adc747266928ae6debfa7b3335" + "sha256:ccc94ed0909b58ffe34430ea5451f07bc0c76467d7081619a454bf5c98b89e28", + "sha256:feae2f18633c32fc71f2de629bfb3bd3c9325cd4419642b1f1da42ee488d9b98" ], - "version": "==0.6.0" + "version": "==2.1.0" } } } diff --git a/litecord/blueprints/channel/reactions.py b/litecord/blueprints/channel/reactions.py index ac1440f..9c1627f 100644 --- a/litecord/blueprints/channel/reactions.py +++ b/litecord/blueprints/channel/reactions.py @@ -18,11 +18,12 @@ along with this program. If not, see . """ from enum import IntEnum +from typing import List, Union, Tuple from quart import Blueprint, request, current_app as app, jsonify from logbook import Logger - +from litecord.errors import BadRequest from litecord.utils import async_map, query_tuple_from_args, extract_limit from litecord.blueprints.auth import token_check from litecord.blueprints.checks import channel_check, channel_perm_check @@ -48,8 +49,7 @@ def emoji_info_from_str(emoji: str) -> tuple: # unicode emoji just have the raw unicode. # try checking if the emoji is custom or unicode - emoji_type = 0 if ":" in emoji else 1 - emoji_type = EmojiType(emoji_type) + emoji_type = EmojiType(0 if ":" in emoji else 1) # extract the emoji id OR the unicode value of the emoji # depending if it is custom or not @@ -85,22 +85,25 @@ async def add_reaction(channel_id: int, message_id: int, emoji: str): ctype, guild_id = await channel_check(user_id, channel_id) await channel_perm_check(user_id, channel_id, "read_history") - emoji_type, emoji_id, emoji_name = emoji_info_from_str(emoji) + emoji_type, upstream_emoji_id, emoji_name = emoji_info_from_str(emoji) - emoji_id = emoji_id if emoji_type == EmojiType.CUSTOM else None - emoji_text = emoji_id if emoji_type == EmojiType.UNICODE else None + emoji_id = upstream_emoji_id if emoji_type == EmojiType.CUSTOM else None + emoji_text = upstream_emoji_id if emoji_type == EmojiType.UNICODE else None + + # either one must exist + assert emoji_id or emoji_text # ADD_REACTIONS is only checked when this is the first # reaction in a message. reaction_count = await app.db.fetchval( """ - SELECT COUNT(*) - FROM message_reactions - WHERE message_id = $1 - AND emoji_type = $2 - AND emoji_id = $3 - AND emoji_text = $4 - """, + SELECT COUNT(*) + FROM message_reactions + WHERE message_id = $1 + AND emoji_type = $2 + AND emoji_id = $3 + AND emoji_text = $4 + """, message_id, emoji_type, emoji_id, @@ -112,9 +115,10 @@ async def add_reaction(channel_id: int, message_id: int, emoji: str): await app.db.execute( """ - INSERT INTO message_reactions (message_id, user_id, - emoji_type, emoji_id, emoji_text) - VALUES ($1, $2, $3, $4, $5) + INSERT INTO message_reactions + (message_id, user_id, emoji_type, emoji_id, emoji_text) + VALUES + ($1, $2, $3, $4, $5) """, message_id, user_id, @@ -139,20 +143,26 @@ async def add_reaction(channel_id: int, message_id: int, emoji: str): return "", 204 -def emoji_sql(emoji_type, emoji_id, emoji_name, param=4): - """Extract SQL clauses to search for specific emoji - in the message_reactions table.""" - param = f"${param}" +def emoji_sql( + emoji_type, emoji_id, emoji_name, param_index: int = 4 +) -> Tuple[str, Union[int, str]]: + """Extract SQL clauses to search for specific emoji in the message_reactions table.""" + param = f"${param_index}" - # know which column to filter with - where_ext = ( - f"AND emoji_id = {param}" - if emoji_type == EmojiType.CUSTOM - else f"AND emoji_text = {param}" - ) + assert emoji_type in (EmojiType.CUSTOM, EmojiType.UNICODE) - # which emoji to remove (custom or unicode) - main_emoji = emoji_id if emoji_type == EmojiType.CUSTOM else emoji_name + if emoji_type == EmojiType.CUSTOM: + where_ext = f"AND emoji_id = {param}" + main_emoji = emoji_id + elif emoji_type == EmojiType.UNICODE: + + # fun fact, emojis are length 1 in python? i'll use this to the + # best of my ability, lol + if len(emoji_name) != 1: + raise BadRequest("Invalid emoji name") + + where_ext = f"AND emoji_text = {param}" + main_emoji = emoji_name return where_ext, main_emoji @@ -227,21 +237,26 @@ async def list_users_reaction(channel_id, message_id, emoji): limit = extract_limit(request, 25) before, after = query_tuple_from_args(request.args, limit) - before_clause = "AND user_id < $2" if before else "" - after_clause = "AND user_id > $3" if after else "" + args: List[Union[int, str]] = [message_id] - where_ext, main_emoji = _emoji_sql_simple(emoji, 4) + before_clause = "AND user_id < $2" if before else "" + if before_clause: + args.append(before) + + after_clause = f"AND user_id > ${len(args) + 1}" if after else "" + if after_clause: + args.append(after) + + where_ext, main_emoji = _emoji_sql_simple(emoji, len(args) + 1) + args.append(main_emoji) rows = await app.db.fetch( f""" - SELECT user_id - FROM message_reactions - WHERE message_id = $1 {before_clause} {after_clause} {where_ext} - """, - message_id, - before, - after, - main_emoji, + SELECT user_id + FROM message_reactions + WHERE message_id = $1 {before_clause} {after_clause} {where_ext} + """, + *args, ) user_ids = [r["user_id"] for r in rows] diff --git a/litecord/blueprints/guild/members.py b/litecord/blueprints/guild/members.py index 3090131..e051f51 100644 --- a/litecord/blueprints/guild/members.py +++ b/litecord/blueprints/guild/members.py @@ -98,7 +98,7 @@ async def _update_member_roles(guild_id: int, member_id: int, wanted_roles: set) async with app.db.acquire() as conn: async with conn.transaction(): # add roles - await app.db.executemany( + await conn.executemany( """ INSERT INTO member_roles (user_id, guild_id, role_id) VALUES ($1, $2, $3) @@ -107,7 +107,7 @@ async def _update_member_roles(guild_id: int, member_id: int, wanted_roles: set) ) # remove roles - await app.db.executemany( + await conn.executemany( """ DELETE FROM member_roles WHERE diff --git a/litecord/common/guilds.py b/litecord/common/guilds.py index 1b63322..2d11e61 100644 --- a/litecord/common/guilds.py +++ b/litecord/common/guilds.py @@ -17,6 +17,7 @@ along with this program. If not, see . """ +from logbook import Logger from quart import current_app as app from ..snowflake import get_snowflake @@ -24,6 +25,8 @@ from ..permissions import get_role_perms from ..utils import dict_get, maybe_lazy_guild_dispatch from ..enums import ChannelType +log = Logger(__name__) + async def remove_member(guild_id: int, member_id: int): """Do common tasks related to deleting a member from the guild, @@ -178,8 +181,22 @@ async def create_guild_channel( await _specific_chan_create(channel_id, ctype, **kwargs) +async def _del_from_table(table: str, user_id: int): + """Delete a row from a table.""" + res = await app.db.execute( + f""" + DELETE FROM {table} + WHERE guild_id = $1 + """, + user_id, + ) + + log.info("Deleting guild id {} from {}, res: {!r}", user_id, table, res) + + async def delete_guild(guild_id: int): """Delete a single guild.""" + await _del_from_table("vanity_invites", guild_id) await app.db.execute( """ DELETE FROM guilds diff --git a/litecord/common/users.py b/litecord/common/users.py index a3ea268..9d8794c 100644 --- a/litecord/common/users.py +++ b/litecord/common/users.py @@ -218,6 +218,7 @@ async def delete_user(user_id, *, mass_update: bool = True): ) # remove the user from various tables + await _del_from_table(db, "notes", user_id) await _del_from_table(db, "user_settings", user_id) await _del_from_table(db, "user_payment_sources", user_id) await _del_from_table(db, "user_subscriptions", user_id) diff --git a/litecord/storage.py b/litecord/storage.py index dae0961..4532376 100644 --- a/litecord/storage.py +++ b/litecord/storage.py @@ -813,11 +813,11 @@ class Storage: """Get all reactions in a message.""" reactions = await self.db.fetch( """ - SELECT user_id, emoji_type, emoji_id, emoji_text - FROM message_reactions - WHERE message_id = $1 - ORDER BY react_ts - """, + SELECT user_id, emoji_type, emoji_id, emoji_text + FROM message_reactions + WHERE message_id = $1 + ORDER BY react_ts + """, message_id, ) diff --git a/manage/cmd/migration/command.py b/manage/cmd/migration/command.py index 605ee61..9151d51 100644 --- a/manage/cmd/migration/command.py +++ b/manage/cmd/migration/command.py @@ -20,6 +20,7 @@ along with this program. If not, see . import inspect import os import datetime +import sys from pathlib import Path from dataclasses import dataclass @@ -147,6 +148,25 @@ async def _delete_log(app, migration_id: int): ) +async def run_migration(app, conn, migration): + migration_sql = migration.path.read_text(encoding="utf-8") + statements = migration_sql.split(";") + + # NOTE: is bodge, split by ; breaks function definitions. sorry. + if migration.id == 0: + statements = [migration_sql] + + for index, stmt in enumerate(statements): + if not stmt.strip(): + break + + try: + await app.db.execute(stmt) + except Exception: + log.exception("error at statement {}", index + 1) + raise Exception() + + async def apply_migration(app, migration: Migration) -> bool: """Apply a single migration. @@ -158,7 +178,6 @@ async def apply_migration(app, migration: Migration) -> bool: Returns a boolean signaling if this failed or not. """ - migration_sql = migration.path.read_text(encoding="utf-8") res = await _insert_log(app, migration.id, f"migration: {migration.name}") @@ -166,14 +185,15 @@ async def apply_migration(app, migration: Migration) -> bool: return False try: - await app.db.execute(migration_sql) - log.info("applied {} {}", migration.id, migration.name) + async with app.db.acquire() as conn: + async with conn.transaction(): + await run_migration(app, conn, migration) + log.info("applied {} {}", migration.id, migration.name) return True except Exception: log.exception("failed to run migration, rollbacking log") await _delete_log(app, migration.id) - return False @@ -245,7 +265,9 @@ async def migrate_cmd(app, _args): migration = ctx.scripts.get(idx) print("applying", migration.id, migration.name) - await apply_migration(app, migration) + if not await apply_migration(app, migration): + print("stopped migration due to error.") + sys.exit(1) def setup(subparser): diff --git a/manage/cmd/migration/scripts/0_base.sql b/manage/cmd/migration/scripts/0_base.sql index cd057bd..857402e 100644 --- a/manage/cmd/migration/scripts/0_base.sql +++ b/manage/cmd/migration/scripts/0_base.sql @@ -217,8 +217,14 @@ CREATE TABLE IF NOT EXISTS user_subscriptions ( -- payment logs CREATE TABLE IF NOT EXISTS user_payments ( id bigint PRIMARY KEY, + + -- NOTE: has ON DELETE SET NULL (migration 4) source_id bigint REFERENCES user_payment_sources (id), + + -- NOTE: has ON DELETE SET NULL (migration 4) subscription_id bigint REFERENCES user_subscriptions (id), + + -- NOTE: has ON DELETE SET NULL (migration 4) user_id bigint REFERENCES users (id), currency text DEFAULT 'usd', @@ -278,6 +284,8 @@ CREATE TABLE IF NOT EXISTS channels ( CREATE TABLE IF NOT EXISTS user_read_state ( user_id bigint REFERENCES users (id), + + -- NOTE: has ON DELETE CASCADE (migration 4) channel_id bigint REFERENCES channels (id), -- we don't really need to link @@ -318,6 +326,8 @@ CREATE TABLE IF NOT EXISTS voice_regions ( CREATE TABLE IF NOT EXISTS voice_servers ( -- hostname is a reachable url, e.g "brazil2.example.com" hostname text PRIMARY KEY, + + -- NOTE: has ON DELETE CASCADE (migration 4) region_id text REFERENCES voice_regions (id), -- health values are more thoroughly defined in the LVSP documentation @@ -505,6 +515,7 @@ CREATE TABLE IF NOT EXISTS invites ( -- vanity url table, the mapping is 1-1 for guilds and vanity urls CREATE TABLE IF NOT EXISTS vanity_invites ( + -- NOTE: has ON DELETE CASCADE (migration 4) guild_id bigint REFERENCES guilds (id) PRIMARY KEY, code text REFERENCES invites (code) ON DELETE CASCADE ); @@ -683,6 +694,8 @@ CREATE TABLE IF NOT EXISTS attachments ( -- keeping channel_id and message_id -- make a way "better" attachment url. + + -- NOTE: has ON DELETE CASCADE (migration 4) channel_id bigint REFERENCES channels (id), message_id bigint REFERENCES messages (id), diff --git a/manage/cmd/migration/scripts/4_fix_constraints.sql b/manage/cmd/migration/scripts/4_fix_constraints.sql new file mode 100644 index 0000000..4edb17f --- /dev/null +++ b/manage/cmd/migration/scripts/4_fix_constraints.sql @@ -0,0 +1,136 @@ +ALTER TABLE attachments + DROP CONSTRAINT IF EXISTS attachments_channel_id_fkey, + DROP CONSTRAINT IF EXISTS attachments_message_id_fkey, + ADD CONSTRAINT attachments_channel_id_fkey + FOREIGN KEY (channel_id) + REFERENCES channels (id) + ON DELETE CASCADE, + ADD CONSTRAINT attachments_message_id_fkey + FOREIGN KEY (message_id) + REFERENCES messages (id) + ON DELETE CASCADE; + +ALTER TABLE user_payments + DROP CONSTRAINT IF EXISTS user_payments_source_id_fkey, + DROP CONSTRAINT IF EXISTS user_payments_subscription_id_fkey, + DROP CONSTRAINT IF EXISTS user_payments_user_id_fkey, + ADD CONSTRAINT user_payments_source_id_fkey + FOREIGN KEY (source_id) + REFERENCES user_payment_sources (id) + ON DELETE SET NULL, + ADD CONSTRAINT user_payments_subscription_id_fkey + FOREIGN KEY (subscription_id) + REFERENCES user_subscriptions (id) + ON DELETE SET NULL, + ADD CONSTRAINT user_payments_user_id_fkey + FOREIGN KEY (user_id) + REFERENCES users (id) + ON DELETE SET NULL; + +ALTER TABLE user_read_state + DROP CONSTRAINT IF EXISTS user_read_state_channel_id_fkey, + ADD CONSTRAINT user_read_state_channel_id_fkey + FOREIGN KEY (channel_id) + REFERENCES channels (id) + ON DELETE CASCADE; + +ALTER TABLE voice_servers + DROP CONSTRAINT IF EXISTS voice_servers_region_id_fkey, + ADD CONSTRAINT voice_servers_region_id_fkey + FOREIGN KEY (region_id) + REFERENCES voice_regions (id) + ON DELETE CASCADE; + +ALTER TABLE guilds + DROP CONSTRAINT IF EXISTS guilds_region_fkey, + DROP CONSTRAINT IF EXISTS guilds_afk_channel_id_fkey, + DROP CONSTRAINT IF EXISTS guilds_embed_channel_id_fkey, + DROP CONSTRAINT IF EXISTS guilds_widget_channel_id_fkey, + DROP CONSTRAINT IF EXISTS guilds_system_channel_id_fkey, + ADD CONSTRAINT guilds_region_fkey + FOREIGN KEY (region) + REFERENCES voice_regions (id) + ON DELETE SET NULL, + ADD CONSTRAINT guilds_afk_channel_id_fkey + FOREIGN KEY (afk_channel_id) + REFERENCES channels (id) + ON DELETE SET DEFAULT, + ADD CONSTRAINT guilds_embed_channel_id_fkey + FOREIGN KEY (embed_channel_id) + REFERENCES channels (id) + ON DELETE SET DEFAULT, + ADD CONSTRAINT guilds_widget_channel_id_fkey + FOREIGN KEY (widget_channel_id) + REFERENCES channels (id) + ON DELETE SET DEFAULT, + ADD CONSTRAINT guilds_system_channel_id_fkey + FOREIGN KEY (system_channel_id) + REFERENCES channels (id) + ON DELETE SET DEFAULT; + +ALTER TABLE guild_channels + DROP CONSTRAINT IF EXISTS guild_channels_id_fkey, + ADD CONSTRAINT guild_channels_id_fkey + FOREIGN KEY (id) + REFERENCES channels (id) + ON DELETE CASCADE; + +ALTER TABLE group_dm_channels + DROP CONSTRAINT IF EXISTS group_dm_channels_icon_fkey, + ADD CONSTRAINT group_dm_channels_icon_fkey + FOREIGN KEY (icon) + REFERENCES icons (hash) + ON DELETE SET DEFAULT; + +ALTER TABLE guild_emoji + DROP CONSTRAINT IF EXISTS guild_emoji_image_fkey, + ADD CONSTRAINT guild_emoji_image_fkey + FOREIGN KEY (image) + REFERENCES icons (hash) + ON DELETE CASCADE; + +ALTER TABLE vanity_invites + DROP CONSTRAINT IF EXISTS vanity_invites_guild_id_fkey, + ADD CONSTRAINT vanity_invites_guild_id_fkey + FOREIGN KEY (guild_id) + REFERENCES guilds (id) + ON DELETE CASCADE; + +ALTER TABLE guild_whitelists + DROP CONSTRAINT IF EXISTS guild_whitelists_role_id_fkey, + ADD CONSTRAINT guild_whitelists_role_id_fkey + FOREIGN KEY (role_id) + REFERENCES roles (id) + ON DELETE CASCADE; + +ALTER TABLE message_webhook_info + DROP CONSTRAINT IF EXISTS message_webhook_info_message_id_fkey, + ADD CONSTRAINT message_webhook_info_message_id_fkey + FOREIGN KEY (message_id) + REFERENCES messages (id) + ON DELETE CASCADE; + +ALTER TABLE message_reactions + DROP CONSTRAINT IF EXISTS message_reactions_message_id_fkey, + DROP CONSTRAINT IF EXISTS message_reactions_emoji_id_fkey, + ADD CONSTRAINT message_reactions_message_id_fkey + FOREIGN KEY (message_id) + REFERENCES messages (id) + ON DELETE CASCADE, + ADD CONSTRAINT message_reactions_emoji_id_fkey + FOREIGN KEY (emoji_id) + REFERENCES guild_emoji (id) + ON DELETE CASCADE; + +ALTER TABLE attachments + DROP CONSTRAINT IF EXISTS attachments_message_id_fkey, + DROP CONSTRAINT IF EXISTS attachments_channel_id_fkey, + ADD CONSTRAINT attachments_message_id_fkey + FOREIGN KEY (message_id) + REFERENCES messages (id) + ON DELETE CASCADE, + ADD CONSTRAINT attachments_channel_id_fkey + FOREIGN KEY (channel_id) + REFERENCES channels (id) + ON DELETE CASCADE; +