|
1 | 1 | import uuid |
| 2 | +import datetime |
2 | 3 | from typing import Any |
3 | 4 |
|
4 | 5 | from fastapi import APIRouter, HTTPException |
| 6 | +from pydantic import BaseModel |
5 | 7 | from sqlmodel import func, select |
6 | 8 |
|
7 | 9 | from app.api.deps import CurrentUser, SessionDep |
8 | | -from app.models import Item, ItemCreate, ItemPublic, ItemsPublic, ItemUpdate, Message |
| 10 | +from app.models import Item, ItemBase, ItemCreate, ItemPublic, ItemsPublic, ItemUpdate, Message |
9 | 11 | from app.openfga.fgaMiddleware import check_user_has_relation, create_fga_tuple, delete_fga_tuple, initialize_fga_client |
10 | 12 | from app.openfga.fgaMiddleware import check_user_has_permission |
11 | 13 | from openfga_sdk.client.models.tuple import ClientTuple |
|
15 | 17 |
|
16 | 18 | @router.get("/", response_model=ItemsPublic) |
17 | 19 | def read_items( |
18 | | - session: SessionDep, current_user: CurrentUser, skip: int = 0, limit: int = 100, get_completed: bool = False |
| 20 | + session: SessionDep, |
| 21 | + current_user: CurrentUser, |
| 22 | + skip: int = 0, |
| 23 | + limit: int = 100, |
| 24 | + get_completed: bool = False, |
| 25 | + get_owned: bool = False, |
| 26 | + title: str | None = None, |
| 27 | + description: str | None = None, |
| 28 | + location: str | None = None, |
| 29 | + price: str | None = None, |
| 30 | + difficulty: str | None = None, |
| 31 | + type: str | None = None, |
| 32 | + category: str | None = None, |
| 33 | + tags: list[str] | None = None, |
| 34 | + link: str | None = None, |
| 35 | + picture: str | None = None, |
| 36 | + in_featured: bool | None = None, |
| 37 | + rating: float | None = None, |
| 38 | + tries: int | None = None, |
| 39 | + favorites: int | None = None, |
| 40 | + duration: datetime.timedelta | None = None, |
19 | 41 | ) -> Any: |
20 | 42 | """ |
21 | 43 | Retrieve items. |
22 | 44 | """ |
23 | 45 | fga_client = initialize_fga_client() |
24 | 46 |
|
25 | | - if current_user.is_superuser: |
26 | | - count_statement = select(func.count()).select_from(Item) |
27 | | - count = session.exec(count_statement).one() |
28 | | - statement = select(Item).offset(skip).limit(limit) |
29 | | - items = session.exec(statement).all() |
| 47 | + # Database filters |
| 48 | + if title or description or location or price or difficulty or type or category or tags or link or picture or in_featured or rating or tries or favorites or duration: |
| 49 | + query = select(Item) |
| 50 | + # instead of appending to filters, we can use a where builder results = session.exec(query).all() |
| 51 | + if title: |
| 52 | + query = query.where(Item.title == title) |
| 53 | + if description: |
| 54 | + query = query.where(Item.description == description) |
| 55 | + if location: |
| 56 | + query = query.where(Item.location == location) |
| 57 | + if price: |
| 58 | + query = query.where(Item.price == price) |
| 59 | + if difficulty: |
| 60 | + query = query.where(Item.difficulty == difficulty) |
| 61 | + if type: |
| 62 | + query = query.where(Item.type == type) |
| 63 | + if category: |
| 64 | + query = query.where(Item.category == category) |
| 65 | + if tags: |
| 66 | + query = query.where(Item.tags == tags) |
| 67 | + if link: |
| 68 | + query = query.where(Item.link == link) |
| 69 | + if picture: |
| 70 | + query = query.where(Item.picture == picture) |
| 71 | + if in_featured: |
| 72 | + query = query.where(Item.in_featured == in_featured) |
| 73 | + if rating: |
| 74 | + query = query.where(Item.rating == rating) |
| 75 | + if tries: |
| 76 | + query = query.where(Item.tries == tries) |
| 77 | + if favorites: |
| 78 | + query = query.where(Item.favorites == favorites) |
| 79 | + if duration: |
| 80 | + query = query.where(Item.duration == duration) |
| 81 | + |
| 82 | + query = query.offset(skip).limit(limit) |
| 83 | + items = session.exec(query).all() |
| 84 | + count = len(items) |
30 | 85 | else: |
31 | | - count_statement = ( |
32 | | - select(func.count()) |
33 | | - .select_from(Item) |
34 | | - # .where(Item.owner_id == current_user.id) # only returns items that the user owns |
35 | | - ) |
36 | | - count = session.exec(count_statement).one() |
| 86 | + # get all items |
| 87 | + count = session.exec(select(func.count()).select_from(Item)).one() |
37 | 88 | statement = ( |
38 | 89 | select(Item) |
39 | | - # .where(Item.owner_id == current_user.id) |
40 | 90 | .offset(skip) |
41 | 91 | .limit(limit) |
42 | 92 | ) |
43 | 93 | items = session.exec(statement).all() |
| 94 | + |
| 95 | + # FGA filters |
| 96 | + if get_owned: |
| 97 | + item_ids = check_user_has_relation(fga_client, relation="owner", user=f"{current_user.email}") |
| 98 | + if len(item_ids) == 0: |
| 99 | + return ItemsPublic(data=[], count=0) |
| 100 | + else: |
| 101 | + # filter items to only those that match the item_ids |
| 102 | + items = [item for item in items if str(item.id) in item_ids] |
44 | 103 |
|
45 | 104 | if get_completed: |
46 | 105 | item_ids = check_user_has_relation(fga_client, relation="completed", user=f"{current_user.email}") |
47 | 106 | if len(item_ids) == 0: |
48 | 107 | return ItemsPublic(data=[], count=0) |
49 | 108 | else: |
50 | 109 | # get those items with those ids |
51 | | - items = [session.get(Item, id) for id in item_ids] |
| 110 | + items = [item for item in items if str(item.id) in item_ids] |
52 | 111 |
|
53 | 112 | return ItemsPublic(data=[ItemPublic.model_validate(item) for item in items], count=count) |
54 | 113 |
|
@@ -150,3 +209,4 @@ async def delete_item( |
150 | 209 | delete_fga_tuple(fga_client, [ClientTuple(user=f"user:{current_user.id}", relation="owner", object=f"item:{id}")]) |
151 | 210 |
|
152 | 211 | return Message(message="Item deleted successfully") |
| 212 | + |
0 commit comments