mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-04-28 10:26:33 +02:00
Initial commit
This commit is contained in:
commit
55332d1ddb
168 changed files with 18456 additions and 0 deletions
4
apps/api/.env.example
Normal file
4
apps/api/.env.example
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
DB_URL=supabase_url
|
||||
DB_API_KEY=supabase_api_key
|
||||
DB_EMAIl=email_address
|
||||
DB_PASSWORD=password
|
||||
13
apps/api/.vscode/launch.json
vendored
Normal file
13
apps/api/.vscode/launch.json
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Python: FastAPI",
|
||||
"type": "debugpy",
|
||||
"request": "launch",
|
||||
"module": "uvicorn",
|
||||
"args": ["src.main:app", "--reload"],
|
||||
"jinja": true
|
||||
}
|
||||
]
|
||||
}
|
||||
5
apps/api/.vscode/settings.json
vendored
Normal file
5
apps/api/.vscode/settings.json
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"python.testing.pytestArgs": ["tests"],
|
||||
"python.testing.unittestEnabled": false,
|
||||
"python.testing.pytestEnabled": true
|
||||
}
|
||||
8
apps/api/README.md
Normal file
8
apps/api/README.md
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
Generate requirements.txt using Poetry package manager:
|
||||
|
||||
```
|
||||
poetry export --without-hashes --format=requirements.txt > requirements.txt
|
||||
```
|
||||
|
||||
Python monorepo info:
|
||||
https://medium.com/@ashley.e.shultz/python-mono-repo-with-only-built-in-tooling-7c2d52c2fc66
|
||||
78
apps/api/harry-potter-db-seed-spells.csv
Normal file
78
apps/api/harry-potter-db-seed-spells.csv
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
id,name,description
|
||||
c76a2922-ba4c-4278-baab-44defb631236,Aberto,Opens locked doors
|
||||
06485500-d023-4799-93fd-77f2c3341aa3,Accio,Summons objects
|
||||
acbc0ae1-12e1-4813-b51e-09d22de40475,Aguamenti,Summons water
|
||||
c9d2f389-a419-4f7e-8d3d-254959638019,Alohomora,Unlocks objects
|
||||
018429a5-15d5-41af-bf8f-98a966733d77,Anapneo,Clears someone's airway
|
||||
c828685c-52d2-466d-bcc6-fbcd8376cfb5,Aparecium,Reveals secret written messages
|
||||
7fdd393c-2608-4ef3-9fd0-f691ad6f8b88,Apparate,A non-verbal transportation spell that allows a witch or wizard to instantly travel on the spot and appear at another location (disapparate is the opposite)
|
||||
73886d47-2808-4861-ae40-956f4cb56272,Ascendio,Propells someone into the air
|
||||
9a6b6854-8858-4b21-b761-12526a154597,Avada Kedavra,"Also known as The Killing Curse, the most evil spell in the Wizarding World; one of three Unforgivable Curses; Harry Potter is the only known witch or wizard to survive it"
|
||||
b6f20bba-c0db-4ad2-8ac6-2a375a596287,Avis,Conjures a small flock of birds
|
||||
48edfe4d-ddfc-49ac-8065-bd7e73c73778,Bat,Bogey Hex - Turns the target's boogers into bats
|
||||
6bd8d5c1-9375-4b70-8d6e-ad019176c7a2,Bombardo,Creates an explosion
|
||||
8fc19d10-3130-4b85-95c1-f2a51ba5ee3c,Brackium Emendo,Heals broken bones
|
||||
f08c17fa-7bf9-49bf-9fba-a7806815bc80,Capacious Extremis,"Known as the Extension Charm, it's a complicated spell that can greatly expand or extend the capacity of an object or space without affecting it externally"
|
||||
55dec867-ac07-4975-94c7-090f6fd25c86,Confundo,"Known as the Confundus Charm, it causes confusion of the target"
|
||||
816d9fee-b78f-47b4-be46-b48626c013f9,Conjunctivitis Curse,Affects the eyes and sight of a target
|
||||
58b8727a-6c0c-469c-b91d-8ac0cc0dd2d8,Crinus Muto,Changes hair color and style
|
||||
f1e91049-e866-4f6f-9d87-d6fd366aecbf,Crucio,"One of three Unforgivable Curses, it causes unbearable pain in the target"
|
||||
7324e645-8f41-4c83-a367-0d10a72906ff,Diffindo,Used to precisely cut an object
|
||||
638072b9-b7ac-405d-914b-d9293c5f9d25,Disillusionment Charm,Causes the target to take on the appearance of its surroundings
|
||||
b7643e32-ef9c-41b8-83f2-03f6b5015e04,Disapparate,A non-verbal transportation spell that allows a witch or wizard to instantly travel on the spot and leave for another location (apparate is the opposite)
|
||||
20476c31-4f27-49ac-876f-a4c4028f1b5b,Engorgio,Causes rapid growth in the targeted object
|
||||
ecb9a882-d6d7-495e-9958-a1a06902bb65,Episkey,Heals minor injuries
|
||||
317ff981-ad65-421e-92fb-5f6647d95232,Expecto patronum,"The Patronus Charm is a powerful projection of hope and happiness that drives away Dementors; a corpeal Patronus takes the the respective animal form of the caster, while a non-corpeal appears as a wisp of light; at 13, Harry Potter was the youngest known witch or wizard to prouduce a corpeal Patronus"
|
||||
60149246-91cf-44a5-8885-78a7acc4bf90,Erecto,"Allows a witch or wizard to build a structure, like a tent"
|
||||
6d8138c3-0773-4c23-b0bf-aab0e5c6fd95,Evanesco,Vanishes objects
|
||||
678474e6-fb30-4bf0-a18c-228f6b36592d,Expelliarmus,Forces an opponent to drop whatever's in their possession
|
||||
31b38b6c-4775-4e20-815d-dbf302433de6,Ferula,A healing charm that conjures wraps and bandages for wounds
|
||||
37d262c9-28ab-408f-9576-acf54ce50203,Fidelius Charm,"A complex charm that conceals a secret into the soul of a chosen ""Secret Keeper"". If a location is the subject of concealment, it becomes undetectable to others"
|
||||
9121b557-0ebf-4b60-a119-9d1c5ff05dee,Fiendfyre Curse,"Conjures destructive, enormous enchanted flames"
|
||||
de23025f-5e6a-4ec3-b827-5c526a922a89,Finite Incantatem,A general counter-spell that's used to reverse or counter already cast charms
|
||||
d536cbe5-bc0f-49e5-b063-e02c231a3988,Furnunculus Curse,A jinx that causes a breakout of boils or pimples
|
||||
7915b07a-d26e-4057-9083-e457643e57a6,Geminio,Duplicates objects
|
||||
2a942514-7a19-4f0e-9353-171c573abcba,Glisseo,Transforms a staircase into a slide
|
||||
a42028b6-67f5-463b-b759-452103533227,Homenum Revelio,Reveals the presence of another person
|
||||
552cd4ee-2c67-48fd-ae20-a83773262a8a,Homonculus Charm,Detects anyone's true identity and location on a piece of parchment; used to create the Marauder's Map
|
||||
2dfca7d2-ec9b-4150-b3f3-fd972a5fd1bc,Immobulus,Immobilises living targets
|
||||
a49300cc-ddbf-4ff4-b8c2-e8bddbbe4118,Impedimenta,A temporary jinx that slows the movement of the target
|
||||
e5c22d31-26f1-4c88-a586-d9c09cb88c1f,Incarcerous,Conjures ropes
|
||||
a53ad5be-00ee-4254-b3c0-4cec60b0c034,Imperio,"One of the three Unforgivable Curses, it places the target under the complete control of the caster"
|
||||
a3b34bf6-1ff7-4fe3-81ee-e617150f5da9,Impervius,Makes an object waterproof
|
||||
de048df0-b227-4376-a29b-90fe6878d950,Incendio,Conjures flames
|
||||
c4a4520b-b80d-49e8-9e5a-3ca0a7f376ca,Langlock,Causes the target's tongue to stick to the roof of their mouth
|
||||
0da7cb76-dabc-46ff-b8e9-c23a4f03caea,Legilimens,Invading or navigating another's mind
|
||||
723dd9c9-ee62-495b-9071-cddd16087b86,Levicorpus,Levitates the target by their ankle
|
||||
8add16ef-b4b1-4e2b-a91e-80aa194da438,Locomotor Mortis,The Leg-Locker curse bounds the target's legs
|
||||
3b7a10ce-3339-4a36-9493-292c8775e47b,Lumos,Illuminates the caster's wand
|
||||
832edaca-dbff-4a57-80c7-1d8a827c8416,Morsmordre,Conjures and projects Lord Voldemort's Dark Mark
|
||||
7f4b43e0-3356-43f9-9299-15ec37cfaf76,Mucus Ad Nauseam,Inflicts an extreme runny nose or cold
|
||||
f86bbf7e-94ea-4c22-89fb-809af8214a85,Muffliato,Creates a buzzing sound in the target's ears to prevent eavesdropping
|
||||
66be613d-532c-46d8-a3e9-f5a2d9cccf0c,Nox,"Reverses the lumos charm, extinguishing a wand's light"
|
||||
9e3c0217-652a-4763-82f8-5519026a1ea6,Obliviate,Erases the target's memory
|
||||
0af49753-c8ae-4748-87a7-b7cfc47d33a0,Obscuro,Conjures a blindfold
|
||||
67e838c1-4623-414e-9a91-12125631dbad,Oculus Reparo,Repairs eyeglasses
|
||||
12251f32-af9d-408f-a652-3a4cc9602bc0,Oppugno,Directs an object or person to attack a victim
|
||||
da9eab7b-2c7c-42de-861c-fb254bd9423c,Petrificus Totalus,Temporarily freezes or petrifies the body of the target
|
||||
3e5fd245-2ecf-40c4-937d-b2c2f9eee003,Periculum,Conjures flares/red sparks
|
||||
ad5685f8-6e05-49b1-a41c-d72786001d72,Piertotum Locomotor,Incantation used to bring to life inanimate objects and artifacts
|
||||
0a267162-0594-4372-a3d5-89382926f495,Protean Charm,Links objects together for better communication
|
||||
8808aa30-39f4-400c-a0e5-1dcbad657931,Protego,"Casts an invisible shield around the caster, protecting against spells and objects (except for The Killing Curse)"
|
||||
56742dd7-3c93-4085-bea3-971e88d81dc2,Reducto,Reduces the target to pieces
|
||||
2f177949-1f80-4663-9840-da8197411f2a,Reducio,Shrinks an enlarged object to its regular size
|
||||
358ecb3c-e684-492c-b706-47cbd1eae02e,Renneverate,Awakens or revives the target
|
||||
1b7a8a4c-8d4f-4001-8155-e68f1198ef72,Reparifors,Heals magical ailments like poisoning or paralysis
|
||||
799f31a3-799e-411f-b67c-a64e48a5f503,Reparo,Fixes broken objects
|
||||
32dbeb89-0978-4037-ab1b-413d62be02c3,Rictusempra,A charm that disarms an opponent by tickling them
|
||||
c9dc8bed-5834-4001-8fa1-852690d027f2,Riddikulus,"Used to defeat a Boggart, the charm allows the scary creature to assume a comedic form, disarming it"
|
||||
14c47e18-cbf3-4aec-afd3-5473d18ee7c0,Scourgify,Cleans objects
|
||||
3617c34c-e650-4e3b-a13a-651d18471225,Sectumsempra,Inflicts severe lacerations and haemorrhaging on the target
|
||||
53747fb8-bdab-466e-90fb-ca75c66f3dd9,Serpensortia,Conjures a live snake
|
||||
43d3d53e-7ab9-4145-bda7-d96be99c5d31,Silencio,Silences the target
|
||||
d5f71164-fa43-4566-b537-8852859bde01,Sonorus,Amplifies the witch or wizard's voice
|
||||
9ec3258c-bc2f-4427-8440-ebea450a44aa,Spongify,Softens the target
|
||||
37110a48-07e3-4fd7-9aae-ac1145161e1e,Stupefy,The Stunning spell freezes objects and renders living targets unconscious
|
||||
daeb6f2a-5aff-43e1-964a-a06da7f66a3c,Tarantallegra,"Aimed at the legs, causes uncontrollable dancing movement"
|
||||
4eaa6532-3ef2-428d-922f-101aee3d66ed,Unbreakable Vow,A magically binding contract that results in the death of whoever breaks it
|
||||
e23728b2-f6fd-4c70-a1d2-ce602940d873,Wingardium Leviosa,"Causes an object to levitate; but remember what Hermione said: ""It's Wing-gar-dium Levi-o-sa, make the 'gar' nice and long.'"""
|
||||
|
114
apps/api/harry-potter-db-seed-users.csv
Normal file
114
apps/api/harry-potter-db-seed-users.csv
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
id,forename,surname,email
|
||||
fd142190-f1d7-4ce2-bdb3-6ed6b3edc020,Patricia,Stimpson,patriciastimpson@hogwarts.com
|
||||
f94086b8-03ae-4457-ba2c-e624d0980869,Lavender,Brown,lavenderbrown@hogwarts.com
|
||||
ecca342d-d345-4fb3-8a85-ece848ab8938,Milicent,Bullstroude,milicentbullstroude@hogwarts.com
|
||||
ec714982-e604-40d4-bd4c-dc5155506957,Morag,MacDougal,moragmacdougal@hogwarts.com
|
||||
eaea5eb3-48a3-41c6-9ea5-c695299bab16,Lisa,Turpin,lisaturpin@hogwarts.com
|
||||
e7f4554e-8193-4b16-a40b-a8b38a0c3e57,Graham,Montague,grahammontague@hogwarts.com
|
||||
e65c8acb-0dfc-4f15-bcf8-d32b78811093,Rose,Zeller,rosezeller@hogwarts.com
|
||||
e4653b01-76a5-4769-a6a2-1f2efaf89cbb,Rose,Weasley,roseweasley@hogwarts.com
|
||||
e32dd37c-91cd-4950-8ef2-e2ba1b87bd75,Lily,Moon,lilymoon@hogwarts.com
|
||||
dcdc063e-cf3e-48fc-b777-65922e899b38,Albus,Severus,albusseverus@hogwarts.com
|
||||
d9cec110-a1d0-4437-9a55-dced475dfe6d,Andrew,Kirke,andrewkirke@hogwarts.com
|
||||
d5c4daa3-c726-426a-aa98-fb40f3fba816,Cedric,Diggory,cedricdiggory@hogwarts.com
|
||||
cf3707ad-e816-4b54-90d0-403800a06ecd,Emma,Dobbs,emmadobbs@hogwarts.com
|
||||
cb263aed-289b-43ad-8647-db54b8a5fc92,Michael,Corner,michaelcorner@hogwarts.com
|
||||
c8aed011-ab8f-46df-9e8d-dde938256ea9,Miles,Bletchley,milesbletchley@hogwarts.com
|
||||
c74b1fae-4793-4b47-bec2-ee652beabce2,Ritchie,Coote,ritchiecoote@hogwarts.com
|
||||
c61b5c80-2c8e-404f-88ca-349a6344f35c,Cassius,Warrington,cassiuswarrington@hogwarts.com
|
||||
c5acae3e-1a05-4f1d-bb83-3f8c7639d84e,Mandy,Brocklehurst,mandybrocklehurst@hogwarts.com
|
||||
c3b1f9a5-b87b-48bf-b00d-95b093ea6390,Ron,Weasley,ronweasley@hogwarts.com
|
||||
c29cd5f9-d2c3-4be9-ba1c-04169cdf511b,Alicia,Spinet,aliciaspinet@hogwarts.com
|
||||
bff82738-5bb0-4edc-9cec-f80d1af4801f,Vicky,Frobisher,vickyfrobisher@hogwarts.com
|
||||
b78e6677-8bb4-4eb7-97cb-2f86677e27ea,Adrian,Pucey,adrianpucey@hogwarts.com
|
||||
b634f0a1-7b48-49b6-b039-27f947ee76fd,Angelina,Johnson,angelinajohnson@hogwarts.com
|
||||
b01be346-290b-4f65-9c88-a49922e116ee,Orla,Quirke,orlaquirke@hogwarts.com
|
||||
af95bd8a-dfae-45bb-bc69-533860d34129,Draco,Malfoy,dracomalfoy@hogwarts.com
|
||||
ae068570-8419-4063-bf61-ba4a0ef41fe3,Laura,Madley,lauramadley@hogwarts.com
|
||||
a93b80a0-987d-4148-944d-16043df95e8c,Dennis,Creevey,denniscreevey@hogwarts.com
|
||||
a506574f-c8cf-46c6-a8ac-2f805c25e49e,Graham,Pritchard,grahampritchard@hogwarts.com
|
||||
a3e5ea64-b103-4f47-bc26-dc08b799c668,Eddie,Carmichael,eddiecarmichael@hogwarts.com
|
||||
a31ddc78-af12-4978-929c-3cc8a00a833e,Gregory,Goyle,gregorygoyle@hogwarts.com
|
||||
a01f6dbb-bad5-426b-a7df-f9613fa1021d,Euan,Abercrombie,euanabercrombie@hogwarts.com
|
||||
9e3f7ce4-b9a7-4244-b709-dae5c1f1d4a8,Harry,Potter,harrypotter@hogwarts.com
|
||||
9c8ce8c7-ae0a-4646-920f-09c071862f10,James,Potter,jamespotter@hogwarts.com
|
||||
9ba0ca6e-4fba-410d-9b5e-e20694dde413,Melinda,Bobbin,melindabobbin@hogwarts.com
|
||||
9ac09267-92ea-444a-a395-28f3b0f6fe6f,Terrence,Higgs,terrencehiggs@hogwarts.com
|
||||
98546bab-8d5b-4627-95f6-38e306d58a91,Owen,Cauldwell,owencauldwell@hogwarts.com
|
||||
979ab773-944f-4ff8-88be-943a4bc2c18a,Lee,Jordan,leejordan@hogwarts.com
|
||||
938559ee-e8e5-4963-8437-e7da04fd1b31,Marcus,Belby,marcusbelby@hogwarts.com
|
||||
9055a7b1-6ac9-4363-977c-4dec78572fad,Terry,Boot,terryboot@hogwarts.com
|
||||
8f9aa40b-5d7c-441e-ad32-4564ecda3b70,Cho,Chang,chochang@hogwarts.com
|
||||
8f3b8796-c7b9-442e-ac02-113d48306fc7,Percy,Weasley,percyweasley@hogwarts.com
|
||||
8e557e86-28d5-433f-8ac1-d2cecfeb8fb7,Colin,Creevey,colincreevey@hogwarts.com
|
||||
88886e27-9ce2-416f-9dd6-56d4cd94a4fb,Geoffrey,Hooper,geoffreyhooper@hogwarts.com
|
||||
861c4cde-2f0f-4796-8d8f-9492e74b2573,Luna,Lovegood,lunalovegood@hogwarts.com
|
||||
7f2f6207-8998-4f98-92c2-8d02898a82eb,Scorpius,Malfoy,scorpiusmalfoy@hogwarts.com
|
||||
7cc5e694-850d-4c44-830b-7154e23bb5c3,Susan,Bones,susanbones@hogwarts.com
|
||||
781f1061-5413-40c7-8a35-b078e2e969b1,Barnabas,the,barnabasthe@hogwarts.com
|
||||
7772cb4e-5c33-405a-970d-c05cae167917,Daphne,Greengrass,daphnegreengrass@hogwarts.com
|
||||
6fa93583-b935-4228-91e0-729e6713bdab,Zacharias,Smith,zachariassmith@hogwarts.com
|
||||
6c4350a9-2356-4bba-96bd-0458c12d99b5,Romilda,Vane,romildavane@hogwarts.com
|
||||
69c18f6a-cd97-4218-9f2f-740393e6eb1f,Padma,Patil,padmapatil@hogwarts.com
|
||||
61b6d68e-4128-408c-9f71-9ef167cb0e69,Anthony,Goldstein,anthonygoldstein@hogwarts.com
|
||||
58a287c2-8c7a-485a-b095-8c6dcfc7f31d,Lucian,Bole,lucianbole@hogwarts.com
|
||||
57fe29d4-312a-4711-bd9a-c320253d9176,Victoire,Weasley,victoireweasley@hogwarts.com
|
||||
575fbbc2-ac94-4c58-92f6-e5d75846da91,Jack,Sloper,jacksloper@hogwarts.com
|
||||
4eef1e03-cf1c-4441-9119-a6e47a61f880,Kevin,Whitby,kevinwhitby@hogwarts.com
|
||||
4c7e6819-a91a-45b2-a454-f931e4a7cce3,Hermione,Granger,hermionegranger@hogwarts.com
|
||||
4a0f4c3b-14dc-4a9e-a2f8-da23734f5d34,Marietta,Edgecombe,mariettaedgecombe@hogwarts.com
|
||||
48880498-3903-4914-bd11-ec650d803199,Natalie,McDonald,nataliemcdonald@hogwarts.com
|
||||
47aa7511-59b9-4760-9bd7-822a1103177b,Theodore,Nott,theodorenott@hogwarts.com
|
||||
458828b3-82a5-4cad-a784-e23215825765,Peregrine,Derrick,peregrinederrick@hogwarts.com
|
||||
42915280-ba56-4ab8-8b17-9511ba2ab093,Penelope,Clearwater,penelopeclearwater@hogwarts.com
|
||||
3db6dc51-b461-4fa4-a6e4-b1ff352221c5,Neville,Longbottom,nevillelongbottom@hogwarts.com
|
||||
3d629315-1dbb-4e1e-840d-ffbf45bd5894,Sally-Anne,Perks,sally-anneperks@hogwarts.com
|
||||
341e65d4-6917-48d7-80b2-1f9af607e95a,Cormac,McLaggen,cormacmclaggen@hogwarts.com
|
||||
34155375-c8c0-415e-873a-b6483f0cbf17,Justin,Finch-Fletchley,justinfinch-fletchley@hogwarts.com
|
||||
2f8db183-e935-4b91-884f-fb9effe42ab8,Malcolm,Baddock,malcolmbaddock@hogwarts.com
|
||||
2b203c7e-7b3d-4f27-8b3c-11473904da73,Hugo,Weasley,hugoweasley@hogwarts.com
|
||||
2a0615de-8aa4-41e7-9504-dd875f5f3f01,George,Weasley,georgeweasley@hogwarts.com
|
||||
29adbbf0-417a-4c97-8467-adb5341f75e5,Eleanor,Branstone,eleanorbranstone@hogwarts.com
|
||||
28e9fe6b-3ca5-41ca-8a14-b995e0fb398b,Jimmy,Peakes,jimmypeakes@hogwarts.com
|
||||
2899e63f-ed02-4152-8ace-0270a068a70d,Pansy,Parkinson,pansyparkinson@hogwarts.com
|
||||
28741184-263c-4000-b011-ca7c60466ef4,Fred,Weasley,fredweasley@hogwarts.com
|
||||
2832bea8-7aad-4160-a748-442f5770d586,Katie,Bell,katiebell@hogwarts.com
|
||||
26bd4437-73fa-4865-afdd-2fc1456f4592,Kenneth,Towler,kennethtowler@hogwarts.com
|
||||
1fab149b-52b1-4ffe-be52-4eda25d98f5d,Blaise,Zabini,blaisezabini@hogwarts.com
|
||||
1cd6dc64-01a9-4379-9cfd-1a7167ba1bb1,Ginny,Weasley,ginnyweasley@hogwarts.com
|
||||
14aca981-2b60-413e-8f8e-3534961b534b,Millicent,Bulstrode,millicentbulstrode@hogwarts.com
|
||||
1413e1b3-2903-4a47-a2d5-e8abc5ce8014,Seamus,Finnigan,seamusfinnigan@hogwarts.com
|
||||
13a54f8a-7f68-4add-a1b4-49f60c8e7bcc,Eloise,Midgen,eloisemidgen@hogwarts.com
|
||||
0e53860c-7679-49e4-891e-fb92286f0e5b,Demelza,Robins,demelzarobins@hogwarts.com
|
||||
0e42ecbe-27b2-4940-9b03-00182a92c415,Marcus,Flint,marcusflint@hogwarts.com
|
||||
0c80d701-fa23-4126-9711-efe5f3c4789a,Ernie,Macmillan,erniemacmillan@hogwarts.com
|
||||
0af82694-e24f-45ec-a8d7-5bb1199ce631,Hannah,Abbott,hannahabbott@hogwarts.com
|
||||
0a13bf8e-a763-44cc-ac76-c6c53a639809,Roger,Davies,rogerdavies@hogwarts.com
|
||||
09396e81-d317-499f-b330-25b90ba17d20,Oliver,Wood,oliverwood@hogwarts.com
|
||||
05bd5fd1-f347-45e6-8ec0-59b7f11c2aec,Stewart,Ackerley,stewartackerley@hogwarts.com
|
||||
04f9eb45-d843-4e29-a7d3-0bd49ed87f85,Vincent,Crabbe,vincentcrabbe@hogwarts.com
|
||||
0201cf73-8a86-4358-b232-2abaa23f09af,Parvati,Patil,parvatipatil@hogwarts.com
|
||||
ca3827f0-375a-4891-aaa5-f5e8a5bad225,Minerva,McGonagall,minervamcgonagall@hogwarts.com
|
||||
3569d265-bd27-44d8-88e8-82fb0a848374,Severus,Snape,severussnape@hogwarts.com
|
||||
36bfefd0-e0bb-4d11-be98-d1ef6117a77a,Rubeus,Hagrid,rubeushagrid@hogwarts.com
|
||||
b8f9095b-9de6-4d7d-83e0-4391af8f22e4,Remus,Lupin,remuslupin@hogwarts.com
|
||||
2fb675cd-5505-4c8e-a54e-579e73bf4174,Horace,Slughorn,horaceslughorn@hogwarts.com
|
||||
d58e7249-19d1-40bd-a43f-1da0497fe8aa,Dolores,Umbridge,doloresumbridge@hogwarts.com
|
||||
b0620914-858d-46fc-8e6d-033c565e138b,Mrs,Norris,mrsnorris@hogwarts.com
|
||||
2b82cfb8-0440-4a57-a030-6d75a40c0d98,Argus,Filch,argusfilch@hogwarts.com
|
||||
b415c867-1cff-455e-b194-748662ac2cca,Albus,Dumbledore,albusdumbledore@hogwarts.com
|
||||
e9457467-d10a-4893-afa9-19f9602b218a,Madam,Pomfrey,madampomfrey@hogwarts.com
|
||||
ba19be27-178b-4594-95b7-51ba0e3ba1dd,Quirinus,Quirrel,quirinusquirrel@hogwarts.com
|
||||
e8694719-a975-48fb-9523-f4cade1c38aa,Pomona,Sprout,pomonasprout@hogwarts.com
|
||||
6ea188f3-d95c-407c-ab00-a0bec8678a71,Cuthbert,Binns,cuthbertbinns@hogwarts.com
|
||||
a61e0783-7914-4f8d-a800-c409c06315cf,Filius,Flitwick,filiusflitwick@hogwarts.com
|
||||
0a81c4f9-b80d-45a7-a4fd-9191453815a1,Madam,Hooch,madamhooch@hogwarts.com
|
||||
3d687c4d-852e-470f-bac5-5a02758b1f8f,Gilderoy,Lockhart,gilderoylockhart@hogwarts.com
|
||||
cdec9b95-c7a5-4623-ad12-6fa76d168588,Madame,Pince,madamepince@hogwarts.com
|
||||
8ea29415-012d-4781-ba5f-d0de63a05abe,Sybill,Trelawney,sybilltrelawney@hogwarts.com
|
||||
58f2cf41-392c-4e84-b441-dbbce585f78d,Septima,Vector,septimavector@hogwarts.com
|
||||
99d3ce6b-6a45-495a-a7c6-132203697d45,Aurora,Sinistra,aurorasinistra@hogwarts.com
|
||||
41ebe856-f0f4-4c77-8795-4735d3a87f3d,Alastor,Moody,alastormoody@hogwarts.com
|
||||
b48c5b8a-4066-4c24-ba26-7677f5ed2b6f,Wilhelmina,Grubbly-Plank,wilhelminagrubbly-plank@hogwarts.com
|
||||
c4e73590-3ee2-4125-87fb-692dd991819b,Galatea,Merrythought,galateamerrythought@hogwarts.com
|
||||
61d78dce-890b-4f02-844f-b41d66553802,Charity,Burbage,charityburbage@hogwarts.com
|
||||
|
8
apps/api/package.json
Normal file
8
apps/api/package.json
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"name": "api",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"dev": ".\\.venv\\Scripts\\python run.py",
|
||||
"generate:requirements": "poetry export --without-hashes --format=requirements.txt > requirements.txt"
|
||||
}
|
||||
}
|
||||
1789
apps/api/poetry.lock
generated
Normal file
1789
apps/api/poetry.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
3
apps/api/poetry.toml
Normal file
3
apps/api/poetry.toml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
[virtualenvs]
|
||||
in-project = true
|
||||
create = true
|
||||
24
apps/api/pyproject.toml
Normal file
24
apps/api/pyproject.toml
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
[tool.poetry]
|
||||
name = "api"
|
||||
version = "0.1.0"
|
||||
description = ""
|
||||
authors = ["cording12 <joncording12@gmail.com>"]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.9"
|
||||
fastapi = "^0.109.2"
|
||||
uvicorn = "^0.27.1"
|
||||
email-validator = "^2.1.0"
|
||||
pydantic-settings = "^2.2.1"
|
||||
python-dotenv = "^1.0.1"
|
||||
supabase-py-async = "^2.5.5"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
isort = "^5.10.1"
|
||||
black = "^22.6.0"
|
||||
pytest = "^8.0.1"
|
||||
pylint-pydantic = "^0.3.2"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
54
apps/api/requirements.txt
Normal file
54
apps/api/requirements.txt
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
aiohttp==3.9.3; python_version >= "3.9" and python_version < "4.0"
|
||||
aiosignal==1.3.1; python_version >= "3.9" and python_version < "4.0"
|
||||
annotated-types==0.6.0; python_version >= "3.8"
|
||||
anyio==4.3.0; python_version >= "3.9" and python_version < "4.0"
|
||||
argcomplete==3.2.3; python_version >= "3.9" and python_version < "4.0"
|
||||
async-timeout==4.0.3; python_version >= "3.9" and python_version < "3.11"
|
||||
attrs==23.2.0; python_version >= "3.9" and python_version < "4.0"
|
||||
certifi==2024.2.2; python_version >= "3.9" and python_version < "4.0"
|
||||
charset-normalizer==3.3.2; python_version >= "3.9" and python_version < "4.0" and python_full_version >= "3.7.0"
|
||||
click==8.1.7; python_version >= "3.8"
|
||||
colorama==0.4.6; python_version >= "3.9" and python_full_version < "3.0.0" and platform_system == "Windows" and python_version < "4.0" or platform_system == "Windows" and python_version >= "3.9" and python_full_version >= "3.7.0" and python_version < "4.0"
|
||||
commitizen==3.18.4; python_version >= "3.9" and python_version < "4.0"
|
||||
decli==0.6.1; python_version >= "3.9" and python_version < "4.0"
|
||||
deprecation==2.1.0; python_version >= "3.9" and python_version < "4.0"
|
||||
dnspython==2.6.1; python_version >= "3.8"
|
||||
email-validator==2.1.1; python_version >= "3.8"
|
||||
exceptiongroup==1.2.0; python_version < "3.11" and python_version >= "3.8"
|
||||
fastapi==0.109.2; python_version >= "3.8"
|
||||
frozenlist==1.4.1; python_version >= "3.9" and python_version < "4.0"
|
||||
gotrue==2.4.1; python_version >= "3.9" and python_version < "4.0"
|
||||
h11==0.14.0; python_version >= "3.9" and python_version < "4.0"
|
||||
httpcore==1.0.4; python_version >= "3.9" and python_version < "4.0"
|
||||
httpx==0.25.2; python_version >= "3.9" and python_version < "4.0"
|
||||
idna==3.6; python_version >= "3.9" and python_version < "4.0"
|
||||
importlib-metadata==7.0.2; python_version >= "3.9" and python_version < "4.0"
|
||||
jinja2==3.1.3; python_version >= "3.9" and python_version < "4.0"
|
||||
markupsafe==2.1.5; python_version >= "3.9" and python_version < "4.0"
|
||||
multidict==6.0.5; python_version >= "3.9" and python_version < "4.0"
|
||||
packaging==24.0; python_version >= "3.9" and python_version < "4.0"
|
||||
postgrest==0.16.1; python_version >= "3.9" and python_version < "4.0"
|
||||
prompt-toolkit==3.0.36; python_version >= "3.9" and python_version < "4.0" and python_full_version >= "3.6.2"
|
||||
pydantic-core==2.16.3; python_version >= "3.8"
|
||||
pydantic-settings==2.2.1; python_version >= "3.8"
|
||||
pydantic==2.6.4; python_version >= "3.9" and python_version < "4.0"
|
||||
python-dateutil==2.9.0.post0; python_version >= "3.9" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.9" and python_version < "4.0" and python_full_version >= "3.3.0"
|
||||
python-dotenv==1.0.1; python_version >= "3.8"
|
||||
pyyaml==6.0.1; python_version >= "3.9" and python_version < "4.0"
|
||||
questionary==2.0.1; python_version >= "3.9" and python_version < "4.0"
|
||||
realtime==1.0.2; python_version >= "3.9" and python_version < "4.0"
|
||||
six==1.16.0; python_version >= "3.9" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.9" and python_version < "4.0" and python_full_version >= "3.3.0"
|
||||
sniffio==1.3.1; python_version >= "3.9" and python_version < "4.0"
|
||||
starlette==0.36.3; python_version >= "3.8"
|
||||
storage3==0.7.3; python_version >= "3.9" and python_version < "4.0"
|
||||
strenum==0.4.15; python_version >= "3.9" and python_version < "4.0"
|
||||
supabase-py-async==2.5.5; python_version >= "3.9" and python_version < "4.0"
|
||||
supafunc==0.4.0; python_version >= "3.9" and python_version < "4.0"
|
||||
termcolor==2.4.0; python_version >= "3.9" and python_version < "4.0"
|
||||
tomlkit==0.12.4; python_version >= "3.9" and python_version < "4.0"
|
||||
typing-extensions==4.10.0; python_version < "3.10" and python_version >= "3.9"
|
||||
uvicorn==0.27.1; python_version >= "3.8"
|
||||
wcwidth==0.2.13; python_version >= "3.9" and python_version < "4.0" and python_full_version >= "3.6.2"
|
||||
websockets==11.0.3; python_version >= "3.9" and python_version < "4.0"
|
||||
yarl==1.9.4; python_version >= "3.9" and python_version < "4.0"
|
||||
zipp==3.18.1; python_version >= "3.9" and python_version < "4.0"
|
||||
4
apps/api/run.py
Normal file
4
apps/api/run.py
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
import uvicorn
|
||||
|
||||
if __name__ == "__main__":
|
||||
uvicorn.run("src.main:app", reload=True)
|
||||
1
apps/api/src/__init__.py
Normal file
1
apps/api/src/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
|||
__version__ = "0.1.0"
|
||||
0
apps/api/src/api/__init__.py
Normal file
0
apps/api/src/api/__init__.py
Normal file
0
apps/api/src/api/api_v1/__init__.py
Normal file
0
apps/api/src/api/api_v1/__init__.py
Normal file
6
apps/api/src/api/api_v1/api.py
Normal file
6
apps/api/src/api/api_v1/api.py
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
from fastapi import APIRouter
|
||||
from src.api.api_v1.endpoints import users, spells
|
||||
|
||||
api_router = APIRouter()
|
||||
api_router.include_router(users.router, prefix="/users", tags=["users"], responses={404: {"description": "Not found"}})
|
||||
api_router.include_router(spells.router, prefix="/spells", tags=["spells"], responses={404: {"description": "Not found"}})
|
||||
0
apps/api/src/api/api_v1/endpoints/__init__.py
Normal file
0
apps/api/src/api/api_v1/endpoints/__init__.py
Normal file
63
apps/api/src/api/api_v1/endpoints/spells.py
Normal file
63
apps/api/src/api/api_v1/endpoints/spells.py
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
from typing import Literal, Optional, Union
|
||||
|
||||
from fastapi import APIRouter, HTTPException
|
||||
|
||||
from src.api.deps import SessionDep
|
||||
from src.crud import spell
|
||||
from src.schemas import Spell, SpellSearchResults
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/get/", status_code=200, response_model=Spell)
|
||||
async def get_spell(session: SessionDep, spell_id: str) -> Spell:
|
||||
"""Returns a spell from a spell_id.
|
||||
|
||||
**Returns:**
|
||||
- spell: spell object.
|
||||
"""
|
||||
return await spell.get(session, id=spell_id)
|
||||
|
||||
|
||||
@router.get("/get-all/", status_code=200, response_model=list[Spell])
|
||||
async def get_all_spells(session: SessionDep) -> list[Spell]:
|
||||
"""Returns a list of all spells.
|
||||
|
||||
**Returns:**
|
||||
- list[spell]: List of all spells.
|
||||
"""
|
||||
return await spell.get_all(session)
|
||||
|
||||
|
||||
@router.get("/search/", status_code=200, response_model=SpellSearchResults)
|
||||
async def search_spells(
|
||||
session: SessionDep,
|
||||
search_on: Literal["id", "name", "description"] = "name",
|
||||
keyword: Optional[Union[str, int]] = None,
|
||||
max_results: Optional[int] = 10,
|
||||
) -> SpellSearchResults:
|
||||
"""
|
||||
Search for spells based on a keyword and return the top `max_results` items.
|
||||
|
||||
**Args:**
|
||||
- search_on (str, optional): The field to perform the search on. Defaults to "name".
|
||||
- keyword (str, optional): The keyword to search for. Defaults to None.
|
||||
- max_results (int, optional): The maximum number of search results to return. Defaults to 10.
|
||||
|
||||
**Returns:**
|
||||
- SpellSearchResults: Object containing a list of the top `max_results` items that match the keyword.
|
||||
"""
|
||||
if not keyword:
|
||||
results = await spell.get_all(session)
|
||||
return SpellSearchResults(results=results)
|
||||
|
||||
results = await spell.search_all(
|
||||
session, field=search_on, search_value=keyword, max_results=max_results
|
||||
)
|
||||
|
||||
if not results:
|
||||
raise HTTPException(
|
||||
status_code=404, detail="No spells found matching the search criteria"
|
||||
)
|
||||
|
||||
return SpellSearchResults(results=results)
|
||||
76
apps/api/src/api/api_v1/endpoints/users.py
Normal file
76
apps/api/src/api/api_v1/endpoints/users.py
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
from typing import Literal, Optional, Union
|
||||
|
||||
from fastapi import APIRouter, HTTPException
|
||||
|
||||
from src.api.deps import SessionDep
|
||||
from src.crud import user
|
||||
from src.schemas import User, UserCreate, UserSearchResults
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/get/", status_code=200, response_model=User)
|
||||
async def get_user(session: SessionDep, user_id: str) -> User:
|
||||
"""Returns a user from a user_id.
|
||||
|
||||
**Returns:**
|
||||
- User: User object.
|
||||
"""
|
||||
return await user.get(session, id=user_id)
|
||||
|
||||
|
||||
@router.get("/get-all/", status_code=200, response_model=list[User])
|
||||
async def get_all_users(session: SessionDep) -> list[User]:
|
||||
"""Returns a list of all users.
|
||||
|
||||
**Returns:**
|
||||
- list[User]: List of all users.
|
||||
"""
|
||||
return await user.get_all(session)
|
||||
|
||||
|
||||
@router.get("/search/", status_code=200, response_model=UserSearchResults)
|
||||
async def search_users(
|
||||
session: SessionDep,
|
||||
search_on: Literal["id", "email", "forename", "surname"] = "email",
|
||||
keyword: Optional[Union[str, int]] = None,
|
||||
max_results: Optional[int] = 10,
|
||||
) -> UserSearchResults:
|
||||
"""
|
||||
Search for users based on a keyword and return the top `max_results` items.
|
||||
|
||||
**Args:**
|
||||
- keyword (str, optional): The keyword to search for. Defaults to None.
|
||||
- max_results (int, optional): The maximum number of search results to return. Defaults to 10.
|
||||
- search_on (str, optional): The field to perform the search on. Defaults to "email".
|
||||
|
||||
**Returns:**
|
||||
- UserSearchResults: Object containing a list of the top `max_results` items that match the keyword.
|
||||
"""
|
||||
if not keyword:
|
||||
results = await user.get_all(session)
|
||||
return UserSearchResults(results=results)
|
||||
|
||||
results = await user.search_all(
|
||||
session, field=search_on, search_value=keyword, max_results=max_results
|
||||
)
|
||||
|
||||
if not results:
|
||||
raise HTTPException(
|
||||
status_code=404, detail="No users found matching the search criteria"
|
||||
)
|
||||
|
||||
return UserSearchResults(results=results)
|
||||
|
||||
|
||||
@router.post("/create", status_code=201, response_model=User)
|
||||
async def create_user(user_in: UserCreate, session: SessionDep) -> User:
|
||||
"""Craete a new user.
|
||||
|
||||
**Args:**
|
||||
- user_in (UserCreate): JSON of the user to create. Forename, surname and email. Email must be unique.
|
||||
|
||||
**Returns:**
|
||||
- User: User object
|
||||
"""
|
||||
return await user.create(session, obj_in=user_in)
|
||||
30
apps/api/src/api/deps.py
Normal file
30
apps/api/src/api/deps.py
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
from typing import Annotated
|
||||
|
||||
from fastapi import Depends, HTTPException
|
||||
from supabase_py_async import AsyncClient, create_client
|
||||
from supabase_py_async.lib.client_options import ClientOptions
|
||||
|
||||
from src.config import settings
|
||||
|
||||
|
||||
async def get_db() -> AsyncClient:
|
||||
client: AsyncClient | None = None
|
||||
try:
|
||||
client = await create_client(
|
||||
settings.DB_URL,
|
||||
settings.DB_API_KEY,
|
||||
options=ClientOptions(
|
||||
postgrest_client_timeout=10, storage_client_timeout=10
|
||||
),
|
||||
)
|
||||
# client = await client.auth.sign_in_with_password(
|
||||
# {"email": settings.DB_EMAIL, "password": settings.DB_PASSWORD}
|
||||
# )
|
||||
yield client
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
raise
|
||||
|
||||
|
||||
SessionDep = Annotated[AsyncClient, Depends(get_db)]
|
||||
30
apps/api/src/config.py
Normal file
30
apps/api/src/config.py
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import os
|
||||
|
||||
from dotenv import load_dotenv
|
||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||
|
||||
load_dotenv()
|
||||
|
||||
# If the environment is Gitpod, the root path will be the workspace cluster host
|
||||
# If not using gitpod, you can delete this if statement, but keep the else clause
|
||||
if os.getenv("USER") == "gitpod":
|
||||
ROOT_PATH = f"https://8000-cording12-nextfastturbo-qqfo0frc496.{os.getenv('GITPOD_WORKSPACE_CLUSTER_HOST')}"
|
||||
else:
|
||||
# Otherwise, the root path will be the local host. ROOT_PATH is an env var configured in Vercel deployment.
|
||||
# The value for production is equal to the root path of the deployment URL in Vercel.
|
||||
ROOT_PATH = os.getenv("ROOT_PATH", "http://127.0.0.1:8000")
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
PROJECT_NAME: str = "FastAPI App"
|
||||
PROJECT_DESCRIPTION: str = "A simple FastAPI app"
|
||||
DB_URL: str = os.getenv("DB_URL")
|
||||
DB_API_KEY: str = os.getenv("DB_API_KEY")
|
||||
DB_EMAIL: str = os.getenv("DB_EMAIL")
|
||||
DB_PASSWORD: str = os.getenv("DB_PASSWORD")
|
||||
model_config = SettingsConfigDict(env_file=".env")
|
||||
API_VERSION: str = "/api/v1"
|
||||
ROOT: str = ROOT_PATH
|
||||
|
||||
|
||||
settings = Settings()
|
||||
2
apps/api/src/crud/__init__.py
Normal file
2
apps/api/src/crud/__init__.py
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
from .crud_spell import spell
|
||||
from .crud_user import user
|
||||
74
apps/api/src/crud/base.py
Normal file
74
apps/api/src/crud/base.py
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
from typing import Generic, Optional, TypeVar
|
||||
|
||||
from supabase_py_async import AsyncClient
|
||||
|
||||
from src.schemas.base import CreateBase, ResponseBase, UpdateBase
|
||||
|
||||
ModelType = TypeVar("ModelType", bound=ResponseBase)
|
||||
CreateSchemaType = TypeVar("CreateSchemaType", bound=CreateBase)
|
||||
UpdateSchemaType = TypeVar("UpdateSchemaType", bound=UpdateBase)
|
||||
|
||||
|
||||
class CRUDBase(Generic[ModelType, CreateSchemaType, UpdateSchemaType]):
|
||||
def __init__(self, model: type[ModelType]):
|
||||
"""CRUD object with default methods to do CRUD ops
|
||||
|
||||
Args:
|
||||
model (type[ModelType]): Model class type
|
||||
"""
|
||||
self.model = model
|
||||
|
||||
async def get(self, db: AsyncClient, *, id: str) -> Optional[ModelType]:
|
||||
"""get by table_name by id"""
|
||||
data, count = (
|
||||
await db.table(self.model.table_name).select("*").eq("id", id).execute()
|
||||
)
|
||||
_, got = data
|
||||
return self.model(**got[0]) if got else None
|
||||
|
||||
async def get_all(self, db: AsyncClient) -> list[ModelType]:
|
||||
"""get all by table_name"""
|
||||
data, count = await db.table(self.model.table_name).select("*").execute()
|
||||
_, got = data
|
||||
return [self.model(**item) for item in got]
|
||||
|
||||
async def search_all(
|
||||
self, db: AsyncClient, *, field: str, search_value: str, max_results: int
|
||||
) -> list[ModelType]:
|
||||
"""search all by table_name"""
|
||||
data, count = (
|
||||
await db.table(self.model.table_name)
|
||||
.select("*")
|
||||
.ilike(field, f"%{search_value}%")
|
||||
.limit(max_results)
|
||||
.execute()
|
||||
)
|
||||
_, got = data
|
||||
return [self.model(**item) for item in got]
|
||||
|
||||
async def create(self, db: AsyncClient, *, obj_in: CreateSchemaType) -> ModelType:
|
||||
"""create by CreateSchemaType"""
|
||||
data, count = (
|
||||
await db.table(self.model.table_name).insert(obj_in.model_dump()).execute()
|
||||
)
|
||||
_, created = data
|
||||
return self.model(**created[0])
|
||||
|
||||
async def update(self, db: AsyncClient, *, obj_in: UpdateSchemaType) -> ModelType:
|
||||
"""update by UpdateSchemaType"""
|
||||
data, count = (
|
||||
await db.table(self.model.table_name)
|
||||
.update(obj_in.model_dump())
|
||||
.eq("id", obj_in.id)
|
||||
.execute()
|
||||
)
|
||||
_, updated = data
|
||||
return self.model(**updated[0])
|
||||
|
||||
async def delete(self, db: AsyncClient, *, id: str) -> ModelType:
|
||||
"""remove by UpdateSchemaType"""
|
||||
data, count = (
|
||||
await db.table(self.model.table_name).delete().eq("id", id).execute()
|
||||
)
|
||||
_, deleted = data
|
||||
return self.model(**deleted[0])
|
||||
43
apps/api/src/crud/crud_spell.py
Normal file
43
apps/api/src/crud/crud_spell.py
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
from typing import Optional
|
||||
|
||||
from fastapi import HTTPException
|
||||
from supabase_py_async import AsyncClient
|
||||
|
||||
from src.crud.base import CRUDBase
|
||||
from src.schemas import Spell, SpellCreate, SpellUpdate
|
||||
|
||||
|
||||
class CRUDSpell(CRUDBase[Spell, SpellCreate, SpellUpdate]):
|
||||
async def get(self, db: AsyncClient, *, id: str) -> Optional[Spell]:
|
||||
try:
|
||||
return await super().get(db, id=id)
|
||||
except Exception as e:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"{e.code}: Spell not found. {e.details}",
|
||||
)
|
||||
|
||||
async def get_all(self, db: AsyncClient) -> list[Spell]:
|
||||
try:
|
||||
return await super().get_all(db)
|
||||
except Exception as e:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"An error occurred while fetching spells. {e}",
|
||||
)
|
||||
|
||||
async def search_all(
|
||||
self, db: AsyncClient, *, field: str, search_value: str, max_results: int
|
||||
) -> list[Spell]:
|
||||
try:
|
||||
return await super().search_all(
|
||||
db, field=field, search_value=search_value, max_results=max_results
|
||||
)
|
||||
except Exception as e:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"An error occurred while searching for users. {e}",
|
||||
)
|
||||
|
||||
|
||||
spell = CRUDSpell(Spell)
|
||||
58
apps/api/src/crud/crud_user.py
Normal file
58
apps/api/src/crud/crud_user.py
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
from typing import Optional
|
||||
|
||||
from fastapi import HTTPException
|
||||
from supabase_py_async import AsyncClient
|
||||
|
||||
from src.crud.base import CRUDBase
|
||||
from src.schemas import User, UserCreate, UserUpdate
|
||||
|
||||
|
||||
class CRUDUser(CRUDBase[User, UserCreate, UserUpdate]):
|
||||
async def create(self, db: AsyncClient, *, obj_in: UserCreate) -> User:
|
||||
try:
|
||||
return await super().create(db, obj_in=obj_in)
|
||||
except Exception as e:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f"{e.code}: Failed to create user. {e.details}",
|
||||
)
|
||||
|
||||
async def get(self, db: AsyncClient, *, id: str) -> Optional[User]:
|
||||
try:
|
||||
return await super().get(db, id=id)
|
||||
except Exception as e:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"{e.code}: User not found. {e.details}",
|
||||
)
|
||||
|
||||
async def get_all(self, db: AsyncClient) -> list[User]:
|
||||
try:
|
||||
return await super().get_all(db)
|
||||
except Exception as e:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"An error occurred while fetching users. {e}",
|
||||
)
|
||||
|
||||
async def search_all(
|
||||
self, db: AsyncClient, *, field: str, search_value: str, max_results: int
|
||||
) -> list[User]:
|
||||
try:
|
||||
return await super().search_all(
|
||||
db, field=field, search_value=search_value, max_results=max_results
|
||||
)
|
||||
except Exception as e:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"An error occurred while searching for users. {e}",
|
||||
)
|
||||
|
||||
async def update(self, db: AsyncClient, *, obj_in: UserUpdate) -> User:
|
||||
return await super().update(db, obj_in=obj_in)
|
||||
|
||||
async def delete(self, db: AsyncClient, *, id: str) -> User:
|
||||
return await super().delete(db, id=id)
|
||||
|
||||
|
||||
user = CRUDUser(User)
|
||||
51
apps/api/src/main.py
Normal file
51
apps/api/src/main.py
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
from fastapi import APIRouter, FastAPI
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.routing import APIRoute
|
||||
|
||||
from src.api.api_v1.api import api_router
|
||||
from src.config import settings
|
||||
|
||||
info_router = APIRouter()
|
||||
|
||||
|
||||
@info_router.get("/", status_code=200, include_in_schema=False)
|
||||
async def info():
|
||||
return [{"Status": "API Running"}]
|
||||
|
||||
|
||||
def custom_generate_unique_id(route: APIRoute):
|
||||
"""Generates a custom ID when using the TypeScript Generator Client
|
||||
|
||||
Args:
|
||||
route (APIRoute): The route to be customised
|
||||
|
||||
Returns:
|
||||
str: tag-route_name, e.g. items-CreateItem
|
||||
"""
|
||||
return f"{route.tags[0]}-{route.name}"
|
||||
|
||||
|
||||
def get_application():
|
||||
_app = FastAPI(
|
||||
title=settings.PROJECT_NAME,
|
||||
description=settings.PROJECT_DESCRIPTION,
|
||||
generate_unique_id_function=custom_generate_unique_id,
|
||||
root_path=settings.ROOT,
|
||||
root_path_in_servers=True,
|
||||
)
|
||||
|
||||
_app.include_router(api_router, prefix=settings.API_VERSION)
|
||||
_app.include_router(info_router, tags=[""])
|
||||
|
||||
_app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["*"],
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
return _app
|
||||
|
||||
|
||||
app = get_application()
|
||||
2
apps/api/src/schemas/__init__.py
Normal file
2
apps/api/src/schemas/__init__.py
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
from .spell import Spell, SpellCreate, SpellSearchResults, SpellUpdate
|
||||
from .user import User, UserCreate, UserSearchResults, UserUpdate
|
||||
40
apps/api/src/schemas/base.py
Normal file
40
apps/api/src/schemas/base.py
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
from typing import ClassVar
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
|
||||
# Shared properties
|
||||
# class CRUDBaseModel(BaseModel):
|
||||
# # where the data
|
||||
# table_name: str
|
||||
|
||||
|
||||
# Properties to receive on item creation
|
||||
# in
|
||||
class CreateBase(BaseModel):
|
||||
# inherent to add more properties for creating
|
||||
pass
|
||||
|
||||
|
||||
# Properties to receive on item update
|
||||
# in
|
||||
class UpdateBase(BaseModel):
|
||||
# inherent to add more properties for updating
|
||||
id: str
|
||||
|
||||
|
||||
# response
|
||||
# Properties shared by models stored in DB
|
||||
class InDBBase(BaseModel):
|
||||
id: str
|
||||
user_id: str
|
||||
created_at: str
|
||||
|
||||
|
||||
# Properties to return to client
|
||||
# crud model
|
||||
# out
|
||||
class ResponseBase(InDBBase):
|
||||
# inherent to add more properties for responding
|
||||
table_name: ClassVar[str] = "ResponseBase".lower()
|
||||
Config: ClassVar[ConfigDict] = ConfigDict(
|
||||
extra="ignore", arbitrary_types_allowed=True
|
||||
)
|
||||
26
apps/api/src/schemas/spell.py
Normal file
26
apps/api/src/schemas/spell.py
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
from typing import ClassVar, Sequence
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class Spell(BaseModel):
|
||||
id: str
|
||||
name: str
|
||||
description: str
|
||||
table_name: ClassVar[str] = "spells"
|
||||
|
||||
|
||||
class SpellCreate(BaseModel):
|
||||
id: str
|
||||
name: str
|
||||
description: str
|
||||
|
||||
|
||||
class SpellUpdate(BaseModel):
|
||||
id: str
|
||||
name: str
|
||||
description: str
|
||||
|
||||
|
||||
class SpellSearchResults(BaseModel):
|
||||
results: Sequence[Spell]
|
||||
31
apps/api/src/schemas/user.py
Normal file
31
apps/api/src/schemas/user.py
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
from typing import ClassVar, Sequence
|
||||
|
||||
from pydantic import BaseModel, EmailStr
|
||||
|
||||
|
||||
class User(BaseModel):
|
||||
id: str
|
||||
forename: str
|
||||
surname: str
|
||||
email: EmailStr
|
||||
table_name: ClassVar[str] = "user"
|
||||
|
||||
|
||||
class UserCreate(BaseModel):
|
||||
forename: str
|
||||
surname: str
|
||||
email: EmailStr
|
||||
|
||||
|
||||
class UserUpdate(BaseModel):
|
||||
forename: str
|
||||
surname: str
|
||||
email: EmailStr
|
||||
|
||||
|
||||
class ResponseMessage(BaseModel):
|
||||
message: str
|
||||
|
||||
|
||||
class UserSearchResults(BaseModel):
|
||||
results: Sequence[User]
|
||||
0
apps/api/tests/__init__.py
Normal file
0
apps/api/tests/__init__.py
Normal file
5
apps/api/tests/test_api.py
Normal file
5
apps/api/tests/test_api.py
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
from src import __version__
|
||||
|
||||
|
||||
def test_version():
|
||||
assert __version__ == '0.1.0'
|
||||
18
apps/api/vercel.json
Normal file
18
apps/api/vercel.json
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"version": 2,
|
||||
"builds": [
|
||||
{
|
||||
"src": "/src/main.py",
|
||||
"use": "@vercel/python"
|
||||
}
|
||||
],
|
||||
"routes": [
|
||||
{
|
||||
"src": "/(.*)",
|
||||
"dest": "src/main.py"
|
||||
}
|
||||
],
|
||||
"env": {
|
||||
"APP_MODULE": "src.main:app"
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue