diff --git a/Pipfile b/Pipfile index bd083d2..4d5e7ea 100644 --- a/Pipfile +++ b/Pipfile @@ -36,6 +36,7 @@ marshmallow-sqlalchemy = "*" apispec = "*" chardet = "*" charset-normalizer = "*" +strawberry-graphql = {extras = ["debug-server"], version = "*"} [dev-packages] diff --git a/Pipfile.lock b/Pipfile.lock index fd94bb3..48132ef 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "139c2837868fad8189d71c845996c7ca3afd2593fb92d34711e51da8a2b30485" + "sha256": "1d510891b525a476b9c5d71182bed933548ebf442b833c80654da22491674409" }, "pipfile-spec": 6, "requires": { @@ -31,6 +31,14 @@ ], "version": "==9.0.1" }, + "anyio": { + "hashes": [ + "sha256:745843b39e829e108e518c489b31dc757de7d2131d53fac32bd8df268227bfee", + "sha256:e1875bb4b4e2de1669f4bc7869b6d3f54231cdced71605e6e64c9be77e3be50f" + ], + "markers": "python_version >= '3.8'", + "version": "==4.2.0" + }, "apispec": { "extras": [ "yaml" @@ -45,12 +53,12 @@ }, "apispec-webframeworks": { "hashes": [ - "sha256:0db35b267914b3f8c562aca0261957dbcb4176f255eacc22520277010818dcf3", - "sha256:482c563abbcc2a261439476cb3f1a7c7284cc997c322c574d48c111643e9c04e" + "sha256:024965e69d40b8245165070668c9df6e65cd010ed333a5fb648472ff656bf019", + "sha256:7ca64ee5cdac25f6eb686744d179a4946db9185388d1986c9468e4f52762febb" ], "index": "pypi", - "markers": "python_version >= '3.6'", - "version": "==0.5.2" + "markers": "python_version >= '3.8'", + "version": "==1.0.0" }, "attrs": { "hashes": [ @@ -62,12 +70,12 @@ }, "beautifulsoup4": { "hashes": [ - "sha256:492bbc69dca35d12daac71c4db1bfff0c876c00ef4a2ffacce226d4638eb72da", - "sha256:bd2520ca0d9d7d12694a53d44ac482d181b4ec1888909b035a3dbf40d0f57d4a" + "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051", + "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed" ], "index": "pypi", "markers": "python_full_version >= '3.6.0'", - "version": "==4.12.2" + "version": "==4.12.3" }, "black": { "hashes": [ @@ -303,11 +311,11 @@ }, "faker": { "hashes": [ - "sha256:2c2b7a8e55368defd718226bd5b48ef31b2d082c2900ccb4200987e433be500e", - "sha256:fab78f435d27fa7bd109b095eea3504477e4149051c903fd63f11ce252e3d9b7" + "sha256:9a510a31090cc47a7ef7d95c1da8126a891a9d076c7e26b01ad02e1bcf915c3e", + "sha256:a4e689e2f4e62474245364bbd82cec045dcbbf85a539ee742a515fb4e93a6dd5" ], "markers": "python_version >= '3.8'", - "version": "==22.2.0" + "version": "==22.5.0" }, "flasgger": { "hashes": [ @@ -345,12 +353,12 @@ }, "flask-marshmallow": { "hashes": [ - "sha256:2083ae55bebb5142fff98c6bbd483a2f5dbc531a8bc1be2180ed5f75e7f3fccc", - "sha256:ce08a153f74da6ebfffd8065d1687508b0179df37fff7fc0c8f28ccfb64f1b56" + "sha256:2d186af7c8b4455b8a2c166c7470939c17d70353671ea5a287a14676846fa013", + "sha256:45787a13d1e2b4940ea19d1882c8cf6e43335aa769e91f3e2a270d18d9f66f2e" ], "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==0.15.0" + "markers": "python_version >= '3.8'", + "version": "==1.1.0" }, "flask-migrate": { "hashes": [ @@ -425,6 +433,14 @@ "markers": "python_version >= '3.8'", "version": "==23.9.1" }, + "graphql-core": { + "hashes": [ + "sha256:06d2aad0ac723e35b1cb47885d3e5c45e956a53bc1b209a9fc5369007fe46676", + "sha256:5766780452bd5ec8ba133f8bf287dc92713e3868ddd83aee4faab9fc3e303dc3" + ], + "markers": "python_version >= '3.6' and python_version < '4'", + "version": "==3.2.3" + }, "greenlet": { "hashes": [ "sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67", @@ -498,6 +514,14 @@ "markers": "python_version >= '3.5'", "version": "==20.1.0" }, + "h11": { + "hashes": [ + "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", + "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761" + ], + "markers": "python_version >= '3.7'", + "version": "==0.14.0" + }, "idna": { "hashes": [ "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca", @@ -532,11 +556,11 @@ }, "jsonschema": { "hashes": [ - "sha256:3ba18e27f7491ea4a1b22edce00fb820eec968d397feb3f9cb61d5894bb38167", - "sha256:70a09719d375c0a2874571b363c8a24be7df8071b80c9aa76bc4551e7297c63c" + "sha256:7996507afae316306f9e2290407761157c6f78002dcf7419acb99822143d1c6f", + "sha256:85727c00279f5fa6bedbe6238d2aa6403bedd8b4864ab11207d07df3cc1b2ee5" ], "markers": "python_version >= '3.8'", - "version": "==4.21.0" + "version": "==4.21.1" }, "jsonschema-specifications": { "hashes": [ @@ -546,6 +570,42 @@ "markers": "python_version >= '3.8'", "version": "==2023.12.1" }, + "libcst": { + "hashes": [ + "sha256:003e5e83a12eed23542c4ea20fdc8de830887cc03662432bb36f84f8c4841b81", + "sha256:0acbacb9a170455701845b7e940e2d7b9519db35a86768d86330a0b0deae1086", + "sha256:0bf69cbbab5016d938aac4d3ae70ba9ccb3f90363c588b3b97be434e6ba95403", + "sha256:2d37326bd6f379c64190a28947a586b949de3a76be00176b0732c8ee87d67ebe", + "sha256:3a07ecfabbbb8b93209f952a365549e65e658831e9231649f4f4e4263cad24b1", + "sha256:3ebbb9732ae3cc4ae7a0e97890bed0a57c11d6df28790c2b9c869f7da653c7c7", + "sha256:4bc745d0c06420fe2644c28d6ddccea9474fb68a2135904043676deb4fa1e6bc", + "sha256:5297a16e575be8173185e936b7765c89a3ca69d4ae217a4af161814a0f9745a7", + "sha256:5f1cd308a4c2f71d5e4eec6ee693819933a03b78edb2e4cc5e3ad1afd5fb3f07", + "sha256:63f75656fd733dc20354c46253fde3cf155613e37643c3eaf6f8818e95b7a3d1", + "sha256:73c086705ed34dbad16c62c9adca4249a556c1b022993d511da70ea85feaf669", + "sha256:75816647736f7e09c6120bdbf408456f99b248d6272277eed9a58cf50fb8bc7d", + "sha256:78b7a38ec4c1c009ac39027d51558b52851fb9234669ba5ba62283185963a31c", + "sha256:7ccaf53925f81118aeaadb068a911fac8abaff608817d7343da280616a5ca9c1", + "sha256:82d1271403509b0a4ee6ff7917c2d33b5a015f44d1e208abb1da06ba93b2a378", + "sha256:8ae11eb1ea55a16dc0cdc61b41b29ac347da70fec14cc4381248e141ee2fbe6c", + "sha256:8afb6101b8b3c86c5f9cec6b90ab4da16c3c236fe7396f88e8b93542bb341f7c", + "sha256:8c1f2da45f1c45634090fd8672c15e0159fdc46853336686959b2d093b6e10fa", + "sha256:97fbc73c87e9040e148881041fd5ffa2a6ebf11f64b4ccb5b52e574b95df1a15", + "sha256:99fdc1929703fd9e7408aed2e03f58701c5280b05c8911753a8d8619f7dfdda5", + "sha256:9dffa1795c2804d183efb01c0f1efd20a7831db6a21a0311edf90b4100d67436", + "sha256:bca1841693941fdd18371824bb19a9702d5784cd347cb8231317dbdc7062c5bc", + "sha256:c653d9121d6572d8b7f8abf20f88b0a41aab77ff5a6a36e5a0ec0f19af0072e8", + "sha256:c8f26250f87ca849a7303ed7a4fd6b2c7ac4dec16b7d7e68ca6a476d7c9bfcdb", + "sha256:cc9b6ac36d7ec9db2f053014ea488086ca2ed9c322be104fbe2c71ca759da4bb", + "sha256:d22d1abfe49aa60fc61fa867e10875a9b3024ba5a801112f4d7ba42d8d53242e", + "sha256:d68c34e3038d3d1d6324eb47744cbf13f2c65e1214cf49db6ff2a6603c1cd838", + "sha256:e3d8cf974cfa2487b28f23f56c4bff90d550ef16505e58b0dca0493d5293784b", + "sha256:f36f592e035ef84f312a12b75989dde6a5f6767fe99146cdae6a9ee9aff40dd0", + "sha256:f561c9a84eca18be92f4ad90aa9bd873111efbea995449301719a1a7805dbc5c", + "sha256:fe41b33aa73635b1651f64633f429f7aa21f86d2db5748659a99d9b7b1ed2a90" + ], + "version": "==1.1.0" + }, "loguru": { "hashes": [ "sha256:066bd06758d0a513e9836fd9c6b5a75bfb3fd36841f4b996bc60b547a309d41c", @@ -557,77 +617,85 @@ }, "mako": { "hashes": [ - "sha256:57d4e997349f1a92035aa25c17ace371a4213f2ca42f99bee9a602500cfd54d9", - "sha256:e3a9d388fd00e87043edbe8792f45880ac0114e9c4adc69f6e9bfb2c55e3b11b" + "sha256:463f03e04559689adaee25e0967778d6ad41285ed607dc1e7df0dd4e4df81f9e", + "sha256:baee30b9c61718e093130298e678abed0dbfa1b411fcc4c1ab4df87cd631a0f2" ], "markers": "python_version >= '3.8'", - "version": "==1.3.0" + "version": "==1.3.1" + }, + "markdown-it-py": { + "hashes": [ + "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", + "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb" + ], + "markers": "python_version >= '3.8'", + "version": "==3.0.0" }, "markupsafe": { "hashes": [ - "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e", - "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e", - "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431", - "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686", - "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c", - "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559", - "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc", - "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb", - "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939", - "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c", - "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0", - "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4", - "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9", - "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575", - "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba", - "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d", - "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd", - "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3", - "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00", - "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155", - "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac", - "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52", - "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f", - "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8", - "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b", - "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007", - "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24", - "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea", - "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198", - "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0", - "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee", - "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be", - "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2", - "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1", - "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707", - "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6", - "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c", - "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58", - "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823", - "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779", - "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636", - "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c", - "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad", - "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee", - "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc", - "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2", - "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48", - "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7", - "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e", - "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b", - "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa", - "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5", - "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e", - "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb", - "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9", - "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57", - "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc", - "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc", - "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2", - "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11" + "sha256:0042d6a9880b38e1dd9ff83146cc3c9c18a059b9360ceae207805567aacccc69", + "sha256:0c26f67b3fe27302d3a412b85ef696792c4a2386293c53ba683a89562f9399b0", + "sha256:0fbad3d346df8f9d72622ac71b69565e621ada2ce6572f37c2eae8dacd60385d", + "sha256:15866d7f2dc60cfdde12ebb4e75e41be862348b4728300c36cdf405e258415ec", + "sha256:1c98c33ffe20e9a489145d97070a435ea0679fddaabcafe19982fe9c971987d5", + "sha256:21e7af8091007bf4bebf4521184f4880a6acab8df0df52ef9e513d8e5db23411", + "sha256:23984d1bdae01bee794267424af55eef4dfc038dc5d1272860669b2aa025c9e3", + "sha256:31f57d64c336b8ccb1966d156932f3daa4fee74176b0fdc48ef580be774aae74", + "sha256:3583a3a3ab7958e354dc1d25be74aee6228938312ee875a22330c4dc2e41beb0", + "sha256:36d7626a8cca4d34216875aee5a1d3d654bb3dac201c1c003d182283e3205949", + "sha256:396549cea79e8ca4ba65525470d534e8a41070e6b3500ce2414921099cb73e8d", + "sha256:3a66c36a3864df95e4f62f9167c734b3b1192cb0851b43d7cc08040c074c6279", + "sha256:3aae9af4cac263007fd6309c64c6ab4506dd2b79382d9d19a1994f9240b8db4f", + "sha256:3ab3a886a237f6e9c9f4f7d272067e712cdb4efa774bef494dccad08f39d8ae6", + "sha256:47bb5f0142b8b64ed1399b6b60f700a580335c8e1c57f2f15587bd072012decc", + "sha256:49a3b78a5af63ec10d8604180380c13dcd870aba7928c1fe04e881d5c792dc4e", + "sha256:4df98d4a9cd6a88d6a585852f56f2155c9cdb6aec78361a19f938810aa020954", + "sha256:5045e892cfdaecc5b4c01822f353cf2c8feb88a6ec1c0adef2a2e705eef0f656", + "sha256:5244324676254697fe5c181fc762284e2c5fceeb1c4e3e7f6aca2b6f107e60dc", + "sha256:54635102ba3cf5da26eb6f96c4b8c53af8a9c0d97b64bdcb592596a6255d8518", + "sha256:54a7e1380dfece8847c71bf7e33da5d084e9b889c75eca19100ef98027bd9f56", + "sha256:55d03fea4c4e9fd0ad75dc2e7e2b6757b80c152c032ea1d1de487461d8140efc", + "sha256:698e84142f3f884114ea8cf83e7a67ca8f4ace8454e78fe960646c6c91c63bfa", + "sha256:6aa5e2e7fc9bc042ae82d8b79d795b9a62bd8f15ba1e7594e3db243f158b5565", + "sha256:7653fa39578957bc42e5ebc15cf4361d9e0ee4b702d7d5ec96cdac860953c5b4", + "sha256:765f036a3d00395a326df2835d8f86b637dbaf9832f90f5d196c3b8a7a5080cb", + "sha256:78bc995e004681246e85e28e068111a4c3f35f34e6c62da1471e844ee1446250", + "sha256:7a07f40ef8f0fbc5ef1000d0c78771f4d5ca03b4953fc162749772916b298fc4", + "sha256:8b570a1537367b52396e53325769608f2a687ec9a4363647af1cded8928af959", + "sha256:987d13fe1d23e12a66ca2073b8d2e2a75cec2ecb8eab43ff5624ba0ad42764bc", + "sha256:9896fca4a8eb246defc8b2a7ac77ef7553b638e04fbf170bff78a40fa8a91474", + "sha256:9e9e3c4020aa2dc62d5dd6743a69e399ce3de58320522948af6140ac959ab863", + "sha256:a0b838c37ba596fcbfca71651a104a611543077156cb0a26fe0c475e1f152ee8", + "sha256:a4d176cfdfde84f732c4a53109b293d05883e952bbba68b857ae446fa3119b4f", + "sha256:a76055d5cb1c23485d7ddae533229039b850db711c554a12ea64a0fd8a0129e2", + "sha256:a76cd37d229fc385738bd1ce4cba2a121cf26b53864c1772694ad0ad348e509e", + "sha256:a7cc49ef48a3c7a0005a949f3c04f8baa5409d3f663a1b36f0eba9bfe2a0396e", + "sha256:abf5ebbec056817057bfafc0445916bb688a255a5146f900445d081db08cbabb", + "sha256:b0fe73bac2fed83839dbdbe6da84ae2a31c11cfc1c777a40dbd8ac8a6ed1560f", + "sha256:b6f14a9cd50c3cb100eb94b3273131c80d102e19bb20253ac7bd7336118a673a", + "sha256:b83041cda633871572f0d3c41dddd5582ad7d22f65a72eacd8d3d6d00291df26", + "sha256:b835aba863195269ea358cecc21b400276747cc977492319fd7682b8cd2c253d", + "sha256:bf1196dcc239e608605b716e7b166eb5faf4bc192f8a44b81e85251e62584bd2", + "sha256:c669391319973e49a7c6230c218a1e3044710bc1ce4c8e6eb71f7e6d43a2c131", + "sha256:c7556bafeaa0a50e2fe7dc86e0382dea349ebcad8f010d5a7dc6ba568eaaa789", + "sha256:c8f253a84dbd2c63c19590fa86a032ef3d8cc18923b8049d91bcdeeb2581fbf6", + "sha256:d18b66fe626ac412d96c2ab536306c736c66cf2a31c243a45025156cc190dc8a", + "sha256:d5291d98cd3ad9a562883468c690a2a238c4a6388ab3bd155b0c75dd55ece858", + "sha256:d5c31fe855c77cad679b302aabc42d724ed87c043b1432d457f4976add1c2c3e", + "sha256:d6e427c7378c7f1b2bef6a344c925b8b63623d3321c09a237b7cc0e77dd98ceb", + "sha256:dac1ebf6983148b45b5fa48593950f90ed6d1d26300604f321c74a9ca1609f8e", + "sha256:de8153a7aae3835484ac168a9a9bdaa0c5eee4e0bc595503c95d53b942879c84", + "sha256:e1a0d1924a5013d4f294087e00024ad25668234569289650929ab871231668e7", + "sha256:e7902211afd0af05fbadcc9a312e4cf10f27b779cf1323e78d52377ae4b72bea", + "sha256:e888ff76ceb39601c59e219f281466c6d7e66bd375b4ec1ce83bcdc68306796b", + "sha256:f06e5a9e99b7df44640767842f414ed5d7bedaaa78cd817ce04bbd6fd86e2dd6", + "sha256:f6be2d708a9d0e9b0054856f07ac7070fbe1754be40ca8525d5adccdbda8f475", + "sha256:f9917691f410a2e0897d1ef99619fd3f7dd503647c8ff2475bf90c3cf222ad74", + "sha256:fc1a75aa8f11b87910ffd98de62b29d6520b6d6e8a3de69a70ca34dea85d2a8a", + "sha256:fe8512ed897d5daf089e5bd010c3dc03bb1bdae00b35588c49b98268d4a01e00" ], "markers": "python_version >= '3.7'", - "version": "==2.1.3" + "version": "==2.1.4" }, "marshmallow": { "hashes": [ @@ -646,6 +714,14 @@ "markers": "python_version >= '3.8'", "version": "==0.30.0" }, + "mdurl": { + "hashes": [ + "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", + "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba" + ], + "markers": "python_version >= '3.7'", + "version": "==0.1.2" + }, "mistune": { "hashes": [ "sha256:71481854c30fdbc938963d3605b72501f5c10a9320ecd412c121c163a1c7d205", @@ -735,6 +811,13 @@ "markers": "python_version >= '3.8'", "version": "==4.25.2" }, + "pygments": { + "hashes": [ + "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c", + "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367" + ], + "version": "==2.17.2" + }, "pyjwt": { "hashes": [ "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de", @@ -804,6 +887,13 @@ "markers": "python_version >= '3.5'", "version": "==0.20.0" }, + "python-multipart": { + "hashes": [ + "sha256:e9925a80bb668529f1b67c7fdb0a5dacdd7cbfc6fb0bff3ea443fe22bdd62132", + "sha256:ee698bab5ef148b0a760751c261902cd096e57e10558e11aca17646b74ee1c18" + ], + "version": "==0.0.6" + }, "pytz": { "hashes": [ "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b", @@ -842,6 +932,7 @@ "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4", "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba", "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8", + "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef", "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5", "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd", "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3", @@ -884,6 +975,13 @@ "markers": "python_version >= '3.7'", "version": "==2.31.0" }, + "rich": { + "hashes": [ + "sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa", + "sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235" + ], + "version": "==13.7.0" + }, "rpds-py": { "hashes": [ "sha256:01f58a7306b64e0a4fe042047dd2b7d411ee82e54240284bab63e325762c1147", @@ -1014,6 +1112,14 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.16.0" }, + "sniffio": { + "hashes": [ + "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101", + "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384" + ], + "markers": "python_version >= '3.7'", + "version": "==1.3.0" + }, "soupsieve": { "hashes": [ "sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690", @@ -1084,6 +1190,24 @@ "index": "pypi", "version": "==1.4.1" }, + "starlette": { + "hashes": [ + "sha256:96df8541093dfd37624b5bf980802b99750db6718dd3ca341618fbbcdd6136fb", + "sha256:d5b43a72f475fd1b9707f661aa66da42d59ae16c9b2a5845b4edee4309c425ee" + ], + "version": "==0.36.1" + }, + "strawberry-graphql": { + "extras": [ + "debug-server" + ], + "hashes": [ + "sha256:306f8af56325459a20463431e90d4045ab8190bc3851c652b484cac6fb61c3a5", + "sha256:3d4109c398c1e1d9c44f6785163c5fe94f25507bb21226ace78f1eaf737a378c" + ], + "markers": "python_version >= '3.8' and python_version < '4.0'", + "version": "==0.218.0" + }, "termcolor": { "hashes": [ "sha256:9297c0df9c99445c2412e832e882a7884038a25617c60cea2ad69488d4040d63", @@ -1092,6 +1216,13 @@ "markers": "python_version >= '3.8'", "version": "==2.4.0" }, + "typer": { + "hashes": [ + "sha256:50922fd79aea2f4751a8e0408ff10d2662bd0c8bbfa84755a699f3bada2978b2", + "sha256:5d96d986a21493606a358cae4461bd8cdf83cbf33a5aa950ae629ca3b51467ee" + ], + "version": "==0.9.0" + }, "typing-extensions": { "hashes": [ "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783", @@ -1100,6 +1231,13 @@ "markers": "python_version >= '3.8'", "version": "==4.9.0" }, + "typing-inspect": { + "hashes": [ + "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f", + "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78" + ], + "version": "==0.9.0" + }, "urllib3": { "hashes": [ "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3", @@ -1108,6 +1246,13 @@ "markers": "python_version >= '3.8'", "version": "==2.1.0" }, + "uvicorn": { + "hashes": [ + "sha256:890b00f6c537d58695d3bb1f28e23db9d9e7a17cbcc76d7457c499935f933e24", + "sha256:c855578045d45625fd027367f7653d249f7c49f9361ba15cf9624186b26b8eb6" + ], + "version": "==0.27.0" + }, "validators": { "hashes": [ "sha256:24148ce4e64100a2d5e267233e23e7afeb55316b47d30faae7eb6e7292bc226a" diff --git a/bruno_onisep_explorer/bruno.json b/bruno_onisep_explorer/bruno.json new file mode 100644 index 0000000..de8c91e --- /dev/null +++ b/bruno_onisep_explorer/bruno.json @@ -0,0 +1,5 @@ +{ + "version": "1", + "name": "bruno_onisep_explorer", + "type": "collection" +} \ No newline at end of file diff --git a/bruno_onisep_explorer/geMainFormations.bru b/bruno_onisep_explorer/geMainFormations.bru new file mode 100644 index 0000000..7f61eb0 --- /dev/null +++ b/bruno_onisep_explorer/geMainFormations.bru @@ -0,0 +1,22 @@ +meta { + name: geMainFormations + type: http + seq: 1 +} + +post { + url: http://127.0.0.1:5005/api/v1/formations/ + body: json + auth: none +} + +headers { + Content-Type: application/json +} + +body:json { + { + "offset": 0, + "limit": 10 + } +} diff --git a/bruno_onisep_explorer/searchFormation.bru b/bruno_onisep_explorer/searchFormation.bru new file mode 100644 index 0000000..63977fe --- /dev/null +++ b/bruno_onisep_explorer/searchFormation.bru @@ -0,0 +1,23 @@ +meta { + name: searchFormation + type: http + seq: 2 +} + +post { + url: http://localhost:5005/api/v1/formations/search + body: json + auth: none +} + +headers { + Content-Type: application/json +} + +body:json { + { + "limit": 10, + "offset": 0, + "query": "BTS SIO" + } +} diff --git a/requirements.txt b/requirements.txt index 958b9db..e977854 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,7 +12,7 @@ click==8.1.7 coverage==7.4.0 decorator==5.1.1 factory-boy==3.3.0 -Faker==22.4.0 +Faker==22.5.0 flasgger==0.9.5 Flask==2.2.2 Flask-Cors==3.0.10 @@ -34,7 +34,7 @@ jsonschema==4.21.1 jsonschema-specifications==2023.12.1 libcst==1.1.0 loguru==0.6.0 -Mako==1.3.0 +Mako==1.3.1 markdown-it-py==3.0.0 MarkupSafe==2.1.4 marshmallow==3.20.2 @@ -70,14 +70,14 @@ sniffio==1.3.0 soupsieve==2.5 SQLAlchemy==2.0.25 SQLAlchemy-serializer==1.4.1 -starlette==0.35.1 -strawberry-graphql==0.217.1 +starlette==0.36.1 +strawberry-graphql==0.218.0 termcolor==2.4.0 typer==0.9.0 typing-inspect==0.9.0 typing_extensions==4.9.0 urllib3==2.1.0 -uvicorn==0.26.0 +uvicorn==0.27.0 validators==0.20.0 Werkzeug==2.2.2 xmltodict==0.13.0 diff --git a/src/__init__.py b/src/__init__.py index 8c5cfd5..564d5d1 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -63,12 +63,14 @@ def register_blueprints(app: Flask): from src.blueprints.formations import formations from src.blueprints.utils import utils from src.blueprints.legal.views import legal + from src.blueprints.graphql import graphql app.register_blueprint(utils) app.register_blueprint(auth) app.register_blueprint(legal) app.register_blueprint(favoris) app.register_blueprint(formations) + app.register_blueprint(graphql) def _set_log_levels(): diff --git a/src/api/schema.py b/src/api/schema.py new file mode 100644 index 0000000..8708dd7 --- /dev/null +++ b/src/api/schema.py @@ -0,0 +1,24 @@ +import strawberry +from strawberry.extensions import MaxAliasesLimiter, MaxTokensLimiter, QueryDepthLimiter + + +@strawberry.type +class Book: + title: str + author: str + + +@strawberry.type +class Query: + books: list[Book] + + +schema = strawberry.Schema( + query=Query, + extensions=[ + QueryDepthLimiter(max_depth=10), + MaxTokensLimiter(max_token_count=1000), + MaxAliasesLimiter(max_alias_count=15), + ], +) +# https://strawberry.rocks/docs/guides/tools diff --git a/src/blueprints/graphql.py b/src/blueprints/graphql.py new file mode 100644 index 0000000..eeaf12e --- /dev/null +++ b/src/blueprints/graphql.py @@ -0,0 +1,12 @@ +from flask import Blueprint, Response +from strawberry.flask.views import GraphQLView + +from src.api.schema import schema + +graphql = Blueprint("graphql", __name__, url_prefix="/api/graphql") + + +@graphql.route("/", methods=["POST", "GET"]) +def gql() -> tuple[Response, int]: + view = GraphQLView.as_view("graphql_view", schema=schema) + return view() diff --git a/src/business_logic/formation/get_formation_details.py b/src/business_logic/formation/get_formation_details.py index a13e312..3a69054 100644 --- a/src/business_logic/formation/get_formation_details.py +++ b/src/business_logic/formation/get_formation_details.py @@ -1,7 +1,9 @@ from dataclasses import dataclass -from datetime import date +from datetime import date, datetime import json from typing import Any, Optional + +import strawberry from src.business_logic.formation.exceptions import ProcessFormationException from src.business_logic.formation.job.get_job_by_formation import Job, process_jobs from src.business_logic.formation.parcoursup.get_parcoursup_expectations import ( @@ -16,9 +18,12 @@ process_continuation_studies, ) +DATE_FORMAT = "%d/%m/%Y" + @dataclass -class Formation: +@strawberry.type +class FormationDetail: id: str exceptions: Optional[ParcourSupExpectations] duree: str @@ -29,7 +34,7 @@ class Formation: type: str jobs: Optional[list[Job]] continuation_studies: Optional[ContinuationOfStudies] - updated_at: date + updated_at: Optional[date] def _filter_by_link(formations: list[dict[str, Any]], for_id: str) -> dict[str, Any]: @@ -45,7 +50,7 @@ def _read_json_formation(for_id: str) -> Optional[dict[str, Any]]: return result if len(result) > 0 else None -def _process_formation(for_id: str) -> Formation: +def _process_formation(for_id: str) -> FormationDetail: formation = _read_json_formation(for_id) if formation: @@ -68,8 +73,10 @@ def _process_formation(for_id: str) -> Formation: continuation_studies = process_continuation_studies( poursuite_etudes if poursuite_etudes else None ) - updated_at = formation["modification_date"] - return Formation( + updated_at = datetime.strptime( + formation["modification_date"], DATE_FORMAT + ).date() + return FormationDetail( id=identifiant, exceptions=exceptions, duree=duree, @@ -84,10 +91,10 @@ def _process_formation(for_id: str) -> Formation: ) -def get_formation_by_id(for_id: str) -> Formation: +def get_formation_by_id(for_id: str) -> FormationDetail: try: return _process_formation(for_id) except Exception as e: raise ProcessFormationException( - "Error during formation processing : " + e + "Error during formation processing : " + str(e) ) from e diff --git a/src/business_logic/formation/job/get_job_by_formation.py b/src/business_logic/formation/job/get_job_by_formation.py index 2ba9d8d..5d72748 100644 --- a/src/business_logic/formation/job/get_job_by_formation.py +++ b/src/business_logic/formation/job/get_job_by_formation.py @@ -1,6 +1,9 @@ from dataclasses import dataclass +import strawberry + +@strawberry.type @dataclass class Job: id: str diff --git a/src/business_logic/formation/parcoursup/helper/html_parser.py b/src/business_logic/formation/parcoursup/helper/html_parser.py index 87e3813..837acd1 100644 --- a/src/business_logic/formation/parcoursup/helper/html_parser.py +++ b/src/business_logic/formation/parcoursup/helper/html_parser.py @@ -1,14 +1,17 @@ from dataclasses import dataclass, field from typing import Optional from bs4 import BeautifulSoup +import strawberry +@strawberry.type @dataclass class Expectation: title: str sub_expectations: Optional[list[str]] = field(default_factory=list) +@strawberry.type @dataclass class ParcourSupExpectations: title: str @@ -67,4 +70,4 @@ def parse_html(self) -> ParcourSupExpectations: title = self._extract_title() expectations = self._extract_expectations() - return ParcourSupExpectations(title, expectations) + return ParcourSupExpectations(title=title, expectations=expectations) diff --git a/src/business_logic/formation/scrap/types.py b/src/business_logic/formation/scrap/types.py index 3f9d5e8..03225b8 100644 --- a/src/business_logic/formation/scrap/types.py +++ b/src/business_logic/formation/scrap/types.py @@ -1,20 +1,25 @@ from dataclasses import dataclass +import strawberry + from src.models.formation import Formation +@strawberry.type @dataclass class Facet: key: str doc_count: int +@strawberry.type @dataclass class FormationIsFavorite: formation: Formation is_favorite: bool +@strawberry.type @dataclass class FormationsWithTotal: total: int diff --git a/src/business_logic/formation/study/get_continuation_of_study.py b/src/business_logic/formation/study/get_continuation_of_study.py index 03c3b12..5c72d3f 100644 --- a/src/business_logic/formation/study/get_continuation_of_study.py +++ b/src/business_logic/formation/study/get_continuation_of_study.py @@ -1,7 +1,10 @@ from dataclasses import dataclass, field from typing import Optional +import strawberry + +@strawberry.type @dataclass class ContinuationOfStudies: title: str = "" diff --git a/src/models/base_model.py b/src/models/base_model.py index 970acc6..3cbab8b 100644 --- a/src/models/base_model.py +++ b/src/models/base_model.py @@ -7,6 +7,8 @@ class BaseModel(Model): __abstract__: bool = True + __allow_unmapped__: bool = True + created_at = Column(DateTime, nullable=False, default=func.now()) updated_at = Column( DateTime, nullable=False, default=func.now(), onupdate=func.now() diff --git a/src/models/formation.py b/src/models/formation.py index e215526..1f2c2ad 100644 --- a/src/models/formation.py +++ b/src/models/formation.py @@ -1,6 +1,7 @@ import uuid from sqlalchemy import Column, Integer, String, Text +import strawberry from src.models.base_model import BaseModel from src.models.helpers.UUIDType import UUIDType @@ -11,19 +12,20 @@ def default_uuid5(): return uuid.uuid5(namespace, name) +@strawberry.type class Formation(BaseModel): __tablename__ = "formation" - id = Column( + id: uuid.UUID = Column( UUIDType, default=default_uuid5, primary_key=True, ) - code_nsf = Column(Integer, nullable=False) - type = Column(String(255), nullable=False) - libelle = Column(String(255), nullable=False) - tutelle = Column(String(255), nullable=False) - url = Column(String(255), nullable=False, unique=True) - domain = Column(Text, nullable=False) - niveau_de_sortie = Column(String(255), nullable=False) - duree = Column(String(255), nullable=False) + code_nsf: int = Column(Integer, nullable=False) + type: str = Column(String(255), nullable=False) + libelle: str = Column(String(255), nullable=False) + tutelle: str = Column(String(255), nullable=False) + url: str = Column(String(255), nullable=False, unique=True) + domain: str = Column(Text, nullable=False) + niveau_de_sortie: str = Column(String(255), nullable=False) + duree: str = Column(String(255), nullable=False) diff --git a/src/models/user.py b/src/models/user.py index 63ce745..1b09c98 100644 --- a/src/models/user.py +++ b/src/models/user.py @@ -1,6 +1,7 @@ -from dataclasses import dataclass +from typing import Optional from sqlalchemy import Column, Integer, String, Text +import strawberry from src.models.base_model import BaseModel from src.models.user_favori import UserFavori from sqlalchemy.orm import relationship @@ -9,22 +10,17 @@ # Create User row -@dataclass +@strawberry.type class User(BaseModel): __tablename__ = "user" - id: int - username: str - email: str - profile_pic_url: str - - id = Column(Integer, primary_key=True) - username = Column(String(80), unique=True, nullable=False) - email = Column(String(200), unique=True, nullable=False) + id: int = Column(Integer, primary_key=True) + username: str = Column(String(80), unique=True, nullable=False) + email: str = Column(String(200), unique=True, nullable=False) password = Column(Text(), nullable=False) - profile_pic_url = Column(Text) + profile_pic_url: Optional[str] = Column(Text) - favoris = relationship( + favoris: list[UserFavori] = relationship( "UserFavori", secondary=UserFavori.__tablename__, primaryjoin="User.id == UserFavori.user_id", diff --git a/src/models/user_favori.py b/src/models/user_favori.py index b6944dc..15e30ea 100644 --- a/src/models/user_favori.py +++ b/src/models/user_favori.py @@ -1,5 +1,6 @@ from sqlalchemy import Column, ForeignKey, Integer from src.models.base_model import BaseModel +from src.models import Formation from src.models.helpers.UUIDType import UUIDType from sqlalchemy_serializer import SerializerMixin from sqlalchemy.orm import relationship @@ -25,4 +26,4 @@ class UserFavori(BaseModel, SerializerMixin): ) users = relationship("User", back_populates="favoris") - formation = relationship("Formation") + formation: list[Formation] = relationship("Formation")