commit
ac52800e3a
1
Pipfile
1
Pipfile
|
@ -27,6 +27,7 @@ asyncio = "*"
|
|||
fastapi = "*"
|
||||
uvicorn = {extras = ["standard"], version = "*"}
|
||||
sse-starlette = "*"
|
||||
jinja2 = "3.0.1"
|
||||
|
||||
[dev-packages]
|
||||
black = "==20.8b1"
|
||||
|
|
182
Pipfile.lock
generated
182
Pipfile.lock
generated
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "e26f678c4b89a86400e0a62396d06e360bfdf1e0f922d474ded200ee1ffde5c4"
|
||||
"sha256": "97473b3cb250742ebabd8c3a71d4e4c42f8feeaff49dd4542cae24429f096535"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
|
@ -26,11 +26,11 @@
|
|||
},
|
||||
"anyio": {
|
||||
"hashes": [
|
||||
"sha256:929a6852074397afe1d989002aa96d457e3e1e5441357c60d03e7eea0e65e1b0",
|
||||
"sha256:ae57a67583e5ff8b4af47666ff5651c3732d45fd26c929253748e796af860374"
|
||||
"sha256:85913b4e2fec030e8c72a8f9f98092eeb9e25847a6e00d567751b77e34f856fe",
|
||||
"sha256:d7c604dd491eca70e19c78664d685d5e4337612d574419d503e76f5d7d1590bd"
|
||||
],
|
||||
"markers": "python_full_version >= '3.6.2'",
|
||||
"version": "==3.3.0"
|
||||
"version": "==3.3.1"
|
||||
},
|
||||
"asgiref": {
|
||||
"hashes": [
|
||||
|
@ -91,11 +91,11 @@
|
|||
},
|
||||
"charset-normalizer": {
|
||||
"hashes": [
|
||||
"sha256:0c8911edd15d19223366a194a513099a302055a962bca2cec0f54b8b63175d8b",
|
||||
"sha256:f23667ebe1084be45f6ae0538e4a5a865206544097e4e8bbcacf42cd02a348f3"
|
||||
"sha256:5d209c0a931f215cee683b6445e2d77677e7e75e159f78def0db09d68fafcaa6",
|
||||
"sha256:5ec46d183433dcbd0ab716f2d7f29d8dee50505b3fdb40c6b985c7c4f5a3591f"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==2.0.4"
|
||||
"version": "==2.0.6"
|
||||
},
|
||||
"click": {
|
||||
"hashes": [
|
||||
|
@ -115,10 +115,10 @@
|
|||
},
|
||||
"embit": {
|
||||
"hashes": [
|
||||
"sha256:19f69929caf0d2fcfd4b708dd873384dfc36267944d02d5e6dfebc835f294e1b"
|
||||
"sha256:992332bd89af6e2d027e26fe437eb14aa33997db08c882c49064d49c3e6f4ab9"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.4.6"
|
||||
"version": "==0.4.9"
|
||||
},
|
||||
"environs": {
|
||||
"hashes": [
|
||||
|
@ -146,11 +146,11 @@
|
|||
},
|
||||
"httpcore": {
|
||||
"hashes": [
|
||||
"sha256:b0d16f0012ec88d8cc848f5a55f8a03158405f4bca02ee49bc4ca2c1fda49f3e",
|
||||
"sha256:db4c0dcb8323494d01b8c6d812d80091a31e520033e7b0120883d6f52da649ff"
|
||||
"sha256:036f960468759e633574d7c121afba48af6419615d36ab8ede979f1ad6276fa3",
|
||||
"sha256:369aa481b014cf046f7067fddd67d00560f2f00426e79569d99cb11245134af0"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==0.13.6"
|
||||
"version": "==0.13.7"
|
||||
},
|
||||
"httptools": {
|
||||
"hashes": [
|
||||
|
@ -195,6 +195,14 @@
|
|||
"markers": "python_version < '3.8'",
|
||||
"version": "==4.8.1"
|
||||
},
|
||||
"jinja2": {
|
||||
"hashes": [
|
||||
"sha256:1f06f2da51e7b56b8f238affdd6b4e2c61e39598a378cc49345bc1bd42a978a4",
|
||||
"sha256:703f484b47a6af502e743c9122595cc812b0271f661722403114f71a79d0f5a4"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.0.1"
|
||||
},
|
||||
"lnurl": {
|
||||
"hashes": [
|
||||
"sha256:579982fd8c4d25bc84c61c74ec45cb7999fa1fa2426f5d5aeb0160ba333b9c92",
|
||||
|
@ -203,6 +211,66 @@
|
|||
"index": "pypi",
|
||||
"version": "==0.3.6"
|
||||
},
|
||||
"markupsafe": {
|
||||
"hashes": [
|
||||
"sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298",
|
||||
"sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64",
|
||||
"sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b",
|
||||
"sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567",
|
||||
"sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff",
|
||||
"sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724",
|
||||
"sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74",
|
||||
"sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646",
|
||||
"sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35",
|
||||
"sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6",
|
||||
"sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6",
|
||||
"sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad",
|
||||
"sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26",
|
||||
"sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38",
|
||||
"sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac",
|
||||
"sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7",
|
||||
"sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6",
|
||||
"sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75",
|
||||
"sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f",
|
||||
"sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135",
|
||||
"sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8",
|
||||
"sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a",
|
||||
"sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a",
|
||||
"sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9",
|
||||
"sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864",
|
||||
"sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914",
|
||||
"sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18",
|
||||
"sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8",
|
||||
"sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2",
|
||||
"sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d",
|
||||
"sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b",
|
||||
"sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b",
|
||||
"sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f",
|
||||
"sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb",
|
||||
"sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833",
|
||||
"sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28",
|
||||
"sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415",
|
||||
"sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902",
|
||||
"sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d",
|
||||
"sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9",
|
||||
"sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d",
|
||||
"sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145",
|
||||
"sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066",
|
||||
"sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c",
|
||||
"sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1",
|
||||
"sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f",
|
||||
"sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53",
|
||||
"sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134",
|
||||
"sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85",
|
||||
"sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5",
|
||||
"sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94",
|
||||
"sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509",
|
||||
"sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51",
|
||||
"sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==2.0.1"
|
||||
},
|
||||
"marshmallow": {
|
||||
"hashes": [
|
||||
"sha256:c67929438fd73a2be92128caa0325b1b5ed8b626d91a094d2f7f2771bf1f1c0e",
|
||||
|
@ -457,12 +525,12 @@
|
|||
},
|
||||
"typing-extensions": {
|
||||
"hashes": [
|
||||
"sha256:045dd532231acfa03628df5e0c66dba64e2cc8fc8b844538d4ad6d5dd6cb82dc",
|
||||
"sha256:83af6730a045fda60f46510f7f1f094776d90321caa4d97d20ef38871bef4bd3",
|
||||
"sha256:8bbffbd37fbeb9747a0241fdfde5ae99d4531ad1d1a41ccaea62100e15a5814c"
|
||||
"sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e",
|
||||
"sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7",
|
||||
"sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.10.0.1"
|
||||
"version": "==3.10.0.2"
|
||||
},
|
||||
"uvicorn": {
|
||||
"extras": [
|
||||
|
@ -505,41 +573,33 @@
|
|||
},
|
||||
"websockets": {
|
||||
"hashes": [
|
||||
"sha256:0dd4eb8e0bbf365d6f652711ce21b8fd2b596f873d32aabb0fbb53ec604418cc",
|
||||
"sha256:1d0971cc7251aeff955aa742ec541ee8aaea4bb2ebf0245748fbec62f744a37e",
|
||||
"sha256:1d6b4fddb12ab9adf87b843cd4316c4bd602db8d5efd2fb83147f0458fe85135",
|
||||
"sha256:230a3506df6b5f446fed2398e58dcaafdff12d67fe1397dff196411a9e820d02",
|
||||
"sha256:276d2339ebf0df4f45df453923ebd2270b87900eda5dfd4a6b0cfa15f82111c3",
|
||||
"sha256:2cf04601633a4ec176b9cc3d3e73789c037641001dbfaf7c411f89cd3e04fcaf",
|
||||
"sha256:3ddff38894c7857c476feb3538dd847514379d6dc844961dc99f04b0384b1b1b",
|
||||
"sha256:48c222feb3ced18f3dc61168ca18952a22fb88e5eb8902d2bf1b50faefdc34a2",
|
||||
"sha256:51d04df04ed9d08077d10ccbe21e6805791b78eac49d16d30a1f1fe2e44ba0af",
|
||||
"sha256:597c28f3aa7a09e8c070a86b03107094ee5cdafcc0d55f2f2eac92faac8dc67d",
|
||||
"sha256:5c8f0d82ea2468282e08b0cf5307f3ad022290ed50c45d5cb7767957ca782880",
|
||||
"sha256:7189e51955f9268b2bdd6cc537e0faa06f8fffda7fb386e5922c6391de51b077",
|
||||
"sha256:7df3596838b2a0c07c6f6d67752c53859a54993d4f062689fdf547cb56d0f84f",
|
||||
"sha256:826ccf85d4514609219725ba4a7abd569228c2c9f1968e8be05be366f68291ec",
|
||||
"sha256:836d14eb53b500fd92bd5db2fc5894f7c72b634f9c2a28f546f75967503d8e25",
|
||||
"sha256:85db8090ba94e22d964498a47fdd933b8875a1add6ebc514c7ac8703eb97bbf0",
|
||||
"sha256:85e701a6c316b7067f1e8675c638036a796fe5116783a4c932e7eb8e305a3ffe",
|
||||
"sha256:900589e19200be76dd7cbaa95e9771605b5ce3f62512d039fb3bc5da9014912a",
|
||||
"sha256:9147868bb0cc01e6846606cd65cbf9c58598f187b96d14dd1ca17338b08793bb",
|
||||
"sha256:9e7fdc775fe7403dbd8bc883ba59576a6232eac96dacb56512daacf7af5d618d",
|
||||
"sha256:ab5ee15d3462198c794c49ccd31773d8a2b8c17d622aa184f669d2b98c2f0857",
|
||||
"sha256:ad893d889bc700a5835e0a95a3e4f2c39e91577ab232a3dc03c262a0f8fc4b5c",
|
||||
"sha256:b2e71c4670ebe1067fa8632f0d081e47254ee2d3d409de54168b43b0ba9147e0",
|
||||
"sha256:b43b13e5622c5a53ab12f3272e6f42f1ce37cd5b6684b2676cb365403295cd40",
|
||||
"sha256:b4ad84b156cf50529b8ac5cc1638c2cf8680490e3fccb6121316c8c02620a2e4",
|
||||
"sha256:be5fd35e99970518547edc906efab29afd392319f020c3c58b0e1a158e16ed20",
|
||||
"sha256:caa68c95bc1776d3521f81eeb4d5b9438be92514ec2a79fececda814099c8314",
|
||||
"sha256:d144b350045c53c8ff09aa1cfa955012dd32f00c7e0862c199edcabb1a8b32da",
|
||||
"sha256:d2c2d9b24d3c65b5a02cac12cbb4e4194e590314519ed49db2f67ef561c3cf58",
|
||||
"sha256:e9e5fd6dbdf95d99bc03732ded1fc8ef22ebbc05999ac7e0c7bf57fe6e4e5ae2",
|
||||
"sha256:ebf459a1c069f9866d8569439c06193c586e72c9330db1390af7c6a0a32c4afd",
|
||||
"sha256:f31722f1c033c198aa4a39a01905951c00bd1c74f922e8afc1b1c62adbcdd56a",
|
||||
"sha256:f68c352a68e5fdf1e97288d5cec9296664c590c25932a8476224124aaf90dbcd"
|
||||
"sha256:01db0ecd1a0ca6702d02a5ed40413e18b7d22f94afb3bbe0d323bac86c42c1c8",
|
||||
"sha256:085bb8a6e780d30eaa1ba48ac7f3a6707f925edea787cfb761ce5a39e77ac09b",
|
||||
"sha256:1ac35426fe3e7d3d0fac3d63c8965c76ed67a8fd713937be072bf0ce22808539",
|
||||
"sha256:1f6b814cff6aadc4288297cb3a248614829c6e4ff5556593c44a115e9dd49939",
|
||||
"sha256:2a43072e434c041a99f2e1eb9b692df0232a38c37c61d00e9f24db79474329e4",
|
||||
"sha256:5b2600e01c7ca6f840c42c747ffbe0254f319594ed108db847eb3d75f4aacb80",
|
||||
"sha256:62160772314920397f9d219147f958b33fa27a12c662d4455c9ccbba9a07e474",
|
||||
"sha256:706e200fc7f03bed99ad0574cd1ea8b0951477dd18cc978ccb190683c69dba76",
|
||||
"sha256:71358c7816e2762f3e4af3adf0040f268e219f5a38cb3487a9d0fc2e554fef6a",
|
||||
"sha256:7d2e12e4f901f1bc062dfdf91831712c4106ed18a9a4cdb65e2e5f502124ca37",
|
||||
"sha256:7f79f02c7f9a8320aff7d3321cd1c7e3a7dbc15d922ac996cca827301ee75238",
|
||||
"sha256:82b17524b1ce6ae7f7dd93e4d18e9b9474071e28b65dbf1dfe9b5767778db379",
|
||||
"sha256:82bd921885231f4a30d9bc550552495b3fc36b1235add6d374e7c65c3babd805",
|
||||
"sha256:8bbf8660c3f833ddc8b1afab90213f2e672a9ddac6eecb3cde968e6b2807c1c7",
|
||||
"sha256:9a4d889162bd48588e80950e07fa5e039eee9deb76a58092e8c3ece96d7ef537",
|
||||
"sha256:b4ade7569b6fd17912452f9c3757d96f8e4044016b6d22b3b8391e641ca50456",
|
||||
"sha256:b8176deb6be540a46695960a765a77c28ac8b2e3ef2ec95d50a4f5df901edb1c",
|
||||
"sha256:c4fc9a1d242317892590abe5b61a9127f1a61740477bfb121743f290b8054002",
|
||||
"sha256:c5880442f5fc268f1ef6d37b2c152c114deccca73f48e3a8c48004d2f16f4567",
|
||||
"sha256:cd8c6f2ec24aedace251017bc7a414525171d4e6578f914acab9349362def4da",
|
||||
"sha256:d67646ddd17a86117ae21c27005d83c1895c0cef5d7be548b7549646372f868a",
|
||||
"sha256:e42a1f1e03437b017af341e9bbfdc09252cd48ef32a8c3c3ead769eab3b17368",
|
||||
"sha256:eb282127e9c136f860c6068a4fba5756eb25e755baffb5940b6f1eae071928b2",
|
||||
"sha256:fe83b3ec9ef34063d86dfe1029160a85f24a5a94271036e5714a57acfdd089a1",
|
||||
"sha256:ff59c6bdb87b31f7e2d596f09353d5a38c8c8ff571b0e2238e8ee2d55ad68465"
|
||||
],
|
||||
"version": "==9.1"
|
||||
"version": "==10.0"
|
||||
},
|
||||
"zipp": {
|
||||
"hashes": [
|
||||
|
@ -707,11 +767,11 @@
|
|||
},
|
||||
"pluggy": {
|
||||
"hashes": [
|
||||
"sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0",
|
||||
"sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"
|
||||
"sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159",
|
||||
"sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==0.13.1"
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==1.0.0"
|
||||
},
|
||||
"py": {
|
||||
"hashes": [
|
||||
|
@ -731,11 +791,11 @@
|
|||
},
|
||||
"pytest": {
|
||||
"hashes": [
|
||||
"sha256:50bcad0a0b9c5a72c8e4e7c9855a3ad496ca6a881a3641b4260605450772c54b",
|
||||
"sha256:91ef2131a9bd6be8f76f1f08eac5c5317221d6ad1e143ae03894b862e8976890"
|
||||
"sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89",
|
||||
"sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==6.2.4"
|
||||
"version": "==6.2.5"
|
||||
},
|
||||
"pytest-cov": {
|
||||
"hashes": [
|
||||
|
@ -837,12 +897,12 @@
|
|||
},
|
||||
"typing-extensions": {
|
||||
"hashes": [
|
||||
"sha256:045dd532231acfa03628df5e0c66dba64e2cc8fc8b844538d4ad6d5dd6cb82dc",
|
||||
"sha256:83af6730a045fda60f46510f7f1f094776d90321caa4d97d20ef38871bef4bd3",
|
||||
"sha256:8bbffbd37fbeb9747a0241fdfde5ae99d4531ad1d1a41ccaea62100e15a5814c"
|
||||
"sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e",
|
||||
"sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7",
|
||||
"sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.10.0.1"
|
||||
"version": "==3.10.0.2"
|
||||
},
|
||||
"zipp": {
|
||||
"hashes": [
|
||||
|
|
|
@ -65,7 +65,7 @@ def create_app(config_object="lnbits.settings") -> FastAPI:
|
|||
register_routes(app)
|
||||
# register_commands(app)
|
||||
register_async_tasks(app)
|
||||
# register_exception_handlers(app)
|
||||
register_exception_handlers(app)
|
||||
|
||||
return app
|
||||
|
||||
|
@ -96,6 +96,11 @@ def register_routes(app: FastAPI) -> None:
|
|||
ext_module = importlib.import_module(f"lnbits.extensions.{ext.code}")
|
||||
ext_route = getattr(ext_module, f"{ext.code}_ext")
|
||||
|
||||
if hasattr(ext_module, f"{ext.code}_start"):
|
||||
ext_start_func = getattr(ext_module, f"{ext.code}_start")
|
||||
ext_start_func()
|
||||
|
||||
if hasattr(ext_module, f"{ext.code}_static_files"):
|
||||
ext_statics = getattr(ext_module, f"{ext.code}_static_files")
|
||||
for s in ext_statics:
|
||||
app.mount(s["path"], s["app"], s["name"])
|
||||
|
@ -145,11 +150,11 @@ def register_async_tasks(app):
|
|||
async def stop_listeners():
|
||||
pass
|
||||
|
||||
def register_exception_handlers(app):
|
||||
@app.errorhandler(Exception)
|
||||
def register_exception_handlers(app: FastAPI):
|
||||
@app.exception_handler(Exception)
|
||||
async def basic_error(request: Request, err):
|
||||
print("handled error", traceback.format_exc())
|
||||
etype, value, tb = sys.exc_info()
|
||||
etype, _, tb = sys.exc_info()
|
||||
traceback.print_exception(etype, err, tb)
|
||||
exc = traceback.format_exc()
|
||||
return template_renderer().TemplateResponse("error.html", {"request": request, "err": err})
|
||||
|
|
|
@ -52,6 +52,7 @@ async def api_payments(wallet: WalletTypeInfo = Depends(get_key_type)):
|
|||
|
||||
|
||||
class CreateInvoiceData(BaseModel):
|
||||
out: Optional[bool] = True
|
||||
amount: int = Query(None, ge=1)
|
||||
memo: str = None
|
||||
unit: Optional[str] = None
|
||||
|
@ -60,6 +61,7 @@ class CreateInvoiceData(BaseModel):
|
|||
lnurl_balance_check: Optional[str] = None
|
||||
extra: Optional[dict] = None
|
||||
webhook: Optional[str] = None
|
||||
bolt11: Optional[str] = None
|
||||
|
||||
async def api_payments_create_invoice(data: CreateInvoiceData, wallet: Wallet):
|
||||
if "description_hash" in data:
|
||||
|
@ -169,17 +171,16 @@ async def api_payments_pay_invoice(bolt11: str, wallet: Wallet):
|
|||
@core_app.post("/api/v1/payments", deprecated=True,
|
||||
description="DEPRECATED. Use /api/v2/TBD and /api/v2/TBD instead",
|
||||
status_code=HTTPStatus.CREATED)
|
||||
async def api_payments_create(wallet: WalletTypeInfo = Depends(get_key_type), out: bool = True,
|
||||
invoiceData: Optional[CreateInvoiceData] = Body(None),
|
||||
bolt11: Optional[str] = Body(None)):
|
||||
async def api_payments_create(wallet: WalletTypeInfo = Depends(get_key_type),
|
||||
invoiceData: CreateInvoiceData = Body(...)):
|
||||
|
||||
if wallet.wallet_type < 0 or wallet.wallet_type > 2:
|
||||
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail="Key is invalid")
|
||||
|
||||
if out is True and wallet.wallet_type == 0:
|
||||
if not bolt11:
|
||||
if invoiceData.out is True and wallet.wallet_type == 0:
|
||||
if not invoiceData.bolt11:
|
||||
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail="BOLT11 string is invalid or not given")
|
||||
return await api_payments_pay_invoice(bolt11, wallet.wallet) # admin key
|
||||
return await api_payments_pay_invoice(invoiceData.bolt11, wallet.wallet) # admin key
|
||||
return await api_payments_create_invoice(invoiceData, wallet.wallet) # invoice key
|
||||
|
||||
class CreateLNURLData(BaseModel):
|
||||
|
@ -189,8 +190,9 @@ class CreateLNURLData(BaseModel):
|
|||
comment: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
|
||||
@core_app.post("/api/v1/payments/lnurl", dependencies=[Depends(WalletAdminKeyChecker())])
|
||||
async def api_payments_pay_lnurl(data: CreateLNURLData):
|
||||
@core_app.post("/api/v1/payments/lnurl")
|
||||
async def api_payments_pay_lnurl(data: CreateLNURLData,
|
||||
wallet: WalletTypeInfo = Depends(get_key_type)):
|
||||
domain = urlparse(data.callback).netloc
|
||||
|
||||
async with httpx.AsyncClient() as client:
|
||||
|
@ -220,13 +222,13 @@ async def api_payments_pay_lnurl(data: CreateLNURLData):
|
|||
if invoice.amount_msat != data.amount:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.BAD_REQUEST,
|
||||
detail=f"{domain} returned an invalid invoice. Expected {g().data['amount']} msat, got {invoice.amount_msat}."
|
||||
detail=f"{domain} returned an invalid invoice. Expected {data['amount']} msat, got {invoice.amount_msat}."
|
||||
)
|
||||
|
||||
if invoice.description_hash != g().data["description_hash"]:
|
||||
if invoice.description_hash != data.description_hash:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.BAD_REQUEST,
|
||||
detail=f"{domain} returned an invalid invoice. Expected description_hash == {g().data['description_hash']}, got {invoice.description_hash}."
|
||||
detail=f"{domain} returned an invalid invoice. Expected description_hash == {data['description_hash']}, got {invoice.description_hash}."
|
||||
)
|
||||
|
||||
|
||||
|
@ -238,7 +240,7 @@ async def api_payments_pay_lnurl(data: CreateLNURLData):
|
|||
extra["comment"] = data.comment
|
||||
|
||||
payment_hash = await pay_invoice(
|
||||
wallet_id=g().wallet.id,
|
||||
wallet_id=wallet.wallet.id,
|
||||
payment_request=params["pr"],
|
||||
description=data.description,
|
||||
extra=extra,
|
||||
|
|
|
@ -96,6 +96,8 @@ async def get_key_type(r: Request,
|
|||
await checker.__call__(r)
|
||||
return WalletTypeInfo(0, checker.wallet)
|
||||
except HTTPException as e:
|
||||
if e.status_code == HTTPStatus.BAD_REQUEST:
|
||||
raise
|
||||
if e.status_code == HTTPStatus.UNAUTHORIZED:
|
||||
pass
|
||||
except:
|
||||
|
@ -106,6 +108,8 @@ async def get_key_type(r: Request,
|
|||
await checker.__call__(r)
|
||||
return WalletTypeInfo(1, checker.wallet)
|
||||
except HTTPException as e:
|
||||
if e.status_code == HTTPStatus.BAD_REQUEST:
|
||||
raise
|
||||
if e.status_code == HTTPStatus.UNAUTHORIZED:
|
||||
return WalletTypeInfo(2, None)
|
||||
except:
|
||||
|
|
|
@ -1,17 +1,33 @@
|
|||
from quart import Blueprint
|
||||
import asyncio
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
from lnbits.db import Database
|
||||
from lnbits.helpers import template_renderer
|
||||
from lnbits.tasks import catch_everything_and_restart
|
||||
|
||||
db = Database("ext_lnticket")
|
||||
|
||||
lnticket_ext: Blueprint = Blueprint(
|
||||
"lnticket", __name__, static_folder="static", template_folder="templates"
|
||||
lnticket_ext: APIRouter = APIRouter(
|
||||
prefix="/lnticket",
|
||||
tags=["LNTicket"]
|
||||
# "lnticket", __name__, static_folder="static", template_folder="templates"
|
||||
)
|
||||
|
||||
def lnticket_renderer():
|
||||
return template_renderer(
|
||||
[
|
||||
"lnbits/extensions/lnticket/templates",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
from .views_api import * # noqa
|
||||
from .views import * # noqa
|
||||
from .tasks import register_listeners
|
||||
from .tasks import wait_for_paid_invoices
|
||||
|
||||
from lnbits.tasks import record_async
|
||||
|
||||
lnticket_ext.record(record_async(register_listeners))
|
||||
def lnticket_start():
|
||||
loop = asyncio.get_event_loop()
|
||||
loop.create_task(catch_everything_and_restart(wait_for_paid_invoices))
|
||||
|
||||
|
|
|
@ -1,27 +1,24 @@
|
|||
from lnbits.core.models import Wallet
|
||||
from typing import List, Optional, Union
|
||||
|
||||
from lnbits.helpers import urlsafe_short_hash
|
||||
|
||||
from . import db
|
||||
from .models import Tickets, Forms
|
||||
from .models import CreateFormData, CreateTicketData, Tickets, Forms
|
||||
import httpx
|
||||
|
||||
|
||||
async def create_ticket(
|
||||
payment_hash: str,
|
||||
wallet: str,
|
||||
form: str,
|
||||
name: str,
|
||||
email: str,
|
||||
ltext: str,
|
||||
sats: int,
|
||||
data: CreateTicketData
|
||||
) -> Tickets:
|
||||
await db.execute(
|
||||
"""
|
||||
INSERT INTO lnticket.ticket (id, form, email, ltext, name, wallet, sats, paid)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(payment_hash, form, email, ltext, name, wallet, sats, False),
|
||||
(payment_hash, data.form, data.email, data.ltext, data.name, wallet, data.sats, False),
|
||||
)
|
||||
|
||||
ticket = await get_ticket(payment_hash)
|
||||
|
@ -103,13 +100,8 @@ async def delete_ticket(ticket_id: str) -> None:
|
|||
|
||||
|
||||
async def create_form(
|
||||
*,
|
||||
wallet: str,
|
||||
name: str,
|
||||
webhook: Optional[str] = None,
|
||||
description: str,
|
||||
amount: int,
|
||||
flatrate: int,
|
||||
data: CreateFormData,
|
||||
wallet: Wallet,
|
||||
) -> Forms:
|
||||
form_id = urlsafe_short_hash()
|
||||
await db.execute(
|
||||
|
@ -117,7 +109,7 @@ async def create_form(
|
|||
INSERT INTO lnticket.form2 (id, wallet, name, webhook, description, flatrate, amount, amountmade)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(form_id, wallet, name, webhook, description, flatrate, amount, 0),
|
||||
(form_id, wallet.id, wallet.name, data.webhook, data.description, data.flatrate, data.amount, 0),
|
||||
)
|
||||
|
||||
form = await get_form(form_id)
|
||||
|
|
|
@ -1,10 +1,26 @@
|
|||
from typing import Optional
|
||||
from fastapi.param_functions import Query
|
||||
from pydantic import BaseModel
|
||||
|
||||
class CreateFormData(BaseModel):
|
||||
name: str = Query(...)
|
||||
webhook: str = Query(None)
|
||||
description: str = Query(..., min_length=0)
|
||||
amount: int = Query(..., ge=0)
|
||||
flatrate: int = Query(...)
|
||||
|
||||
class CreateTicketData(BaseModel):
|
||||
form: str = Query(...)
|
||||
name: str = Query(...)
|
||||
email: str = Query("")
|
||||
ltext: str = Query(...)
|
||||
sats: int = Query(..., ge=0)
|
||||
|
||||
class Forms(BaseModel):
|
||||
id: str
|
||||
wallet: str
|
||||
name: str
|
||||
webhook: str
|
||||
webhook: Optional[str]
|
||||
description: str
|
||||
amount: int
|
||||
flatrate: int
|
||||
|
|
|
@ -1,23 +1,17 @@
|
|||
import json
|
||||
import trio # type: ignore
|
||||
import asyncio
|
||||
|
||||
from lnbits.core.models import Payment
|
||||
from lnbits.core.crud import create_payment
|
||||
from lnbits.core import db as core_db
|
||||
from lnbits.tasks import register_invoice_listener, internal_invoice_paid
|
||||
from lnbits.helpers import urlsafe_short_hash
|
||||
from lnbits.tasks import register_invoice_listener
|
||||
|
||||
from .crud import get_ticket, set_ticket_paid
|
||||
|
||||
|
||||
async def register_listeners():
|
||||
invoice_paid_chan_send, invoice_paid_chan_recv = trio.open_memory_channel(2)
|
||||
register_invoice_listener(invoice_paid_chan_send)
|
||||
await wait_for_paid_invoices(invoice_paid_chan_recv)
|
||||
async def wait_for_paid_invoices():
|
||||
invoice_queue = asyncio.Queue()
|
||||
register_invoice_listener(invoice_queue)
|
||||
|
||||
|
||||
async def wait_for_paid_invoices(invoice_paid_chan: trio.MemoryReceiveChannel):
|
||||
async for payment in invoice_paid_chan:
|
||||
while True:
|
||||
payment = await invoice_queue.get()
|
||||
await on_invoice_paid(payment)
|
||||
|
||||
|
||||
|
|
|
@ -337,7 +337,7 @@
|
|||
LNbits.api
|
||||
.request(
|
||||
'GET',
|
||||
'/lnticket/api/v1/tickets?all_wallets',
|
||||
'/lnticket/api/v1/tickets?all_wallets=true',
|
||||
this.g.user.wallets[0].inkey
|
||||
)
|
||||
.then(function (response) {
|
||||
|
@ -382,7 +382,7 @@
|
|||
LNbits.api
|
||||
.request(
|
||||
'GET',
|
||||
'/lnticket/api/v1/forms?all_wallets',
|
||||
'/lnticket/api/v1/forms?all_wallets=true',
|
||||
this.g.user.wallets[0].inkey
|
||||
)
|
||||
.then(function (response) {
|
||||
|
|
|
@ -1,32 +1,40 @@
|
|||
from quart import g, abort, render_template
|
||||
|
||||
from fastapi.param_functions import Depends
|
||||
from starlette.exceptions import HTTPException
|
||||
from starlette.responses import HTMLResponse
|
||||
from lnbits.core.models import User
|
||||
from lnbits.core.crud import get_wallet
|
||||
from lnbits.decorators import check_user_exists, validate_uuids
|
||||
from lnbits.decorators import check_user_exists
|
||||
from http import HTTPStatus
|
||||
|
||||
from . import lnticket_ext
|
||||
from . import lnticket_ext, lnticket_renderer
|
||||
from .crud import get_form
|
||||
from fastapi import FastAPI, Request
|
||||
from fastapi.templating import Jinja2Templates
|
||||
|
||||
templates = Jinja2Templates(directory="templates")
|
||||
|
||||
@lnticket_ext.route("/")
|
||||
@validate_uuids(["usr"], required=True)
|
||||
@check_user_exists()
|
||||
async def index(request: Request):
|
||||
return await templates.TemplateResponse("lnticket/index.html", {"request": request,"user":g.user})
|
||||
@lnticket_ext.get("/", response_class=HTMLResponse)
|
||||
# not needed as we automatically get the user with the given ID
|
||||
# If no user with this ID is found, an error is raised
|
||||
# @validate_uuids(["usr"], required=True)
|
||||
# @check_user_exists()
|
||||
async def index(request: Request, user: User = Depends(check_user_exists)):
|
||||
return lnticket_renderer().TemplateResponse("lnticket/index.html", {"request": request,"user": user.dict()})
|
||||
|
||||
|
||||
@lnticket_ext.route("/<form_id>")
|
||||
@lnticket_ext.get("/{form_id}")
|
||||
async def display(request: Request, form_id):
|
||||
form = await get_form(form_id)
|
||||
if not form:
|
||||
abort(HTTPStatus.NOT_FOUND, "LNTicket does not exist.")
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.NOT_FOUND,
|
||||
detail="LNTicket does not exist."
|
||||
)
|
||||
# abort(HTTPStatus.NOT_FOUND, "LNTicket does not exist.")
|
||||
|
||||
wallet = await get_wallet(form.wallet)
|
||||
|
||||
return await templates.TemplateResponse(
|
||||
return lnticket_renderer().TemplateResponse(
|
||||
"lnticket/display.html",
|
||||
{"request": request,
|
||||
"form_id":form.id,
|
||||
|
|
|
@ -1,15 +1,19 @@
|
|||
from lnbits.extensions.lnticket.models import CreateFormData, CreateTicketData
|
||||
import re
|
||||
from quart import g, jsonify, request
|
||||
from http import HTTPStatus
|
||||
from typing import List
|
||||
|
||||
from fastapi import Query
|
||||
from fastapi.params import Depends
|
||||
|
||||
from fastapi import FastAPI, Query
|
||||
from fastapi.encoders import jsonable_encoder
|
||||
from fastapi.responses import JSONResponse
|
||||
from pydantic import BaseModel
|
||||
from starlette.exceptions import HTTPException
|
||||
from starlette.requests import Request
|
||||
from starlette.responses import HTMLResponse, JSONResponse # type: ignore
|
||||
|
||||
from lnbits.core.crud import get_user, get_wallet
|
||||
from lnbits.core.services import create_invoice, check_invoice_status
|
||||
from lnbits.decorators import api_check_wallet_key, api_validate_post_request
|
||||
from lnbits.decorators import WalletTypeInfo, get_key_type
|
||||
|
||||
from . import lnticket_ext
|
||||
from .crud import (
|
||||
|
@ -30,29 +34,17 @@ from .crud import (
|
|||
|
||||
|
||||
@lnticket_ext.get("/api/v1/forms")
|
||||
@api_check_wallet_key("invoice")
|
||||
async def api_forms():
|
||||
wallet_ids = [g.wallet.id]
|
||||
async def api_forms_get(r: Request, all_wallets: bool = Query(False), wallet: WalletTypeInfo = Depends(get_key_type)):
|
||||
wallet_ids = [wallet.wallet.id]
|
||||
|
||||
if "all_wallets" in request.args:
|
||||
wallet_ids = (await get_user(g.wallet.user)).wallet_ids
|
||||
if all_wallets:
|
||||
wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids
|
||||
|
||||
return (
|
||||
[form._asdict() for form in await get_forms(wallet_ids)],
|
||||
HTTPStatus.OK,
|
||||
)
|
||||
return [form.dict() for form in await get_forms(wallet_ids)]
|
||||
|
||||
class CreateData(BaseModel):
|
||||
wallet: str = Query(...)
|
||||
name: str = Query(...)
|
||||
webhook: str = Query(None)
|
||||
description: str = Query(..., min_length=0)
|
||||
amount: int = Query(..., ge=0)
|
||||
flatrate: int = Query(...)
|
||||
|
||||
@lnticket_ext.post("/api/v1/forms")
|
||||
@lnticket_ext.post("/api/v1/forms", status_code=HTTPStatus.CREATED)
|
||||
@lnticket_ext.put("/api/v1/forms/{form_id}")
|
||||
@api_check_wallet_key("invoice")
|
||||
# @api_check_wallet_key("invoice")
|
||||
# @api_validate_post_request(
|
||||
# schema={
|
||||
# "wallet": {"type": "string", "empty": False, "required": True},
|
||||
|
@ -63,62 +55,69 @@ class CreateData(BaseModel):
|
|||
# "flatrate": {"type": "integer", "required": True},
|
||||
# }
|
||||
# )
|
||||
async def api_form_create(data: CreateData, form_id=None):
|
||||
async def api_form_create(data: CreateFormData, form_id=None, wallet: WalletTypeInfo = Depends(get_key_type)):
|
||||
if form_id:
|
||||
form = await get_form(form_id)
|
||||
|
||||
if not form:
|
||||
return {"message": "Form does not exist."}, HTTPStatus.NOT_FOUND
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.NOT_FOUND,
|
||||
detail=f"Form does not exist."
|
||||
)
|
||||
# return {"message": "Form does not exist."}, HTTPStatus.NOT_FOUND
|
||||
|
||||
if form.wallet != g.wallet.id:
|
||||
return jsonify{"message": "Not your form."}, HTTPStatus.FORBIDDEN
|
||||
if form.wallet != wallet.wallet.id:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.FORBIDDEN,
|
||||
detail=f"Not your form."
|
||||
)
|
||||
# return {"message": "Not your form."}, HTTPStatus.FORBIDDEN
|
||||
|
||||
form = await update_form(form_id, **data)
|
||||
else:
|
||||
form = await create_form(**data)
|
||||
return form._asdict(), HTTPStatus.CREATED
|
||||
form = await create_form(data, wallet.wallet)
|
||||
return form.dict()
|
||||
|
||||
|
||||
@lnticket_ext.delete("/api/v1/forms/{form_id}")
|
||||
@api_check_wallet_key("invoice")
|
||||
async def api_form_delete(form_id):
|
||||
# @api_check_wallet_key("invoice")
|
||||
async def api_form_delete(form_id, wallet: WalletTypeInfo = Depends(get_key_type)):
|
||||
form = await get_form(form_id)
|
||||
|
||||
if not form:
|
||||
return {"message": "Form does not exist."}, HTTPStatus.NOT_FOUND
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.NOT_FOUND,
|
||||
detail=f"Form does not exist."
|
||||
)
|
||||
# return {"message": "Form does not exist."}, HTTPStatus.NOT_FOUND
|
||||
|
||||
if form.wallet != g.wallet.id:
|
||||
return {"message": "Not your form."}, HTTPStatus.FORBIDDEN
|
||||
if form.wallet != wallet.wallet.id:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.FORBIDDEN,
|
||||
detail=f"Not your form."
|
||||
)
|
||||
# return {"message": "Not your form."}, HTTPStatus.FORBIDDEN
|
||||
|
||||
await delete_form(form_id)
|
||||
|
||||
return "", HTTPStatus.NO_CONTENT
|
||||
# return "", HTTPStatus.NO_CONTENT
|
||||
raise HTTPException(status_code=HTTPStatus.NO_CONTENT)
|
||||
|
||||
|
||||
#########tickets##########
|
||||
|
||||
|
||||
@lnticket_ext.get("/api/v1/tickets")
|
||||
@api_check_wallet_key("invoice")
|
||||
async def api_tickets(all_wallets: bool = Query(None)):
|
||||
wallet_ids = [g.wallet.id]
|
||||
# @api_check_wallet_key("invoice")
|
||||
async def api_tickets(all_wallets: bool = Query(False), wallet: WalletTypeInfo = Depends(get_key_type)):
|
||||
wallet_ids = [wallet.wallet.id]
|
||||
|
||||
if all_wallets:
|
||||
wallet_ids = (await get_user(g.wallet.user)).wallet_ids
|
||||
wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids
|
||||
|
||||
return (
|
||||
[form._asdict() for form in await get_tickets(wallet_ids)],
|
||||
HTTPStatus.OK,
|
||||
)
|
||||
return [form.dict() for form in await get_tickets(wallet_ids)]
|
||||
|
||||
class CreateTicketData(BaseModel):
|
||||
form: str = Query(...)
|
||||
name: str = Query(...)
|
||||
email: str = Query("")
|
||||
ltext: str = Query(...)
|
||||
sats: int = Query(..., ge=0)
|
||||
|
||||
@lnticket_ext.post("/api/v1/tickets/{form_id}")
|
||||
@lnticket_ext.post("/api/v1/tickets/{form_id}", status_code=HTTPStatus.CREATED)
|
||||
# @api_validate_post_request(
|
||||
# schema={
|
||||
# "form": {"type": "string", "empty": False, "required": True},
|
||||
|
@ -131,66 +130,86 @@ class CreateTicketData(BaseModel):
|
|||
async def api_ticket_make_ticket(data: CreateTicketData, form_id):
|
||||
form = await get_form(form_id)
|
||||
if not form:
|
||||
return {"message": "LNTicket does not exist."}, HTTPStatus.NOT_FOUND
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.NOT_FOUND,
|
||||
detail=f"LNTicket does not exist."
|
||||
)
|
||||
# return {"message": "LNTicket does not exist."}, HTTPStatus.NOT_FOUND
|
||||
|
||||
nwords = len(re.split(r"\s+", data["ltext"]))
|
||||
sats = data["sats"]
|
||||
nwords = len(re.split(r"\s+", data.ltext))
|
||||
|
||||
try:
|
||||
payment_hash, payment_request = await create_invoice(
|
||||
wallet_id=form.wallet,
|
||||
amount=sats,
|
||||
amount=data.sats,
|
||||
memo=f"ticket with {nwords} words on {form_id}",
|
||||
extra={"tag": "lnticket"},
|
||||
)
|
||||
except Exception as e:
|
||||
return {"message": str(e)}, HTTPStatus.INTERNAL_SERVER_ERROR
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
|
||||
detail=str(e)
|
||||
)
|
||||
# return {"message": str(e)}, HTTPStatus.INTERNAL_SERVER_ERROR
|
||||
|
||||
ticket = await create_ticket(
|
||||
payment_hash=payment_hash, wallet=form.wallet, **data
|
||||
payment_hash=payment_hash, wallet=form.wallet, data=data
|
||||
)
|
||||
|
||||
if not ticket:
|
||||
return (
|
||||
{"message": "LNTicket could not be fetched."},
|
||||
HTTPStatus.NOT_FOUND,
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.NOT_FOUND,
|
||||
detail="LNTicket could not be fetched."
|
||||
)
|
||||
# return (
|
||||
# {"message": "LNTicket could not be fetched."},
|
||||
# HTTPStatus.NOT_FOUND,
|
||||
# )
|
||||
|
||||
return
|
||||
{"payment_hash": payment_hash, "payment_request": payment_request},
|
||||
HTTPStatus.OK
|
||||
return {
|
||||
"payment_hash": payment_hash,
|
||||
"payment_request": payment_request
|
||||
}
|
||||
|
||||
|
||||
@lnticket_ext.get("/api/v1/tickets/{payment_hash}")
|
||||
@lnticket_ext.get("/api/v1/tickets/{payment_hash}", status_code=HTTPStatus.OK)
|
||||
async def api_ticket_send_ticket(payment_hash):
|
||||
ticket = await get_ticket(payment_hash)
|
||||
try:
|
||||
status = await check_invoice_status(ticket.wallet, payment_hash)
|
||||
is_paid = not status.pending
|
||||
except Exception:
|
||||
return {"paid": False}, HTTPStatus.OK
|
||||
return {"paid": False}
|
||||
|
||||
if is_paid:
|
||||
wallet = await get_wallet(ticket.wallet)
|
||||
payment = await wallet.get_payment(payment_hash)
|
||||
await payment.set_pending(False)
|
||||
ticket = await set_ticket_paid(payment_hash=payment_hash)
|
||||
return {"paid": True}, HTTPStatus.OK
|
||||
return {"paid": True}
|
||||
|
||||
return {"paid": False}, HTTPStatus.OK
|
||||
return {"paid": False}
|
||||
|
||||
|
||||
@lnticket_ext.delete("/api/v1/tickets/{ticket_id}")
|
||||
@api_check_wallet_key("invoice")
|
||||
async def api_ticket_delete(ticket_id):
|
||||
# @api_check_wallet_key("invoice")
|
||||
async def api_ticket_delete(ticket_id, wallet: WalletTypeInfo = Depends(get_key_type)):
|
||||
ticket = await get_ticket(ticket_id)
|
||||
|
||||
if not ticket:
|
||||
return {"message": "Paywall does not exist."}, HTTPStatus.NOT_FOUND
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.NOT_FOUND,
|
||||
detail=f"LNTicket does not exist."
|
||||
)
|
||||
# return {"message": "Paywall does not exist."}, HTTPStatus.NOT_FOUND
|
||||
|
||||
if ticket.wallet != g.wallet.id:
|
||||
return {"message": "Not your ticket."}, HTTPStatus.FORBIDDEN
|
||||
if ticket.wallet != wallet.wallet.id:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.FORBIDDEN,
|
||||
detail="Not your ticket."
|
||||
)
|
||||
# return {"message": "Not your ticket."}, HTTPStatus.FORBIDDEN
|
||||
|
||||
await delete_ticket(ticket_id)
|
||||
|
||||
return "", HTTPStatus.NO_CONTENT
|
||||
raise HTTPException(status_code=HTTPStatus.NO_CONTENT)
|
||||
# return ""
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import hashlib
|
||||
from lnbits.extensions.offlineshop.models import Item
|
||||
from fastapi.params import Query
|
||||
|
||||
from starlette.requests import Request
|
||||
|
@ -13,8 +14,8 @@ from .crud import get_shop, get_item
|
|||
|
||||
|
||||
@offlineshop_ext.get("/lnurl/{item_id}", name="offlineshop.lnurl_response")
|
||||
async def lnurl_response(item_id: int = Query(...)):
|
||||
item = await get_item(item_id)
|
||||
async def lnurl_response(req: Request, item_id: int = Query(...)):
|
||||
item = await get_item(item_id) # type: Item
|
||||
if not item:
|
||||
return {"status": "ERROR", "reason": "Item not found."}
|
||||
|
||||
|
@ -28,7 +29,7 @@ async def lnurl_response(item_id: int = Query(...)):
|
|||
) * 1000
|
||||
|
||||
resp = LnurlPayResponse(
|
||||
callback=url_for("offlineshop.lnurl_callback", item_id=item.id, _external=True),
|
||||
callback=req.url_for("offlineshop.lnurl_callback", item_id=item.id),
|
||||
min_sendable=price_msat,
|
||||
max_sendable=price_msat,
|
||||
metadata=await item.lnurlpay_metadata(),
|
||||
|
@ -37,9 +38,9 @@ async def lnurl_response(item_id: int = Query(...)):
|
|||
return resp.dict()
|
||||
|
||||
|
||||
@offlineshop_ext.get("/lnurl/cb/<item_id>")
|
||||
@offlineshop_ext.get("/lnurl/cb/{item_id}", name="offlineshop.lnurl_callback")
|
||||
async def lnurl_callback(request: Request, item_id: int):
|
||||
item = await get_item(item_id)
|
||||
item = await get_item(item_id) # type: Item
|
||||
if not item:
|
||||
return {"status": "ERROR", "reason": "Couldn't find item."}
|
||||
|
||||
|
@ -52,7 +53,7 @@ async def lnurl_callback(request: Request, item_id: int):
|
|||
min = price * 995
|
||||
max = price * 1010
|
||||
|
||||
amount_received = int(request.args.get("amount") or 0)
|
||||
amount_received = int(request.query_params.get("amount") or 0)
|
||||
if amount_received < min:
|
||||
return LnurlErrorResponse(
|
||||
reason=f"Amount {amount_received} is smaller than minimum {min}."
|
||||
|
|
|
@ -14,7 +14,8 @@ from .helpers import totp
|
|||
shop_counters: Dict = {}
|
||||
|
||||
|
||||
class ShopCounter(BaseModel):
|
||||
class ShopCounter():
|
||||
wordlist: List[str]
|
||||
fulfilled_payments: OrderedDict
|
||||
counter: int
|
||||
|
||||
|
@ -88,6 +89,11 @@ class Item(BaseModel):
|
|||
price: int
|
||||
unit: str
|
||||
|
||||
def lnurl(self, req: Request) -> str:
|
||||
return lnurl_encode(
|
||||
req.url_for("offlineshop.lnurl_response", item_id=self.id)
|
||||
)
|
||||
|
||||
def values(self, req: Request):
|
||||
values = self.dict()
|
||||
values["lnurl"] = lnurl_encode(
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import time
|
||||
from datetime import datetime
|
||||
from http import HTTPStatus
|
||||
from typing import List
|
||||
|
||||
from fastapi.params import Depends
|
||||
from fastapi.params import Depends, Query
|
||||
from starlette.responses import HTMLResponse
|
||||
|
||||
from lnbits.decorators import check_user_exists
|
||||
|
@ -10,6 +11,7 @@ from lnbits.core.models import Payment, User
|
|||
from lnbits.core.crud import get_standalone_payment
|
||||
|
||||
from . import offlineshop_ext, offlineshop_renderer
|
||||
from .models import Item
|
||||
from .crud import get_item, get_shop
|
||||
from fastapi import Request, HTTPException
|
||||
|
||||
|
@ -20,14 +22,14 @@ async def index(request: Request, user: User = Depends(check_user_exists)):
|
|||
|
||||
|
||||
@offlineshop_ext.get("/print", response_class=HTMLResponse)
|
||||
async def print_qr_codes(request: Request):
|
||||
async def print_qr_codes(request: Request, items: List[int] = None):
|
||||
items = []
|
||||
for item_id in request.args.get("items").split(","):
|
||||
item = await get_item(item_id)
|
||||
for item_id in request.query_params.get("items").split(","):
|
||||
item = await get_item(item_id) # type: Item
|
||||
if item:
|
||||
items.append(
|
||||
{
|
||||
"lnurl": item.lnurl,
|
||||
"lnurl": item.lnurl(request),
|
||||
"name": item.name,
|
||||
"price": f"{item.price} {item.unit}",
|
||||
}
|
||||
|
@ -36,8 +38,9 @@ async def print_qr_codes(request: Request):
|
|||
return offlineshop_renderer().TemplateResponse("offlineshop/print.html", {"request": request,"items":items})
|
||||
|
||||
|
||||
@offlineshop_ext.get("/confirmation")
|
||||
async def confirmation_code(p: str):
|
||||
@offlineshop_ext.get("/confirmation/{p}", name="offlineshop.confirmation_code",
|
||||
response_class=HTMLResponse)
|
||||
async def confirmation_code(p: str = Query(...)):
|
||||
style = "<style>* { font-size: 100px}</style>"
|
||||
|
||||
payment_hash = p
|
||||
|
|
|
@ -1,51 +1,48 @@
|
|||
aiofiles==0.6.0
|
||||
async-generator==1.10
|
||||
attrs==20.3.0
|
||||
aiofiles==0.7.0
|
||||
anyio==3.3.1
|
||||
asgiref==3.4.1
|
||||
asyncio==3.4.3
|
||||
attrs==21.2.0
|
||||
bech32==1.2.0
|
||||
bitstring==3.1.7
|
||||
blinker==1.4
|
||||
brotli==1.0.9
|
||||
cerberus==1.3.3
|
||||
certifi==2020.12.5
|
||||
click==7.1.2
|
||||
ecdsa==0.16.1
|
||||
embit==0.2.1
|
||||
environs==9.3.2
|
||||
bitstring==3.1.9
|
||||
cerberus==1.3.4
|
||||
certifi==2021.5.30
|
||||
charset-normalizer==2.0.6
|
||||
click==8.0.1
|
||||
ecdsa==0.17.0
|
||||
embit==0.4.9
|
||||
environs==9.3.3
|
||||
fastapi==0.68.1
|
||||
h11==0.12.0
|
||||
h2==4.0.0
|
||||
hpack==4.0.0
|
||||
httpcore==0.12.3
|
||||
httpx==0.17.1
|
||||
hypercorn==0.11.2
|
||||
hyperframe==6.0.0
|
||||
idna==3.1
|
||||
itsdangerous==1.1.0
|
||||
jinja2==2.11.3
|
||||
httpcore==0.13.7
|
||||
httptools==0.2.0
|
||||
httpx==0.19.0
|
||||
idna==3.2
|
||||
importlib-metadata==4.8.1
|
||||
jinja2==3.0.1
|
||||
lnurl==0.3.6
|
||||
markupsafe==1.1.1
|
||||
marshmallow==3.11.1
|
||||
markupsafe==2.0.1
|
||||
marshmallow==3.13.0
|
||||
outcome==1.1.0
|
||||
priority==1.3.0
|
||||
pydantic==1.8.1
|
||||
pyngrok==5.0.5
|
||||
pypng==0.0.20
|
||||
psycopg2-binary==2.9.1
|
||||
pydantic==1.8.2
|
||||
pypng==0.0.21
|
||||
pyqrcode==1.2.1
|
||||
pyscss==1.3.7
|
||||
python-dotenv==0.17.0
|
||||
quart==0.14.1
|
||||
quart-compress==0.2.1
|
||||
quart-cors==0.4.0
|
||||
quart-trio==0.7.0
|
||||
python-dotenv==0.19.0
|
||||
pyyaml==5.4.1
|
||||
represent==1.6.0.post0
|
||||
rfc3986==1.4.0
|
||||
rfc3986==1.5.0
|
||||
shortuuid==1.0.1
|
||||
six==1.15.0
|
||||
six==1.16.0
|
||||
sniffio==1.2.0
|
||||
sortedcontainers==2.3.0
|
||||
sqlalchemy==1.3.23
|
||||
sqlalchemy-aio==0.16.0
|
||||
toml==0.10.2
|
||||
trio==0.16.0
|
||||
typing-extensions==3.7.4.3
|
||||
werkzeug==1.0.1
|
||||
wsproto==1.0.0
|
||||
sse-starlette==0.6.2
|
||||
starlette==0.14.2
|
||||
typing-extensions==3.10.0.2
|
||||
uvicorn==0.15.0
|
||||
uvloop==0.16.0
|
||||
watchgod==0.7
|
||||
websockets==10.0
|
||||
zipp==3.5.0
|
||||
|
|
Loading…
Reference in New Issue
Block a user