Added identity
This commit is contained in:
parent
6ba6406427
commit
edbe082387
6 changed files with 71 additions and 51 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,3 +1,4 @@
|
||||||
.venv/
|
.venv/
|
||||||
__pycache__
|
__pycache__
|
||||||
data/
|
data/
|
||||||
|
.vscode/*
|
||||||
22
main.py
22
main.py
|
|
@ -4,8 +4,9 @@ import datetime
|
||||||
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from typing import List, Annotated
|
from typing import List, Annotated
|
||||||
from fastapi import FastAPI, Depends, Query
|
from fastapi import FastAPI, Depends, Query, Cookie
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
|
from fastapi.encoders import jsonable_encoder
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
|
|
||||||
app = FastAPI()
|
app = FastAPI()
|
||||||
|
|
@ -27,6 +28,9 @@ async def get_db():
|
||||||
finally:
|
finally:
|
||||||
await sql_db.close()
|
await sql_db.close()
|
||||||
|
|
||||||
|
async def cookie_person(user_id: Annotated[int, Cookie(alias='user_id')], conn: sqlite3.Connection = Depends(get_db)) -> persons.Person:
|
||||||
|
return await persons.find_person_by_id(conn, user_id)
|
||||||
|
|
||||||
@app.get("/recipes/parse")
|
@app.get("/recipes/parse")
|
||||||
async def parse_recipe_handler(url: str, conn: sqlite3.Connection = Depends(get_db)) -> recipes.Recipe:
|
async def parse_recipe_handler(url: str, conn: sqlite3.Connection = Depends(get_db)) -> recipes.Recipe:
|
||||||
parsed = await recipes.parse_recipe(conn, url)
|
parsed = await recipes.parse_recipe(conn, url)
|
||||||
|
|
@ -89,7 +93,7 @@ async def get_recipe(recipe_id: int, conn: sqlite3.Connection = Depends(get_db))
|
||||||
return r
|
return r
|
||||||
|
|
||||||
@app.post('/recipes/')
|
@app.post('/recipes/')
|
||||||
async def create_recipe(item: recipes.Recipe, conn: sqlite3.Connection = Depends(get_db)) -> recipes.Recipe:
|
async def create_recipe(item: recipes.Recipe, conn: sqlite3.Connection = Depends(get_db), user: persons.Person = Depends(cookie_person)) -> recipes.Recipe:
|
||||||
if not item.ingredients:
|
if not item.ingredients:
|
||||||
return JSONResponse(status_code=400, content={'message': 'Recipe must have at least one ingredient'})
|
return JSONResponse(status_code=400, content={'message': 'Recipe must have at least one ingredient'})
|
||||||
|
|
||||||
|
|
@ -97,6 +101,7 @@ async def create_recipe(item: recipes.Recipe, conn: sqlite3.Connection = Depends
|
||||||
if not ingredient.product:
|
if not ingredient.product:
|
||||||
return JSONResponse(status_code=400, content={'message': 'Ingredient must have a product'})
|
return JSONResponse(status_code=400, content={'message': 'Ingredient must have a product'})
|
||||||
|
|
||||||
|
item.created_by_id = user.id
|
||||||
await recipes.insert_recipe(conn, item)
|
await recipes.insert_recipe(conn, item)
|
||||||
for ingredient in item.ingredients:
|
for ingredient in item.ingredients:
|
||||||
ingredient.recipe_id = item.id
|
ingredient.recipe_id = item.id
|
||||||
|
|
@ -169,3 +174,16 @@ async def create_person(person: persons.Person, conn: sqlite3.Connection = Depen
|
||||||
await persons.insert(conn, person)
|
await persons.insert(conn, person)
|
||||||
await conn.commit()
|
await conn.commit()
|
||||||
return person
|
return person
|
||||||
|
|
||||||
|
class LoginBody(BaseModel):
|
||||||
|
username: str
|
||||||
|
|
||||||
|
@app.post('/auth/login')
|
||||||
|
async def login(data: LoginBody, conn: sqlite3.Connection = Depends(get_db)) -> persons.Person:
|
||||||
|
person = await persons.get_by_name(conn, data.username)
|
||||||
|
if not person:
|
||||||
|
return JSONResponse(status_code=404, content={'message': 'Person not found'})
|
||||||
|
|
||||||
|
response = JSONResponse(content=jsonable_encoder(person))
|
||||||
|
response.set_cookie(key='user_id', value=str(person.id))
|
||||||
|
return response
|
||||||
31
model.py
31
model.py
|
|
@ -1,31 +0,0 @@
|
||||||
from typing import List, ClassVar
|
|
||||||
from pydantic import BaseModel
|
|
||||||
|
|
||||||
"""
|
|
||||||
class Person:
|
|
||||||
def __init__(self, id: int, name: str) -> None:
|
|
||||||
self.id = id
|
|
||||||
self.name = name
|
|
||||||
|
|
||||||
class Meal:
|
|
||||||
def __init__(self, id: int, date: datetime, chef: List[Person], cleanup: List[Person],
|
|
||||||
consumers: List[Person], recipes: List[Recipe]) -> None:
|
|
||||||
self.id = id
|
|
||||||
self.date = date
|
|
||||||
self.chef = chef
|
|
||||||
self.cleanup = cleanup
|
|
||||||
self.consumers = consumers
|
|
||||||
self.recipes = recipes
|
|
||||||
|
|
||||||
class ShoppingListItem:
|
|
||||||
def __init__(self, id: int, food_item: Product, measure: Measurement, source: Union[Meal, None]) -> None:
|
|
||||||
self.id = id
|
|
||||||
self.food_item = food_item
|
|
||||||
self.measure = measure
|
|
||||||
self.source = source
|
|
||||||
|
|
||||||
class ShoppingList:
|
|
||||||
def __init__(self, date: datetime, items: List[ShoppingListItem]) -> None:
|
|
||||||
self.date = date
|
|
||||||
self.items = items
|
|
||||||
"""
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from typing import List, ClassVar
|
from typing import List
|
||||||
|
|
||||||
class Person(BaseModel):
|
class Person(BaseModel):
|
||||||
id: int
|
id: int
|
||||||
|
|
@ -12,6 +12,22 @@ async def create(conn):
|
||||||
name TEXT UNIQUE
|
name TEXT UNIQUE
|
||||||
);''')
|
);''')
|
||||||
|
|
||||||
|
await insert(conn, Person(id=0, name='Jacob'))
|
||||||
|
await insert(conn, Person(id=0, name='Ellie'))
|
||||||
|
await insert(conn, Person(id=0, name='Ryan'))
|
||||||
|
await insert(conn, Person(id=0, name='Chris'))
|
||||||
|
|
||||||
|
async def get_by_name(conn, name: str) -> Person:
|
||||||
|
cursor = await conn.execute('''
|
||||||
|
SELECT id, name
|
||||||
|
FROM Person
|
||||||
|
WHERE name = ?
|
||||||
|
''', (name,))
|
||||||
|
row = await cursor.fetchone()
|
||||||
|
if not row:
|
||||||
|
return None
|
||||||
|
return Person(id=row[0], name=row[1])
|
||||||
|
|
||||||
async def get_by_id(conn, id: int) -> Person:
|
async def get_by_id(conn, id: int) -> Person:
|
||||||
cursor = await conn.execute('''
|
cursor = await conn.execute('''
|
||||||
SELECT id, name
|
SELECT id, name
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,6 @@ from recipes.db import Recipe, insert_recipe, find_recipe_by_id, get_all, find_r
|
||||||
from recipes.scraping import scrape_recipe_ldata as _scrape_recipe_ldata
|
from recipes.scraping import scrape_recipe_ldata as _scrape_recipe_ldata
|
||||||
from ingredients import parse_ingredient_from_nlp as _parse_ingredient_from_nlp, match_existing_products as _match_existing_products
|
from ingredients import parse_ingredient_from_nlp as _parse_ingredient_from_nlp, match_existing_products as _match_existing_products
|
||||||
|
|
||||||
import json
|
|
||||||
|
|
||||||
async def parse_recipe(conn, url: str) -> Recipe:
|
async def parse_recipe(conn, url: str) -> Recipe:
|
||||||
ldata = await _scrape_recipe_ldata(url)
|
ldata = await _scrape_recipe_ldata(url)
|
||||||
if ldata:
|
if ldata:
|
||||||
|
|
@ -30,6 +28,5 @@ async def _get_recipe_from_ldata(conn, url: str, ldata: dict) -> dict:
|
||||||
name=name,
|
name=name,
|
||||||
link=url,
|
link=url,
|
||||||
image_urls=images,
|
image_urls=images,
|
||||||
raw_data=json.dumps(ldata),
|
|
||||||
ingredients=ingredients
|
ingredients=ingredients
|
||||||
)
|
)
|
||||||
|
|
@ -1,34 +1,53 @@
|
||||||
import json
|
import json, datetime
|
||||||
|
|
||||||
|
from persons import Person
|
||||||
from ingredients import Ingredient, find_ingredients_by_recipe_id
|
from ingredients import Ingredient, find_ingredients_by_recipe_id
|
||||||
|
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel
|
||||||
from typing import List, ClassVar, Tuple
|
from typing import List, ClassVar, Tuple, Optional
|
||||||
|
|
||||||
class Recipe(BaseModel):
|
class Recipe(BaseModel):
|
||||||
KEYS: ClassVar[List[str]] = ['id', 'name', 'link', 'image_urls', 'raw_data']
|
KEYS: ClassVar[List[str]] = ['id', 'name', 'link', 'image_urls', 'based_on_recipe', 'created_by_id', 'date_created', 'hidden_by_id', 'date_hidden']
|
||||||
id: int
|
id: int
|
||||||
name: str
|
name: str
|
||||||
link: str
|
link: str
|
||||||
raw_data: str
|
|
||||||
image_urls: List[str] = []
|
image_urls: List[str] = []
|
||||||
ingredients: List[Ingredient] = []
|
ingredients: List[Ingredient] = []
|
||||||
|
based_on_recipe: Optional[int] = None
|
||||||
|
|
||||||
|
date_created: Optional[datetime.datetime] = None
|
||||||
|
created_by_id: Optional[int] = None
|
||||||
|
created_by: Optional[Person] = None
|
||||||
|
|
||||||
|
date_hidden: Optional[datetime.datetime] = None
|
||||||
|
hidden_by_id: Optional[int] = None
|
||||||
|
hidden_by: Optional[Person] = None
|
||||||
|
|
||||||
async def create(conn):
|
async def create(conn):
|
||||||
await conn.execute('''
|
await conn.execute('''
|
||||||
CREATE TABLE IF NOT EXISTS Recipe (
|
CREATE TABLE IF NOT EXISTS Recipe (
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
name TEXT,
|
name TEXT NOT NULL,
|
||||||
link TEXT,
|
link TEXT NOT NULL,
|
||||||
image_urls TEXT,
|
image_urls TEXT NOT NULL,
|
||||||
raw_data TEXT
|
based_on_recipe INTEGER NULL,
|
||||||
|
|
||||||
|
date_created DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
created_by_id INTEGER NOT NULL,
|
||||||
|
|
||||||
|
date_hidden DATETIME DEFAULT NULL,
|
||||||
|
hidden_by_id INTEGER DEFAULT NULL,
|
||||||
|
|
||||||
|
FOREIGN KEY (based_on_recipe) REFERENCES Recipe(id)
|
||||||
|
FOREIGN KEY (created_by_id) REFERENCES Person(id)
|
||||||
|
FOREIGN KEY (hidden_by_id) REFERENCES Person(id)
|
||||||
);''')
|
);''')
|
||||||
|
|
||||||
async def insert_recipe(conn, recipe: Recipe):
|
async def insert_recipe(conn, recipe: Recipe):
|
||||||
async with conn.execute('''
|
async with conn.execute('''
|
||||||
INSERT INTO Recipe (name, link, raw_data, image_urls)
|
INSERT INTO Recipe (name, link, image_urls, based_on_recipe, created_by_id)
|
||||||
VALUES (?, ?, ?, ?)
|
VALUES (?, ?, ?, ?, ?)
|
||||||
''', (recipe.name, recipe.link, recipe.raw_data, json.dumps(recipe.image_urls))) as cursor:
|
''', (recipe.name, recipe.link, json.dumps(recipe.image_urls), recipe.based_on_recipe, recipe.created_by_id)) as cursor:
|
||||||
recipe.id = cursor.lastrowid
|
recipe.id = cursor.lastrowid
|
||||||
|
|
||||||
def row_to_recipe(col_tuples: List[Tuple[str, ...]]) -> Recipe:
|
def row_to_recipe(col_tuples: List[Tuple[str, ...]]) -> Recipe:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue