├── Pipfile ├── Pipfile.lock ├── README.md ├── alembic.ini ├── api ├── api.py ├── auth.py ├── schemas.py └── server.py ├── data_access └── models.py ├── jwt_generator.py ├── migrations ├── README ├── env.py ├── script.py.mako └── versions │ └── 7a4054a75244_add_user_and_task_models.py ├── oas.yaml ├── private_key.pem └── public_key.pem /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | name = "pypi" 3 | url = "https://pypi.org/simple" 4 | verify_ssl = true 5 | 6 | [dev-packages] 7 | black = "*" 8 | 9 | [packages] 10 | fastapi = "*" 11 | uvicorn = "*" 12 | pyyaml = "*" 13 | pyjwt = "*" 14 | cryptography = "*" 15 | sqlalchemy = "*" 16 | alembic = "*" 17 | 18 | [requires] 19 | python_version = "3.9" 20 | 21 | [pipenv] 22 | allow_prereleases = true 23 | -------------------------------------------------------------------------------- /Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "1796fb9beca6ef64ab590e3bd7006625c4bdf515dfb7086a9f8ef321b1061fbb" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "3.9" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.org/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": { 19 | "alembic": { 20 | "hashes": [ 21 | "sha256:6c0c05e9768a896d804387e20b299880fe01bc56484246b0dffe8075d6d3d847", 22 | "sha256:ad842f2c3ab5c5d4861232730779c05e33db4ba880a08b85eb505e87c01095bc" 23 | ], 24 | "index": "pypi", 25 | "version": "==1.7.6" 26 | }, 27 | "anyio": { 28 | "hashes": [ 29 | "sha256:a0aeffe2fb1fdf374a8e4b471444f0f3ac4fb9f5a5b542b48824475e0042a5a6", 30 | "sha256:b5fa16c5ff93fa1046f2eeb5bbff2dad4d3514d6cda61d02816dba34fa8c3c2e" 31 | ], 32 | "version": "==3.5.0" 33 | }, 34 | "asgiref": { 35 | "hashes": [ 36 | "sha256:2f8abc20f7248433085eda803936d98992f1343ddb022065779f37c5da0181d0", 37 | "sha256:88d59c13d634dcffe0510be048210188edd79aeccb6a6c9028cdad6f31d730a9" 38 | ], 39 | "version": "==3.5.0" 40 | }, 41 | "cffi": { 42 | "hashes": [ 43 | "sha256:00c878c90cb53ccfaae6b8bc18ad05d2036553e6d9d1d9dbcf323bbe83854ca3", 44 | "sha256:0104fb5ae2391d46a4cb082abdd5c69ea4eab79d8d44eaaf79f1b1fd806ee4c2", 45 | "sha256:06c48159c1abed75c2e721b1715c379fa3200c7784271b3c46df01383b593636", 46 | "sha256:0808014eb713677ec1292301ea4c81ad277b6cdf2fdd90fd540af98c0b101d20", 47 | "sha256:10dffb601ccfb65262a27233ac273d552ddc4d8ae1bf93b21c94b8511bffe728", 48 | "sha256:14cd121ea63ecdae71efa69c15c5543a4b5fbcd0bbe2aad864baca0063cecf27", 49 | "sha256:17771976e82e9f94976180f76468546834d22a7cc404b17c22df2a2c81db0c66", 50 | "sha256:181dee03b1170ff1969489acf1c26533710231c58f95534e3edac87fff06c443", 51 | "sha256:23cfe892bd5dd8941608f93348c0737e369e51c100d03718f108bf1add7bd6d0", 52 | "sha256:263cc3d821c4ab2213cbe8cd8b355a7f72a8324577dc865ef98487c1aeee2bc7", 53 | "sha256:2756c88cbb94231c7a147402476be2c4df2f6078099a6f4a480d239a8817ae39", 54 | "sha256:27c219baf94952ae9d50ec19651a687b826792055353d07648a5695413e0c605", 55 | "sha256:2a23af14f408d53d5e6cd4e3d9a24ff9e05906ad574822a10563efcef137979a", 56 | "sha256:31fb708d9d7c3f49a60f04cf5b119aeefe5644daba1cd2a0fe389b674fd1de37", 57 | "sha256:3415c89f9204ee60cd09b235810be700e993e343a408693e80ce7f6a40108029", 58 | "sha256:3773c4d81e6e818df2efbc7dd77325ca0dcb688116050fb2b3011218eda36139", 59 | "sha256:3b96a311ac60a3f6be21d2572e46ce67f09abcf4d09344c49274eb9e0bf345fc", 60 | "sha256:3f7d084648d77af029acb79a0ff49a0ad7e9d09057a9bf46596dac9514dc07df", 61 | "sha256:41d45de54cd277a7878919867c0f08b0cf817605e4eb94093e7516505d3c8d14", 62 | "sha256:4238e6dab5d6a8ba812de994bbb0a79bddbdf80994e4ce802b6f6f3142fcc880", 63 | "sha256:45db3a33139e9c8f7c09234b5784a5e33d31fd6907800b316decad50af323ff2", 64 | "sha256:45e8636704eacc432a206ac7345a5d3d2c62d95a507ec70d62f23cd91770482a", 65 | "sha256:4958391dbd6249d7ad855b9ca88fae690783a6be9e86df65865058ed81fc860e", 66 | "sha256:4a306fa632e8f0928956a41fa8e1d6243c71e7eb59ffbd165fc0b41e316b2474", 67 | "sha256:57e9ac9ccc3101fac9d6014fba037473e4358ef4e89f8e181f8951a2c0162024", 68 | "sha256:59888172256cac5629e60e72e86598027aca6bf01fa2465bdb676d37636573e8", 69 | "sha256:5e069f72d497312b24fcc02073d70cb989045d1c91cbd53979366077959933e0", 70 | "sha256:64d4ec9f448dfe041705426000cc13e34e6e5bb13736e9fd62e34a0b0c41566e", 71 | "sha256:6dc2737a3674b3e344847c8686cf29e500584ccad76204efea14f451d4cc669a", 72 | "sha256:74fdfdbfdc48d3f47148976f49fab3251e550a8720bebc99bf1483f5bfb5db3e", 73 | "sha256:75e4024375654472cc27e91cbe9eaa08567f7fbdf822638be2814ce059f58032", 74 | "sha256:786902fb9ba7433aae840e0ed609f45c7bcd4e225ebb9c753aa39725bb3e6ad6", 75 | "sha256:8b6c2ea03845c9f501ed1313e78de148cd3f6cad741a75d43a29b43da27f2e1e", 76 | "sha256:91d77d2a782be4274da750752bb1650a97bfd8f291022b379bb8e01c66b4e96b", 77 | "sha256:91ec59c33514b7c7559a6acda53bbfe1b283949c34fe7440bcf917f96ac0723e", 78 | "sha256:920f0d66a896c2d99f0adbb391f990a84091179542c205fa53ce5787aff87954", 79 | "sha256:a5263e363c27b653a90078143adb3d076c1a748ec9ecc78ea2fb916f9b861962", 80 | "sha256:abb9a20a72ac4e0fdb50dae135ba5e77880518e742077ced47eb1499e29a443c", 81 | "sha256:c2051981a968d7de9dd2d7b87bcb9c939c74a34626a6e2f8181455dd49ed69e4", 82 | "sha256:c21c9e3896c23007803a875460fb786118f0cdd4434359577ea25eb556e34c55", 83 | "sha256:c2502a1a03b6312837279c8c1bd3ebedf6c12c4228ddbad40912d671ccc8a962", 84 | "sha256:d4d692a89c5cf08a8557fdeb329b82e7bf609aadfaed6c0d79f5a449a3c7c023", 85 | "sha256:da5db4e883f1ce37f55c667e5c0de439df76ac4cb55964655906306918e7363c", 86 | "sha256:e7022a66d9b55e93e1a845d8c9eba2a1bebd4966cd8bfc25d9cd07d515b33fa6", 87 | "sha256:ef1f279350da2c586a69d32fc8733092fd32cc8ac95139a00377841f59a3f8d8", 88 | "sha256:f54a64f8b0c8ff0b64d18aa76675262e1700f3995182267998c31ae974fbc382", 89 | "sha256:f5c7150ad32ba43a07c4479f40241756145a1f03b43480e058cfd862bf5041c7", 90 | "sha256:f6f824dc3bce0edab5f427efcfb1d63ee75b6fcb7282900ccaf925be84efb0fc", 91 | "sha256:fd8a250edc26254fe5b33be00402e6d287f562b6a5b2152dec302fa15bb3e997", 92 | "sha256:ffaa5c925128e29efbde7301d8ecaf35c8c60ffbcd6a1ffd3a552177c8e5e796" 93 | ], 94 | "version": "==1.15.0" 95 | }, 96 | "click": { 97 | "hashes": [ 98 | "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3", 99 | "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b" 100 | ], 101 | "version": "==8.0.3" 102 | }, 103 | "cryptography": { 104 | "hashes": [ 105 | "sha256:0a817b961b46894c5ca8a66b599c745b9a3d9f822725221f0e0fe49dc043a3a3", 106 | "sha256:2d87cdcb378d3cfed944dac30596da1968f88fb96d7fc34fdae30a99054b2e31", 107 | "sha256:30ee1eb3ebe1644d1c3f183d115a8c04e4e603ed6ce8e394ed39eea4a98469ac", 108 | "sha256:391432971a66cfaf94b21c24ab465a4cc3e8bf4a939c1ca5c3e3a6e0abebdbcf", 109 | "sha256:39bdf8e70eee6b1c7b289ec6e5d84d49a6bfa11f8b8646b5b3dfe41219153316", 110 | "sha256:4caa4b893d8fad33cf1964d3e51842cd78ba87401ab1d2e44556826df849a8ca", 111 | "sha256:53e5c1dc3d7a953de055d77bef2ff607ceef7a2aac0353b5d630ab67f7423638", 112 | "sha256:596f3cd67e1b950bc372c33f1a28a0692080625592ea6392987dba7f09f17a94", 113 | "sha256:5d59a9d55027a8b88fd9fd2826c4392bd487d74bf628bb9d39beecc62a644c12", 114 | "sha256:6c0c021f35b421ebf5976abf2daacc47e235f8b6082d3396a2fe3ccd537ab173", 115 | "sha256:73bc2d3f2444bcfeac67dd130ff2ea598ea5f20b40e36d19821b4df8c9c5037b", 116 | "sha256:74d6c7e80609c0f4c2434b97b80c7f8fdfaa072ca4baab7e239a15d6d70ed73a", 117 | "sha256:7be0eec337359c155df191d6ae00a5e8bbb63933883f4f5dffc439dac5348c3f", 118 | "sha256:94ae132f0e40fe48f310bba63f477f14a43116f05ddb69d6fa31e93f05848ae2", 119 | "sha256:bb5829d027ff82aa872d76158919045a7c1e91fbf241aec32cb07956e9ebd3c9", 120 | "sha256:ca238ceb7ba0bdf6ce88c1b74a87bffcee5afbfa1e41e173b1ceb095b39add46", 121 | "sha256:ca28641954f767f9822c24e927ad894d45d5a1e501767599647259cbf030b903", 122 | "sha256:e0344c14c9cb89e76eb6a060e67980c9e35b3f36691e15e1b7a9e58a0a6c6dc3", 123 | "sha256:ebc15b1c22e55c4d5566e3ca4db8689470a0ca2babef8e3a9ee057a8b82ce4b1", 124 | "sha256:ec63da4e7e4a5f924b90af42eddf20b698a70e58d86a72d943857c4c6045b3ee" 125 | ], 126 | "index": "pypi", 127 | "version": "==36.0.1" 128 | }, 129 | "fastapi": { 130 | "hashes": [ 131 | "sha256:dcfee92a7f9a72b5d4b7ca364bd2b009f8fc10d95ed5769be20e94f39f7e5a15", 132 | "sha256:f0a618aff5f6942862f2d3f20f39b1c037e33314d1b8207fd1c3a2cca76dfd8c" 133 | ], 134 | "index": "pypi", 135 | "version": "==0.73.0" 136 | }, 137 | "greenlet": { 138 | "hashes": [ 139 | "sha256:03e6e40a1c6d523e59e4b80173986dfb4bdefbbd14104a6f1a9d321bb4dc0226", 140 | "sha256:045a6cdd8d7ba5fffb82b9d4d35ae99bbc57afdd03a8b8eb161ec6fd0d2fc15b", 141 | "sha256:04828fcd02de1fa606560ac13eaa026a3f1859bbb6098cbb4e2c9471bce73e17", 142 | "sha256:063c55ae93b19dcbd077182d34ab7e70838d16edae8a5ba9fe1c8f9a6530201d", 143 | "sha256:08f03790cd6105a5b0f452d798a22bd72944bda41dc674d39dc8e485b730056e", 144 | "sha256:22b2111811abbd2af884426b2286b41ad3dbec15dcd362f68fc319abdf2d6f36", 145 | "sha256:44440890e79d8bded5893fa4c322c3d8bf18fdf87657fd6523252ec247be6f4b", 146 | "sha256:4c74283a777414ea1382448f70340096b360e3dc4bedc64259b0e355328f2f5a", 147 | "sha256:4c79da840373815c8ebbde0e64aa0b74fbfe74394665dcf318cfd7220ca9ed8b", 148 | "sha256:4cedd60664090cc7407119fd40b91c9a2a640909c8c59273b180ba61b1ff9210", 149 | "sha256:53f90311f1779fac5641a75c01ba3b9d088688518915b7138b2f0636f151c20a", 150 | "sha256:5667b436e4a365f9bc9bb98c0d5356c1929a62a51d78373c92870a138ada273a", 151 | "sha256:5aa13f7f2650f39653c096cead3346e0a69cc17ad29a91a3a6776801f124b963", 152 | "sha256:5f9a1fdd3339cd2fcaa2e768fb297429601888ef28ab9509a34cb3dd4497c88f", 153 | "sha256:61c2fbbf1cebb7cbaa35690143b5dc3212d764c7975957cc5aeacfd5686ad534", 154 | "sha256:63e0620aec7dc22fd988ec2c62c7e678921d13cf8eaefc2d2df6cc065998cc7b", 155 | "sha256:676d9c5f0428da9f69621ff71091b4c02d952a2f7e71a47891cde93b9114f048", 156 | "sha256:678065b2bc9a2fb804a61cfddac6b44cbddb1787e619e47eae3cb25c57709516", 157 | "sha256:68ebc87166fc0a13d9fb0b7f231790369ea03ca0b7efa6d100ea2f701dfb6a6a", 158 | "sha256:69a681b219c1208f0dd40c29c142e44a436f1f7add8ae9ac93470c1764b38980", 159 | "sha256:6bcfa9dd47645ea7ab072422405858ab8afb8420014bd2dfde0fed78d4026e08", 160 | "sha256:757ddbadc18515d28018c53f98bf85ea7af9fb7accff0d7b5d681bcbfdca9a74", 161 | "sha256:7bf83a6b7f068e631cfae0a0fc9f7ca73bc8115c0d6240131b1d5c5d7a65bbc2", 162 | "sha256:800c0e9f13df16c36df8b040bb1693cea4e8375b8ddc730013c87ed656d3659c", 163 | "sha256:80e8f41031b26856b8e4a0f65a395bb57cb3fcc22a810f87994a266f63f22fd0", 164 | "sha256:81e8c96d0f590c11ffcbed42293dc3e10be1639a57b0e531a937ac61fb400224", 165 | "sha256:85a8b1bfccf88326cf36a43a6cd7990afa22f0a02da624ca18ac7eb16bc14edd", 166 | "sha256:9ad8a0b3542747b4311f03784a87ba2f1c2a0bf15e7e95ecf06d97ccea2f81e9", 167 | "sha256:9ae7b519fbacaa5bf7e9ba71d582da463ce049e493568be6da80f444504bc951", 168 | "sha256:9d531a58f3feb283f120bacc817e4d75289bde8263363fbfeedf96376a1c68a8", 169 | "sha256:9db3f35c9c493dbbf053fb13285822bccbf2a76049328d10edf0daf4591b65a0", 170 | "sha256:9dcc10e86164853c5267bfac43816048a12dcf4c898c1b83a2eb8d5933da9ee0", 171 | "sha256:a172161ec09ef67f8b88fce873f3b6b37ca99b4ddd2536147dc611d4d645bc28", 172 | "sha256:a34b6d63ebaab722f79df4f79cbceab6fac2f96546561848a8ce1513a4478e16", 173 | "sha256:a74c507dbef45ba85f8565a1bc297f97342a246078af5ea05330992d5a26e72c", 174 | "sha256:ab6385c0a16c1d33ab45593f0cad49834918ad83d0406b58cd62f1454a1778c6", 175 | "sha256:ab951ebc9f4c63d9ba0518d533f358519e3633c3a263bfba8674ee0c5043bd1a", 176 | "sha256:b3ff97e9761e3c392eaba4b7f17da9deb9e1177b372313611ee2358a19f235bb", 177 | "sha256:b68ff6925dd210a4eac47df411316168a2448178f837fcb01597d9a183ad8603", 178 | "sha256:b904cbb4b69fa959674043d39aa34ec84abca917037ec931d72003b60b311174", 179 | "sha256:be681332594c3361a32198fe591f966e6114c67bf62e1cbb1f6fe700e7f809b3", 180 | "sha256:c006d07a64777466b4ecf75a3fc86f7c687021e9b1fae0a0c3157ae93ce44563", 181 | "sha256:c9525a82b0ff1bb35253ec2d2e9430c53479274e65bddefbfd5db74972c7202d", 182 | "sha256:cb1f258971419b4b34f71736b09ce7d3daeea71a5660eb28b34f8a80520ee20b", 183 | "sha256:ce1f6e65a3b9b6a8b5b1f64ef75e49fa159721c8882027b50cfaa82472bd1c10", 184 | "sha256:ce2ec312bcb516a83780b659fd008fdd26af449b653c8ffa52e203a397765cc2", 185 | "sha256:da809e3861a8f697727b6bdf4c735184912215d2eb9df15eb7ad3d6c9d533a52", 186 | "sha256:edacb7c0f8a42e6df031ef675e29156ca933403f1cb8027e8f2c82ad8d68bc67", 187 | "sha256:fa04d0419b2ed61125bb8a4a0a810cad428546adeee87cab6f2beee50259fecc" 188 | ], 189 | "markers": "python_version >= '3' and (platform_machine == 'aarch64' or (platform_machine == 'ppc64le' or (platform_machine == 'x86_64' or (platform_machine == 'amd64' or (platform_machine == 'AMD64' or (platform_machine == 'win32' or platform_machine == 'WIN32'))))))", 190 | "version": "==2.0.0a1" 191 | }, 192 | "h11": { 193 | "hashes": [ 194 | "sha256:70813c1135087a248a4d38cc0e1a0181ffab2188141a93eaf567940c3957ff06", 195 | "sha256:8ddd78563b633ca55346c8cd41ec0af27d3c79931828beffb46ce70a379e7442" 196 | ], 197 | "version": "==0.13.0" 198 | }, 199 | "idna": { 200 | "hashes": [ 201 | "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff", 202 | "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d" 203 | ], 204 | "version": "==3.3" 205 | }, 206 | "mako": { 207 | "hashes": [ 208 | "sha256:4e9e345a41924a954251b95b4b28e14a301145b544901332e658907a7464b6b2", 209 | "sha256:afaf8e515d075b22fad7d7b8b30e4a1c90624ff2f3733a06ec125f5a5f043a57" 210 | ], 211 | "version": "==1.1.6" 212 | }, 213 | "markupsafe": { 214 | "hashes": [ 215 | "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298", 216 | "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64", 217 | "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b", 218 | "sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194", 219 | "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567", 220 | "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff", 221 | "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724", 222 | "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74", 223 | "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646", 224 | "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35", 225 | "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6", 226 | "sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a", 227 | "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6", 228 | "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad", 229 | "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26", 230 | "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38", 231 | "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac", 232 | "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7", 233 | "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6", 234 | "sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047", 235 | "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75", 236 | "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f", 237 | "sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b", 238 | "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135", 239 | "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8", 240 | "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a", 241 | "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a", 242 | "sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1", 243 | "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9", 244 | "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864", 245 | "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914", 246 | "sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee", 247 | "sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f", 248 | "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18", 249 | "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8", 250 | "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2", 251 | "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d", 252 | "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b", 253 | "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b", 254 | "sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86", 255 | "sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6", 256 | "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f", 257 | "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb", 258 | "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833", 259 | "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28", 260 | "sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e", 261 | "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415", 262 | "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902", 263 | "sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f", 264 | "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d", 265 | "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9", 266 | "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d", 267 | "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145", 268 | "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066", 269 | "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c", 270 | "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1", 271 | "sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a", 272 | "sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207", 273 | "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f", 274 | "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53", 275 | "sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd", 276 | "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134", 277 | "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85", 278 | "sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9", 279 | "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5", 280 | "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94", 281 | "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509", 282 | "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51", 283 | "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872" 284 | ], 285 | "version": "==2.0.1" 286 | }, 287 | "pycparser": { 288 | "hashes": [ 289 | "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9", 290 | "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206" 291 | ], 292 | "version": "==2.21" 293 | }, 294 | "pydantic": { 295 | "hashes": [ 296 | "sha256:085ca1de245782e9b46cefcf99deecc67d418737a1fd3f6a4f511344b613a5b3", 297 | "sha256:086254884d10d3ba16da0588604ffdc5aab3f7f09557b998373e885c690dd398", 298 | "sha256:0b6037175234850ffd094ca77bf60fb54b08b5b22bc85865331dd3bda7a02fa1", 299 | "sha256:0fe476769acaa7fcddd17cadd172b156b53546ec3614a4d880e5d29ea5fbce65", 300 | "sha256:1d5278bd9f0eee04a44c712982343103bba63507480bfd2fc2790fa70cd64cf4", 301 | "sha256:2cc6a4cb8a118ffec2ca5fcb47afbacb4f16d0ab8b7350ddea5e8ef7bcc53a16", 302 | "sha256:2ee7e3209db1e468341ef41fe263eb655f67f5c5a76c924044314e139a1103a2", 303 | "sha256:3011b975c973819883842c5ab925a4e4298dffccf7782c55ec3580ed17dc464c", 304 | "sha256:3c3b035103bd4e2e4a28da9da7ef2fa47b00ee4a9cf4f1a735214c1bcd05e0f6", 305 | "sha256:4c68c3bc88dbda2a6805e9a142ce84782d3930f8fdd9655430d8576315ad97ce", 306 | "sha256:574936363cd4b9eed8acdd6b80d0143162f2eb654d96cb3a8ee91d3e64bf4cf9", 307 | "sha256:5a79330f8571faf71bf93667d3ee054609816f10a259a109a0738dac983b23c3", 308 | "sha256:5e48ef4a8b8c066c4a31409d91d7ca372a774d0212da2787c0d32f8045b1e034", 309 | "sha256:6c5b77947b9e85a54848343928b597b4f74fc364b70926b3c4441ff52620640c", 310 | "sha256:742645059757a56ecd886faf4ed2441b9c0cd406079c2b4bee51bcc3fbcd510a", 311 | "sha256:7bdfdadb5994b44bd5579cfa7c9b0e1b0e540c952d56f627eb227851cda9db77", 312 | "sha256:815ddebb2792efd4bba5488bc8fde09c29e8ca3227d27cf1c6990fc830fd292b", 313 | "sha256:8b5ac0f1c83d31b324e57a273da59197c83d1bb18171e512908fe5dc7278a1d6", 314 | "sha256:96f240bce182ca7fe045c76bcebfa0b0534a1bf402ed05914a6f1dadff91877f", 315 | "sha256:a733965f1a2b4090a5238d40d983dcd78f3ecea221c7af1497b845a9709c1721", 316 | "sha256:ab624700dc145aa809e6f3ec93fb8e7d0f99d9023b713f6a953637429b437d37", 317 | "sha256:b2571db88c636d862b35090ccf92bf24004393f85c8870a37f42d9f23d13e032", 318 | "sha256:bbbc94d0c94dd80b3340fc4f04fd4d701f4b038ebad72c39693c794fd3bc2d9d", 319 | "sha256:c0727bda6e38144d464daec31dff936a82917f431d9c39c39c60a26567eae3ed", 320 | "sha256:c556695b699f648c58373b542534308922c46a1cda06ea47bc9ca45ef5b39ae6", 321 | "sha256:c86229333cabaaa8c51cf971496f10318c4734cf7b641f08af0a6fbf17ca3054", 322 | "sha256:c8d7da6f1c1049eefb718d43d99ad73100c958a5367d30b9321b092771e96c25", 323 | "sha256:c8e9dcf1ac499679aceedac7e7ca6d8641f0193c591a2d090282aaf8e9445a46", 324 | "sha256:cb23bcc093697cdea2708baae4f9ba0e972960a835af22560f6ae4e7e47d33f5", 325 | "sha256:d1e4c28f30e767fd07f2ddc6f74f41f034d1dd6bc526cd59e63a82fe8bb9ef4c", 326 | "sha256:d9c9bdb3af48e242838f9f6e6127de9be7063aad17b32215ccc36a09c5cf1070", 327 | "sha256:dee5ef83a76ac31ab0c78c10bd7d5437bfdb6358c95b91f1ba7ff7b76f9996a1", 328 | "sha256:e0896200b6a40197405af18828da49f067c2fa1f821491bc8f5bde241ef3f7d7", 329 | "sha256:f5a64b64ddf4c99fe201ac2724daada8595ada0d102ab96d019c1555c2d6441d", 330 | "sha256:f947352c3434e8b937e3aa8f96f47bdfe6d92779e44bb3f41e4c213ba6a32145" 331 | ], 332 | "version": "==1.9.0" 333 | }, 334 | "pyjwt": { 335 | "hashes": [ 336 | "sha256:b888b4d56f06f6dcd777210c334e69c737be74755d3e5e9ee3fe67dc18a0ee41", 337 | "sha256:e0c4bb8d9f0af0c7f5b1ec4c5036309617d03d56932877f2f7a0beeb5318322f" 338 | ], 339 | "index": "pypi", 340 | "version": "==2.3.0" 341 | }, 342 | "pyyaml": { 343 | "hashes": [ 344 | "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293", 345 | "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b", 346 | "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57", 347 | "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b", 348 | "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4", 349 | "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07", 350 | "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba", 351 | "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9", 352 | "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287", 353 | "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513", 354 | "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0", 355 | "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0", 356 | "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92", 357 | "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f", 358 | "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2", 359 | "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc", 360 | "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c", 361 | "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86", 362 | "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4", 363 | "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c", 364 | "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34", 365 | "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b", 366 | "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c", 367 | "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb", 368 | "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737", 369 | "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3", 370 | "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d", 371 | "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53", 372 | "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78", 373 | "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803", 374 | "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a", 375 | "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174", 376 | "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5" 377 | ], 378 | "index": "pypi", 379 | "version": "==6.0" 380 | }, 381 | "sniffio": { 382 | "hashes": [ 383 | "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663", 384 | "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de" 385 | ], 386 | "version": "==1.2.0" 387 | }, 388 | "sqlalchemy": { 389 | "hashes": [ 390 | "sha256:05fa14f279d43df68964ad066f653193187909950aa0163320b728edfc400167", 391 | "sha256:0ddc5e5ccc0160e7ad190e5c61eb57560f38559e22586955f205e537cda26034", 392 | "sha256:15a03261aa1e68f208e71ae3cd845b00063d242cbf8c87348a0c2c0fc6e1f2ac", 393 | "sha256:289465162b1fa1e7a982f8abe59d26a8331211cad4942e8031d2b7db1f75e649", 394 | "sha256:2e216c13ecc7fcdcbb86bb3225425b3ed338e43a8810c7089ddb472676124b9b", 395 | "sha256:2fd4d3ca64c41dae31228b80556ab55b6489275fb204827f6560b65f95692cf3", 396 | "sha256:330eb45395874cc7787214fdd4489e2afb931bc49e0a7a8f9cd56d6e9c5b1639", 397 | "sha256:3c7ed6c69debaf6198fadb1c16ae1253a29a7670bbf0646f92582eb465a0b999", 398 | "sha256:4ad31cec8b49fd718470328ad9711f4dc703507d434fd45461096da0a7135ee0", 399 | "sha256:57205844f246bab9b666a32f59b046add8995c665d9ecb2b7b837b087df90639", 400 | "sha256:582b59d1e5780a447aada22b461e50b404a9dc05768da1d87368ad8190468418", 401 | "sha256:5e9c7b3567edbc2183607f7d9f3e7e89355b8f8984eec4d2cd1e1513c8f7b43f", 402 | "sha256:6a01ec49ca54ce03bc14e10de55dfc64187a2194b3b0e5ac0fdbe9b24767e79e", 403 | "sha256:6f22c040d196f841168b1456e77c30a18a3dc16b336ddbc5a24ce01ab4e95ae0", 404 | "sha256:81f2dd355b57770fdf292b54f3e0a9823ec27a543f947fa2eb4ec0df44f35f0d", 405 | "sha256:85e4c244e1de056d48dae466e9baf9437980c19fcde493e0db1a0a986e6d75b4", 406 | "sha256:8d0949b11681380b4a50ac3cd075e4816afe9fa4a8c8ae006c1ca26f0fa40ad8", 407 | "sha256:975f5c0793892c634c4920057da0de3a48bbbbd0a5c86f5fcf2f2fedf41b76da", 408 | "sha256:9e4fb2895b83993831ba2401b6404de953fdbfa9d7d4fa6a4756294a83bbc94f", 409 | "sha256:b35dca159c1c9fa8a5f9005e42133eed82705bf8e243da371a5e5826440e65ca", 410 | "sha256:b7b20c88873675903d6438d8b33fba027997193e274b9367421e610d9da76c08", 411 | "sha256:bb4b15fb1f0aafa65cbdc62d3c2078bea1ceecbfccc9a1f23a2113c9ac1191fa", 412 | "sha256:c0c7171aa5a57e522a04a31b84798b6c926234cb559c0939840c3235cf068813", 413 | "sha256:c317ddd7c586af350a6aef22b891e84b16bff1a27886ed5b30f15c1ed59caeaa", 414 | "sha256:c3abc34fed19fdeaead0ced8cf56dd121f08198008c033596aa6aae7cc58f59f", 415 | "sha256:ca68c52e3cae491ace2bf39b35fef4ce26c192fd70b4cd90f040d419f70893b5", 416 | "sha256:cf2cd387409b12d0a8b801610d6336ee7d24043b6dd965950eaec09b73e7262f", 417 | "sha256:d046a9aeba9bc53e88a41e58beb72b6205abb9a20f6c136161adf9128e589db5", 418 | "sha256:d5c20c8415173b119762b6110af64448adccd4d11f273fb9f718a9865b88a99c", 419 | "sha256:d86132922531f0dc5a4f424c7580a472a924dd737602638e704841c9cb24aea2", 420 | "sha256:dccff41478050e823271642837b904d5f9bda3f5cf7d371ce163f00a694118d6", 421 | "sha256:de85c26a5a1c72e695ab0454e92f60213b4459b8d7c502e0be7a6369690eeb1a", 422 | "sha256:e3a86b59b6227ef72ffc10d4b23f0fe994bef64d4667eab4fb8cd43de4223bec", 423 | "sha256:e79e73d5ee24196d3057340e356e6254af4d10e1fc22d3207ea8342fc5ffb977", 424 | "sha256:ea8210090a816d48a4291a47462bac750e3bc5c2442e6d64f7b8137a7c3f9ac5", 425 | "sha256:f3b7ec97e68b68cb1f9ddb82eda17b418f19a034fa8380a0ac04e8fe01532875" 426 | ], 427 | "index": "pypi", 428 | "version": "==1.4.31" 429 | }, 430 | "starlette": { 431 | "hashes": [ 432 | "sha256:26a18cbda5e6b651c964c12c88b36d9898481cd428ed6e063f5f29c418f73050", 433 | "sha256:57eab3cc975a28af62f6faec94d355a410634940f10b30d68d31cb5ec1b44ae8" 434 | ], 435 | "version": "==0.17.1" 436 | }, 437 | "typing-extensions": { 438 | "hashes": [ 439 | "sha256:4ca091dea149f945ec56afb48dae714f21e8692ef22a395223bcd328961b6a0e", 440 | "sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b" 441 | ], 442 | "version": "==4.0.1" 443 | }, 444 | "uvicorn": { 445 | "hashes": [ 446 | "sha256:8b16d9ecb76500f7804184f182835fe8a2b54716d3b0b6bb2da0b2b192f62c73", 447 | "sha256:dffbacb8cc25d924d68d231d2c478c4fe6727c36537d8de21e5de591b37afc41" 448 | ], 449 | "index": "pypi", 450 | "version": "==0.17.1" 451 | } 452 | }, 453 | "develop": { 454 | "black": { 455 | "hashes": [ 456 | "sha256:07e5c049442d7ca1a2fc273c79d1aecbbf1bc858f62e8184abe1ad175c4f7cc2", 457 | "sha256:0e21e1f1efa65a50e3960edd068b6ae6d64ad6235bd8bfea116a03b21836af71", 458 | "sha256:1297c63b9e1b96a3d0da2d85d11cd9bf8664251fd69ddac068b98dc4f34f73b6", 459 | "sha256:228b5ae2c8e3d6227e4bde5920d2fc66cc3400fde7bcc74f480cb07ef0b570d5", 460 | "sha256:2d6f331c02f0f40aa51a22e479c8209d37fcd520c77721c034517d44eecf5912", 461 | "sha256:2ff96450d3ad9ea499fc4c60e425a1439c2120cbbc1ab959ff20f7c76ec7e866", 462 | "sha256:3524739d76b6b3ed1132422bf9d82123cd1705086723bc3e235ca39fd21c667d", 463 | "sha256:35944b7100af4a985abfcaa860b06af15590deb1f392f06c8683b4381e8eeaf0", 464 | "sha256:373922fc66676133ddc3e754e4509196a8c392fec3f5ca4486673e685a421321", 465 | "sha256:5fa1db02410b1924b6749c245ab38d30621564e658297484952f3d8a39fce7e8", 466 | "sha256:6f2f01381f91c1efb1451998bd65a129b3ed6f64f79663a55fe0e9b74a5f81fd", 467 | "sha256:742ce9af3086e5bd07e58c8feb09dbb2b047b7f566eb5f5bc63fd455814979f3", 468 | "sha256:7835fee5238fc0a0baf6c9268fb816b5f5cd9b8793423a75e8cd663c48d073ba", 469 | "sha256:8871fcb4b447206904932b54b567923e5be802b9b19b744fdff092bd2f3118d0", 470 | "sha256:a7c0192d35635f6fc1174be575cb7915e92e5dd629ee79fdaf0dcfa41a80afb5", 471 | "sha256:b1a5ed73ab4c482208d20434f700d514f66ffe2840f63a6252ecc43a9bc77e8a", 472 | "sha256:c8226f50b8c34a14608b848dc23a46e5d08397d009446353dad45e04af0c8e28", 473 | "sha256:ccad888050f5393f0d6029deea2a33e5ae371fd182a697313bdbd835d3edaf9c", 474 | "sha256:dae63f2dbf82882fa3b2a3c49c32bffe144970a573cd68d247af6560fc493ae1", 475 | "sha256:e2f69158a7d120fd641d1fa9a921d898e20d52e44a74a6fbbcc570a62a6bc8ab", 476 | "sha256:efbadd9b52c060a8fc3b9658744091cb33c31f830b3f074422ed27bad2b18e8f", 477 | "sha256:f5660feab44c2e3cb24b2419b998846cbb01c23c7fe645fee45087efa3da2d61", 478 | "sha256:fdb8754b453fb15fad3f72cd9cad3e16776f0964d67cf30ebcbf10327a3777a3" 479 | ], 480 | "index": "pypi", 481 | "version": "==22.1.0" 482 | }, 483 | "click": { 484 | "hashes": [ 485 | "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3", 486 | "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b" 487 | ], 488 | "version": "==8.0.3" 489 | }, 490 | "mypy-extensions": { 491 | "hashes": [ 492 | "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d", 493 | "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8" 494 | ], 495 | "version": "==0.4.3" 496 | }, 497 | "pathspec": { 498 | "hashes": [ 499 | "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a", 500 | "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1" 501 | ], 502 | "version": "==0.9.0" 503 | }, 504 | "platformdirs": { 505 | "hashes": [ 506 | "sha256:1d7385c7db91728b83efd0ca99a5afb296cab9d0ed8313a45ed8ba17967ecfca", 507 | "sha256:440633ddfebcc36264232365d7840a970e75e1018d15b4327d11f91909045fda" 508 | ], 509 | "version": "==2.4.1" 510 | }, 511 | "tomli": { 512 | "hashes": [ 513 | "sha256:b5bde28da1fed24b9bd1d4d2b8cba62300bfb4ec9a6187a957e8ddb9434c5224", 514 | "sha256:c292c34f58502a1eb2bbb9f5bbc9a5ebc37bee10ffb8c2d6bbdfa8eb13cc14e1" 515 | ], 516 | "version": "==2.0.0" 517 | }, 518 | "typing-extensions": { 519 | "hashes": [ 520 | "sha256:4ca091dea149f945ec56afb48dae714f21e8692ef22a395223bcd328961b6a0e", 521 | "sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b" 522 | ], 523 | "version": "==4.0.1" 524 | } 525 | } 526 | } 527 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FastAPI with SQLAlchemy Tutorial 2 | 3 | Code for my video tutorial [FastAPI with SQLAlchemy Tutorial](https://youtu.be/8GSYx-KDEas) 4 | 5 | ## What is FastAPI? 6 | 7 | FastAPI is a high-performant REST API framework for Python. It's built on top of 8 | [Starlette](https://www.starlette.io/) and it uses [Pydantic](https://pydantic-docs.helpmanual.io/) 9 | for data validation. It can generate OpenAPI documentation from your code and also produces 10 | a Swagger UI that you can use to test your application. 11 | 12 | Check out FastAPI's GitHub [repository](https://github.com/tiangolo/fastapi) and give it a 13 | star! Also make sure to check out its excellent [documentation](https://fastapi.tiangolo.com/) online. 14 | 15 | ## What are SQLAlchemy and Alembic? 16 | 17 | * *SQLAlchemy* is Python's most popular Object Relational Mapper (ORM). ORMs are frameworks that offer an 18 | object-oriented interface to your database tables. ORMs give you a layer of abstraction on top of SQL, so 19 | you don't have to write SQL queries by hand - instead, you just write code. ORMs also abstract away the 20 | differences between SQL engines, such as PostgreSQL and MySQL, so you can switch between one and the other 21 | without having to change your code. You can learn more about SQLAlchemy with its official documentation: 22 | https://www.sqlalchemy.org/. 23 | 24 | * *Alembic* is a database migrations management framework. Alembic ensures that your database schemas 25 | accurately reflect the data models that you define with SQLAlchemy. You can learn more about Alembic with 26 | its official documentation: https://alembic.sqlalchemy.org/en/latest/ 27 | 28 | 29 | -------------------------------------------------------------------------------- /alembic.ini: -------------------------------------------------------------------------------- 1 | # A generic, single database configuration. 2 | 3 | [alembic] 4 | # path to migration scripts 5 | script_location = migrations 6 | 7 | # template used to generate migration files 8 | # file_template = %%(rev)s_%%(slug)s 9 | 10 | # sys.path path, will be prepended to sys.path if present. 11 | # defaults to the current working directory. 12 | prepend_sys_path = . 13 | 14 | # timezone to use when rendering the date within the migration file 15 | # as well as the filename. 16 | # If specified, requires the python-dateutil library that can be 17 | # installed by adding `alembic[tz]` to the pip requirements 18 | # string value is passed to dateutil.tz.gettz() 19 | # leave blank for localtime 20 | # timezone = 21 | 22 | # max length of characters to apply to the 23 | # "slug" field 24 | # truncate_slug_length = 40 25 | 26 | # set to 'true' to run the environment during 27 | # the 'revision' command, regardless of autogenerate 28 | # revision_environment = false 29 | 30 | # set to 'true' to allow .pyc and .pyo files without 31 | # a source .py file to be detected as revisions in the 32 | # versions/ directory 33 | # sourceless = false 34 | 35 | # version location specification; This defaults 36 | # to migrations/versions. When using multiple version 37 | # directories, initial revisions must be specified with --version-path. 38 | # The path separator used here should be the separator specified by "version_path_separator" below. 39 | # version_locations = %(here)s/bar:%(here)s/bat:migrations/versions 40 | 41 | # version path separator; As mentioned above, this is the character used to split 42 | # version_locations. The default within new alembic.ini files is "os", which uses os.pathsep. 43 | # If this key is omitted entirely, it falls back to the legacy behavior of splitting on spaces and/or commas. 44 | # Valid values for version_path_separator are: 45 | # 46 | # version_path_separator = : 47 | # version_path_separator = ; 48 | # version_path_separator = space 49 | version_path_separator = os # Use os.pathsep. Default configuration used for new projects. 50 | 51 | # the output encoding used when revision files 52 | # are written from script.py.mako 53 | # output_encoding = utf-8 54 | 55 | sqlalchemy.url = sqlite:///models.db 56 | 57 | 58 | [post_write_hooks] 59 | # post_write_hooks defines scripts or Python functions that are run 60 | # on newly generated revision scripts. See the documentation for further 61 | # detail and examples 62 | 63 | # format using "black" - use the console_scripts runner, against the "black" entrypoint 64 | # hooks = black 65 | # black.type = console_scripts 66 | # black.entrypoint = black 67 | # black.options = -l 79 REVISION_SCRIPT_FILENAME 68 | 69 | # Logging configuration 70 | [loggers] 71 | keys = root,sqlalchemy,alembic 72 | 73 | [handlers] 74 | keys = console 75 | 76 | [formatters] 77 | keys = generic 78 | 79 | [logger_root] 80 | level = WARN 81 | handlers = console 82 | qualname = 83 | 84 | [logger_sqlalchemy] 85 | level = WARN 86 | handlers = 87 | qualname = sqlalchemy.engine 88 | 89 | [logger_alembic] 90 | level = INFO 91 | handlers = 92 | qualname = alembic 93 | 94 | [handler_console] 95 | class = StreamHandler 96 | args = (sys.stderr,) 97 | level = NOTSET 98 | formatter = generic 99 | 100 | [formatter_generic] 101 | format = %(levelname)-5.5s [%(name)s] %(message)s 102 | datefmt = %H:%M:%S 103 | -------------------------------------------------------------------------------- /api/api.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import uuid 3 | 4 | from fastapi import HTTPException 5 | from starlette import status 6 | from starlette.requests import Request 7 | from starlette.responses import Response 8 | 9 | from api.schemas import ListTasksSchema, GetTaskSchema, CreateTaskSchema 10 | from api.server import server, session_maker 11 | from data_access.models import Task, User 12 | 13 | TODO = [] 14 | 15 | 16 | @server.get("/todo", response_model=ListTasksSchema) 17 | def get_tasks(request: Request): 18 | user_id = request.state.user_id 19 | with session_maker() as session: 20 | tasks = [ 21 | task.dict() for task in session.query(User).filter(User.id == user_id).first().tasks 22 | ] 23 | return {"tasks": tasks} 24 | 25 | 26 | @server.post("/todo", response_model=GetTaskSchema, status_code=status.HTTP_201_CREATED) 27 | def create_task(request: Request, payload: CreateTaskSchema): 28 | with session_maker() as session: 29 | task = Task( 30 | created=datetime.datetime.utcnow(), 31 | updated=datetime.datetime.utcnow(), 32 | priority=payload.priority.value, 33 | status=payload.status.value, 34 | task=payload.task, 35 | user_id=request.state.user_id 36 | ) 37 | session.add(task) 38 | session.commit() 39 | task = task.dict() 40 | return task 41 | 42 | 43 | @server.get("/todo/{task_id}", response_model=GetTaskSchema) 44 | def get_task(request: Request, task_id: uuid.UUID): 45 | with session_maker() as session: 46 | task = session.query(Task).filter( 47 | Task.id == str(task_id), Task.user_id == request.state.user_id 48 | ).first() 49 | if task is None: 50 | raise HTTPException(status_code=404, detail=f"Task with ID {task_id} not found") 51 | return task.dict() 52 | 53 | 54 | @server.put("/todo/{task_id}", response_model=GetTaskSchema) 55 | def update_task(request: Request, task_id: uuid.UUID, payload: CreateTaskSchema): 56 | with session_maker() as session: 57 | task = session.query(Task).filter( 58 | Task.id == str(task_id), Task.user_id == request.state.user_id 59 | ).first() 60 | if task is None: 61 | raise HTTPException(status_code=404, detail=f"Task with ID {task_id} not found") 62 | task.status = payload.status.value 63 | task.priority = payload.priority.value 64 | task.task = payload.task 65 | task.updated = datetime.datetime.utcnow() 66 | session.add(task) 67 | session.commit() 68 | task = task.dict() 69 | return task 70 | 71 | 72 | @server.delete( 73 | "/todo/{task_id}", status_code=status.HTTP_204_NO_CONTENT, response_class=Response 74 | ) 75 | def delete_task(request: Request, task_id: uuid.UUID): 76 | with session_maker() as session: 77 | task = session.query(Task).filter( 78 | Task.id == str(task_id), Task.user_id == request.state.user_id 79 | ).first() 80 | if task is None: 81 | raise HTTPException(status_code=404, detail=f"Task with ID {task_id} not found") 82 | session.delete(task) 83 | session.commit() 84 | -------------------------------------------------------------------------------- /api/auth.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | import jwt 4 | from cryptography.x509 import load_pem_x509_certificate 5 | 6 | 7 | def decode_and_validate_token(access_token): 8 | unverified_headers = jwt.get_unverified_header(access_token) 9 | public_key = load_pem_x509_certificate( 10 | (Path(__file__).parent / "../public_key.pem").read_text().encode("utf-8") 11 | ).public_key() 12 | return jwt.decode( 13 | access_token, 14 | key=public_key, 15 | algorithms=unverified_headers["alg"], 16 | audience="http://127.0.0.1:8000/todo", 17 | ) 18 | -------------------------------------------------------------------------------- /api/schemas.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from enum import Enum 3 | from typing import Optional, List 4 | from uuid import UUID 5 | 6 | from pydantic import BaseModel 7 | 8 | 9 | class Error(BaseModel): 10 | detail: Optional[str] = None 11 | 12 | 13 | class Priority(Enum): 14 | low = "low" 15 | medium = "medium" 16 | high = "high" 17 | 18 | 19 | class Status(Enum): 20 | progress = "progress" 21 | pending = "pending" 22 | completed = "completed" 23 | 24 | 25 | class CreateTaskSchema(BaseModel): 26 | priority: Optional[Priority] = "low" 27 | status: Optional[Status] = "pending" 28 | task: str 29 | 30 | 31 | class GetTaskSchema(BaseModel): 32 | id: UUID 33 | created: datetime 34 | priority: Priority 35 | status: Status 36 | task: str 37 | 38 | 39 | class ListTasksSchema(BaseModel): 40 | tasks: List[GetTaskSchema] 41 | -------------------------------------------------------------------------------- /api/server.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | import yaml 4 | from fastapi import FastAPI 5 | from jwt import ( 6 | ExpiredSignatureError, 7 | ImmatureSignatureError, 8 | InvalidAlgorithmError, 9 | InvalidAudienceError, 10 | InvalidKeyError, 11 | InvalidSignatureError, 12 | InvalidTokenError, 13 | MissingRequiredClaimError, 14 | ) 15 | from sqlalchemy import create_engine 16 | from sqlalchemy.orm import sessionmaker 17 | from starlette import status 18 | from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint 19 | from starlette.middleware.cors import CORSMiddleware 20 | from starlette.requests import Request 21 | from starlette.responses import Response, JSONResponse 22 | 23 | from api.auth import decode_and_validate_token 24 | 25 | server = FastAPI(debug=True) 26 | 27 | oas_doc = yaml.safe_load((Path(__file__).parent / "../oas.yaml").read_text()) 28 | 29 | server.openapi = lambda: oas_doc 30 | 31 | session_maker = sessionmaker(bind=create_engine("sqlite:///models.db")) 32 | 33 | 34 | class AuthorizeRequestMiddleware(BaseHTTPMiddleware): 35 | async def dispatch( 36 | self, request: Request, call_next: RequestResponseEndpoint 37 | ) -> Response: 38 | if request.url.path in ["/docs", "/openapi.json"]: 39 | return await call_next(request) 40 | if request.method == "OPTIONS": 41 | return await call_next(request) 42 | 43 | bearer_token = request.headers.get("Authorization") 44 | if not bearer_token: 45 | return JSONResponse( 46 | status_code=status.HTTP_401_UNAUTHORIZED, 47 | content={ 48 | "detail": "Missing access token", 49 | "body": "Missing access token", 50 | }, 51 | ) 52 | try: 53 | auth_token = bearer_token.split(" ")[1].strip() 54 | token_payload = decode_and_validate_token(auth_token) 55 | except ( 56 | ExpiredSignatureError, 57 | ImmatureSignatureError, 58 | InvalidAlgorithmError, 59 | InvalidAudienceError, 60 | InvalidKeyError, 61 | InvalidSignatureError, 62 | InvalidTokenError, 63 | MissingRequiredClaimError, 64 | ) as error: 65 | return JSONResponse( 66 | status_code=status.HTTP_401_UNAUTHORIZED, 67 | content={"detail": str(error), "body": str(error)}, 68 | ) 69 | else: 70 | request.state.user_id = token_payload["sub"] 71 | return await call_next(request) 72 | 73 | 74 | server.add_middleware(AuthorizeRequestMiddleware) 75 | 76 | 77 | server.add_middleware( 78 | CORSMiddleware, 79 | allow_origins=["*"], 80 | allow_credentials=True, 81 | allow_methods=["*"], 82 | allow_headers=["*"], 83 | ) 84 | 85 | import api.api 86 | -------------------------------------------------------------------------------- /data_access/models.py: -------------------------------------------------------------------------------- 1 | import uuid 2 | 3 | from sqlalchemy import Column, String, DateTime, ForeignKey 4 | from sqlalchemy.orm import declarative_base, relationship 5 | 6 | Base = declarative_base() 7 | 8 | 9 | def generate_uuid(): 10 | return str(uuid.uuid4()) 11 | 12 | 13 | class User(Base): 14 | __tablename__ = "user" 15 | 16 | id = Column(String, primary_key=True, default=generate_uuid) 17 | created = Column(DateTime, nullable=False) 18 | email = Column(String, nullable=False) 19 | 20 | tasks = relationship("Task") 21 | 22 | def dict(self): 23 | return { 24 | "id": self.id, 25 | "created": self.created, 26 | "email": self.email, 27 | "tasks": self.tasks 28 | } 29 | 30 | 31 | class Task(Base): 32 | __tablename__ = "task" 33 | 34 | id = Column(String, primary_key=True, default=generate_uuid) 35 | created = Column(DateTime, nullable=False) 36 | updated = Column(DateTime, nullable=False) 37 | priority = Column(String, nullable=False) 38 | status = Column(String, nullable=False) 39 | task = Column(String, nullable=False) 40 | user_id = Column(String, ForeignKey("user.id")) 41 | 42 | def dict(self): 43 | return { 44 | "id": self.id, 45 | "created": self.created, 46 | "priority": self.priority, 47 | "status": self.status, 48 | "task": self.task, 49 | } 50 | -------------------------------------------------------------------------------- /jwt_generator.py: -------------------------------------------------------------------------------- 1 | import uuid 2 | from datetime import datetime, timedelta 3 | from pathlib import Path 4 | 5 | import jwt 6 | from cryptography.hazmat.primitives import serialization 7 | 8 | 9 | def generate_jwt(): 10 | now = datetime.utcnow() 11 | payload = { 12 | "iss": "https://auth.coffeemesh.io/", 13 | "sub": str(uuid.uuid4()), 14 | "aud": "http://127.0.0.1:8000/todo", 15 | "iat": now.timestamp(), 16 | "exp": (now + timedelta(hours=24)).timestamp(), 17 | "scope": "openid", 18 | } 19 | 20 | private_key_text = Path("private_key.pem").read_text() 21 | private_key = serialization.load_pem_private_key( 22 | private_key_text.encode(), 23 | password=None, 24 | ) 25 | return jwt.encode(payload=payload, key=private_key, algorithm="RS256") 26 | 27 | 28 | print(generate_jwt()) 29 | -------------------------------------------------------------------------------- /migrations/README: -------------------------------------------------------------------------------- 1 | Generic single-database configuration. -------------------------------------------------------------------------------- /migrations/env.py: -------------------------------------------------------------------------------- 1 | from logging.config import fileConfig 2 | 3 | from sqlalchemy import engine_from_config 4 | from sqlalchemy import pool 5 | 6 | from alembic import context 7 | 8 | # this is the Alembic Config object, which provides 9 | # access to the values within the .ini file in use. 10 | config = context.config 11 | 12 | # Interpret the config file for Python logging. 13 | # This line sets up loggers basically. 14 | fileConfig(config.config_file_name) 15 | 16 | # add your model's MetaData object here 17 | # for 'autogenerate' support 18 | from data_access.models import Base 19 | target_metadata = Base.metadata 20 | 21 | # other values from the config, defined by the needs of env.py, 22 | # can be acquired: 23 | # my_important_option = config.get_main_option("my_important_option") 24 | # ... etc. 25 | 26 | 27 | def run_migrations_offline(): 28 | """Run migrations in 'offline' mode. 29 | 30 | This configures the context with just a URL 31 | and not an Engine, though an Engine is acceptable 32 | here as well. By skipping the Engine creation 33 | we don't even need a DBAPI to be available. 34 | 35 | Calls to context.execute() here emit the given string to the 36 | script output. 37 | 38 | """ 39 | url = config.get_main_option("sqlalchemy.url") 40 | context.configure( 41 | url=url, 42 | target_metadata=target_metadata, 43 | literal_binds=True, 44 | dialect_opts={"paramstyle": "named"}, 45 | ) 46 | 47 | with context.begin_transaction(): 48 | context.run_migrations() 49 | 50 | 51 | def run_migrations_online(): 52 | """Run migrations in 'online' mode. 53 | 54 | In this scenario we need to create an Engine 55 | and associate a connection with the context. 56 | 57 | """ 58 | connectable = engine_from_config( 59 | config.get_section(config.config_ini_section), 60 | prefix="sqlalchemy.", 61 | poolclass=pool.NullPool, 62 | ) 63 | 64 | with connectable.connect() as connection: 65 | context.configure( 66 | connection=connection, target_metadata=target_metadata 67 | ) 68 | 69 | with context.begin_transaction(): 70 | context.run_migrations() 71 | 72 | 73 | if context.is_offline_mode(): 74 | run_migrations_offline() 75 | else: 76 | run_migrations_online() 77 | -------------------------------------------------------------------------------- /migrations/script.py.mako: -------------------------------------------------------------------------------- 1 | """${message} 2 | 3 | Revision ID: ${up_revision} 4 | Revises: ${down_revision | comma,n} 5 | Create Date: ${create_date} 6 | 7 | """ 8 | from alembic import op 9 | import sqlalchemy as sa 10 | ${imports if imports else ""} 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = ${repr(up_revision)} 14 | down_revision = ${repr(down_revision)} 15 | branch_labels = ${repr(branch_labels)} 16 | depends_on = ${repr(depends_on)} 17 | 18 | 19 | def upgrade(): 20 | ${upgrades if upgrades else "pass"} 21 | 22 | 23 | def downgrade(): 24 | ${downgrades if downgrades else "pass"} 25 | -------------------------------------------------------------------------------- /migrations/versions/7a4054a75244_add_user_and_task_models.py: -------------------------------------------------------------------------------- 1 | """Add user and Task models 2 | 3 | Revision ID: 7a4054a75244 4 | Revises: 5 | Create Date: 2022-02-02 18:28:02.046659 6 | 7 | """ 8 | from alembic import op 9 | import sqlalchemy as sa 10 | 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = '7a4054a75244' 14 | down_revision = None 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade(): 20 | # ### commands auto generated by Alembic - please adjust! ### 21 | op.create_table('user', 22 | sa.Column('id', sa.String(), nullable=False), 23 | sa.Column('created', sa.DateTime(), nullable=False), 24 | sa.Column('email', sa.String(), nullable=False), 25 | sa.PrimaryKeyConstraint('id') 26 | ) 27 | op.create_table('task', 28 | sa.Column('id', sa.String(), nullable=False), 29 | sa.Column('created', sa.DateTime(), nullable=False), 30 | sa.Column('updated', sa.DateTime(), nullable=False), 31 | sa.Column('priority', sa.String(), nullable=False), 32 | sa.Column('status', sa.String(), nullable=False), 33 | sa.Column('task', sa.String(), nullable=False), 34 | sa.Column('user_id', sa.String(), nullable=True), 35 | sa.ForeignKeyConstraint(['user_id'], ['user.id'], ), 36 | sa.PrimaryKeyConstraint('id') 37 | ) 38 | # ### end Alembic commands ### 39 | 40 | 41 | def downgrade(): 42 | # ### commands auto generated by Alembic - please adjust! ### 43 | op.drop_table('task') 44 | op.drop_table('user') 45 | # ### end Alembic commands ### 46 | -------------------------------------------------------------------------------- /oas.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.3 2 | 3 | info: 4 | title: TODO API 5 | description: API that allows you to manage a to-do list 6 | version: 1.0.0 7 | 8 | paths: 9 | /todo: 10 | get: 11 | summary: Returns a list of to-do items 12 | operationId: getTasks 13 | responses: 14 | '200': 15 | description: A JSON array of tasks 16 | content: 17 | application/json: 18 | schema: 19 | $ref: '#/components/schemas/ListTasksSchema' 20 | 21 | post: 22 | summary: Creates a task 23 | operationId: createTask 24 | requestBody: 25 | required: true 26 | content: 27 | application/json: 28 | schema: 29 | $ref: '#/components/schemas/CreateTaskSchema' 30 | responses: 31 | '201': 32 | description: A JSON representation of the created task 33 | content: 34 | application/json: 35 | schema: 36 | $ref: '#/components/schemas/GetTaskSchema' 37 | links: 38 | GetTask: 39 | operationId: getTask 40 | parameters: 41 | task_id: '$response.body#/id' 42 | description: > 43 | The `id` value returned in the response can be used as 44 | the `task_id` parameter in `GET /todo/{task_id} 45 | UpdateTask: 46 | operationId: updateTask 47 | parameters: 48 | task_id: '$response.body#/id' 49 | description: > 50 | The `id` value returned in the response can be used as 51 | the `task_id` parameter in `PUT /todo/{task_id} 52 | DeleteTask: 53 | operationId: deleteTask 54 | parameters: 55 | task_id: '$response.body#/id' 56 | description: > 57 | The `id` value returned in the response can be used as 58 | the `task_id` parameter in `DELETE /todo/{task_id} 59 | 60 | /todo/{task_id}: 61 | parameters: 62 | - in: path 63 | name: task_id 64 | required: true 65 | schema: 66 | type: string 67 | format: uuid 68 | example: d222e7a3-6afb-463a-9709-38eb70cc670d 69 | get: 70 | summary: Returns the details of a task 71 | operationId: getTask 72 | responses: 73 | '200': 74 | description: A JSON representation of a task 75 | content: 76 | application/json: 77 | schema: 78 | $ref: '#/components/schemas/GetTaskSchema' 79 | '404': 80 | $ref: '#/components/responses/NotFound' 81 | 82 | put: 83 | summary: Replaces an existing task 84 | operationId: updateTask 85 | requestBody: 86 | required: true 87 | content: 88 | application/json: 89 | schema: 90 | $ref: '#/components/schemas/CreateTaskSchema' 91 | responses: 92 | '200': 93 | description: A JSON representation of a task 94 | content: 95 | application/json: 96 | schema: 97 | $ref: '#/components/schemas/GetTaskSchema' 98 | '404': 99 | $ref: '#/components/responses/NotFound' 100 | 101 | delete: 102 | summary: Deletes an existing task 103 | operationId: deleteTask 104 | responses: 105 | '204': 106 | description: The resource was deleted successfully 107 | '404': 108 | $ref: '#/components/responses/NotFound' 109 | 110 | components: 111 | responses: 112 | NotFound: 113 | description: The specified resource was not found. 114 | content: 115 | application/json: 116 | schema: 117 | $ref: '#/components/schemas/Error' 118 | 119 | securitySchemes: 120 | bearerAuth: 121 | type: http 122 | scheme: bearer 123 | bearerFormat: JWT 124 | 125 | schemas: 126 | Error: 127 | type: object 128 | properties: 129 | detail: 130 | type: string 131 | 132 | CreateTaskSchema: 133 | type: object 134 | required: 135 | - task 136 | additionalProperties: false 137 | properties: 138 | priority: 139 | type: string 140 | enum: 141 | - low 142 | - medium 143 | - high 144 | default: low 145 | status: 146 | type: string 147 | enum: 148 | - pending 149 | - progress 150 | - completed 151 | default: pending 152 | task: 153 | type: string 154 | 155 | GetTaskSchema: 156 | type: object 157 | required: 158 | - created 159 | - id 160 | - priority 161 | - status 162 | - task 163 | additionalProperties: false 164 | properties: 165 | id: 166 | type: string 167 | format: uuid 168 | created: 169 | type: string 170 | format: date-time 171 | priority: 172 | type: string 173 | enum: 174 | - low 175 | - medium 176 | - high 177 | default: low 178 | status: 179 | type: string 180 | enum: 181 | - pending 182 | - progress 183 | - completed 184 | task: 185 | type: string 186 | ListTasksSchema: 187 | type: object 188 | required: 189 | - tasks 190 | properties: 191 | tasks: 192 | type: array 193 | items: 194 | $ref: '#/components/schemas/GetTaskSchema' 195 | 196 | security: 197 | - bearerAuth: 198 | - getTasks 199 | - createTask 200 | - getTask 201 | - updateTask 202 | - deleteTask 203 | -------------------------------------------------------------------------------- /private_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQD3alnZqD7W5ZEE 3 | rkmwKpTha2P868rgbZHTh7jiJqm28dkp57RxgFCBf92OwhhC8iC46WjTXo14Juc0 4 | c/Cu6YLf7et2ghdCiXU0nfmrI2vThQ+LmjGXvFBJ/JWKRzLt/xjrPikwFjfJi2Vl 5 | eaR6FTEqsaggXpg+8VhIKzIP0ZgB0QeqfajTkNXiHOaXnpInieGxppRS5Yp1nSD+ 6 | c7W37kTNyicB/kVy1R3YTxPuD2nBUoSjHUwQNnXc0t9e2I1BvcydXOhzADi2ioRf 7 | Wentm5zTkgt15s+XmWcvEBuc1UeiTVi6xdlRo0yE06LLf69SSyfbbqsKKLFUlj1T 8 | u6dcKQxlAgMBAAECggEAWYV4p0GyIw2DcF8juINfxUSXNC+ZA6WBqzkjk2iL5e8S 9 | NZBqANt9xa2fXAUsxCRZ5K5HyJsgswXYiGkfABrryNyMYx/lDKUx7GzwppS1ch5m 10 | JowPP6jaoDqtXRAwBF9WA+BFBOo1G069zH68HZRHavxHKhcwHS40VECU55Zd2uGy 11 | McnrCSTbhhuvaAVh0EXLSxWAijubADddLszwtDxUjWKI/z92lIwz0KHNv/EunFYX 12 | fYFnGusJUEKXjJNstgkYB/1NWfxsQEeZ6HJTSeI8DGSZW/MdICZJaFlaj+/LRm0d 13 | KcpWxlebaQPy8s1FJirEW2Wmmz2VHI0vikzm3/ENAQKBgQD+zZdLTnTMSgkMMEIN 14 | 30GzHmoiZgpp7RVwVsFQsG8+QOxQZCqH8hqjbE9uKAEoOJLF+s/zbIagqziksNtq 15 | Cz/IPT0ciBwLs9B0Fa954mVeqStji2zt3TNNqY1qcEJkwjvPUENURNoiT6oe13pf 16 | 4ver/PkQo9v042bQTlvT8KOOJQKBgQD4k+BHROtGznFZhu41Fp1ojLp9WZmjL4PX 17 | q0/mQLEZQGj1kgAy9e37G/O/Gm+mQMmis2P6dueMF6lH07spWcZhYU7iTgrEo/EL 18 | YAr57NDvpCjSCPrWG+mbkj3F2w0UyuIM9qexueyWpPhUj/7gZUw5NA8WJFBhmuhd 19 | /PAkSvORQQKBgGVnqMidproO1N727bLboSgJ+K9L8OULJ7cXr8PPE9awu9uaoZqM 20 | 7bEQT+RFI4DAUxlbohr8m++hdN+GSyw+4dltFb8fJBo8K7+nSbi2MyWjKdNqD6Xy 21 | nJJR4if0GVhEPM1a4hDNfgqdrdSsaNV0XKEkAnNu4wDo52gLZ1xHrq/JAoGBAKyC 22 | o8GSON34431IQQSi3zbxg3L+vbscfJkuENMwzjdCFhVm77BuMGx2p6BWjmmIyOab 23 | LKVj46m7ugVZEajO3vgx+fbgRmTVibFlQ/jSuuW0vYeWJ85zrJoE0c4ACYIGkv6A 24 | Jz0WVPTvJFA7Zp0Ab/e7A0VQimBSizS/F0F4qrSBAoGBANQPp0eMPwxIQ8RLpSX3 25 | pnZB2D87Bk08zyK8iPEwLP9LxeJCO9r9mEWkM1Upere6AhMfWvN+sM6DZo9JGvX6 26 | 1hIUhB9NXNt+TUF84sDkhJU8XohP6sNAnPa5HI5O3lDnp1DpjH+OYkWKMPsZADQp 27 | ikU1RIkJ50WjLVW+tJknJudi 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /public_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICqjCCAZICCQChfFrIswTT2TANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxq 3 | d3QtdHVyb3JpYWwwHhcNMjIwMTA2MTcxNzQzWhcNMjIwMjA1MTcxNzQzWjAXMRUw 4 | EwYDVQQDDAxqd3QtdHVyb3JpYWwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK 5 | AoIBAQD3alnZqD7W5ZEErkmwKpTha2P868rgbZHTh7jiJqm28dkp57RxgFCBf92O 6 | whhC8iC46WjTXo14Juc0c/Cu6YLf7et2ghdCiXU0nfmrI2vThQ+LmjGXvFBJ/JWK 7 | RzLt/xjrPikwFjfJi2VleaR6FTEqsaggXpg+8VhIKzIP0ZgB0QeqfajTkNXiHOaX 8 | npInieGxppRS5Yp1nSD+c7W37kTNyicB/kVy1R3YTxPuD2nBUoSjHUwQNnXc0t9e 9 | 2I1BvcydXOhzADi2ioRfWentm5zTkgt15s+XmWcvEBuc1UeiTVi6xdlRo0yE06LL 10 | f69SSyfbbqsKKLFUlj1Tu6dcKQxlAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAFBh 11 | UgSTz4i/LE9Gqn2py5UFMTBjugnVcIHR0Aq2izyKAw4d/jPbN9OEhTRJQT9pH/db 12 | Q87q0f0GmJO6YsZ/3zMz43/vfCDfM9hBERt//Cf6CsnelqurIExMgif89WJqHASO 13 | IGbRCiVJdHX7RwxAXfOj0kUePkh0QHWDGy9HjjNHVi5v/380jNjSmH2i/rM+Og6n 14 | dYXQ0QPoT0JvcQ2XMPZIpbnYVi3l1mPZHrt4g3MxNNH138GUHevU+9b5TdJp1MyL 15 | WpPwAPSB6xI+cN45VAx/dWauiptCklACrZuwq0XLGAL/niGO4+Gzpz0nRzNZErmR 16 | 5nFjePUzKOaZQ4gUYqI= 17 | -----END CERTIFICATE----- 18 | --------------------------------------------------------------------------------