Mapping made_by to displayname
This commit is contained in:
parent
53ca792988
commit
fa5ba578bb
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -54,10 +54,12 @@ def list_recipes_db() -> List[Dict[str, Any]]:
|
|||||||
with conn.cursor() as cur:
|
with conn.cursor() as cur:
|
||||||
cur.execute(
|
cur.execute(
|
||||||
"""
|
"""
|
||||||
SELECT id, name, meal_type, time_minutes,
|
SELECT r.id, r.name, r.meal_type, r.time_minutes,
|
||||||
tags, ingredients, steps, image, made_by, user_id
|
r.tags, r.ingredients, r.steps, r.image, r.made_by, r.user_id,
|
||||||
FROM recipes
|
u.display_name as owner_display_name
|
||||||
ORDER BY id
|
FROM recipes r
|
||||||
|
LEFT JOIN users u ON r.user_id = u.id
|
||||||
|
ORDER BY r.id
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
rows = cur.fetchall()
|
rows = cur.fetchall()
|
||||||
@ -163,19 +165,21 @@ def get_recipes_by_filters_db(
|
|||||||
conn = get_conn()
|
conn = get_conn()
|
||||||
try:
|
try:
|
||||||
query = """
|
query = """
|
||||||
SELECT id, name, meal_type, time_minutes,
|
SELECT r.id, r.name, r.meal_type, r.time_minutes,
|
||||||
tags, ingredients, steps, image, made_by, user_id
|
r.tags, r.ingredients, r.steps, r.image, r.made_by, r.user_id,
|
||||||
FROM recipes
|
u.display_name as owner_display_name
|
||||||
|
FROM recipes r
|
||||||
|
LEFT JOIN users u ON r.user_id = u.id
|
||||||
WHERE 1=1
|
WHERE 1=1
|
||||||
"""
|
"""
|
||||||
params: List = []
|
params: List = []
|
||||||
|
|
||||||
if meal_type:
|
if meal_type:
|
||||||
query += " AND meal_type = %s"
|
query += " AND r.meal_type = %s"
|
||||||
params.append(meal_type.lower())
|
params.append(meal_type.lower())
|
||||||
|
|
||||||
if max_time:
|
if max_time:
|
||||||
query += " AND time_minutes <= %s"
|
query += " AND r.time_minutes <= %s"
|
||||||
params.append(max_time)
|
params.append(max_time)
|
||||||
|
|
||||||
with conn.cursor() as cur:
|
with conn.cursor() as cur:
|
||||||
|
|||||||
@ -51,6 +51,7 @@ class RecipeCreate(RecipeBase):
|
|||||||
class Recipe(RecipeBase):
|
class Recipe(RecipeBase):
|
||||||
id: int
|
id: int
|
||||||
user_id: Optional[int] = None # Recipe owner ID
|
user_id: Optional[int] = None # Recipe owner ID
|
||||||
|
owner_display_name: Optional[str] = None # Owner's display name for filtering
|
||||||
|
|
||||||
|
|
||||||
class RecipeUpdate(RecipeBase):
|
class RecipeUpdate(RecipeBase):
|
||||||
@ -132,6 +133,7 @@ def list_recipes():
|
|||||||
steps=r["steps"] or [],
|
steps=r["steps"] or [],
|
||||||
image=r.get("image"),
|
image=r.get("image"),
|
||||||
user_id=r.get("user_id"),
|
user_id=r.get("user_id"),
|
||||||
|
owner_display_name=r.get("owner_display_name"),
|
||||||
)
|
)
|
||||||
for r in rows
|
for r in rows
|
||||||
]
|
]
|
||||||
@ -157,6 +159,7 @@ def create_recipe(recipe_in: RecipeCreate, current_user: dict = Depends(get_curr
|
|||||||
steps=row["steps"] or [],
|
steps=row["steps"] or [],
|
||||||
image=row.get("image"),
|
image=row.get("image"),
|
||||||
user_id=row.get("user_id"),
|
user_id=row.get("user_id"),
|
||||||
|
owner_display_name=current_user.get("display_name"),
|
||||||
)
|
)
|
||||||
|
|
||||||
@app.put("/recipes/{recipe_id}", response_model=Recipe)
|
@app.put("/recipes/{recipe_id}", response_model=Recipe)
|
||||||
@ -192,6 +195,7 @@ def update_recipe(recipe_id: int, recipe_in: RecipeUpdate, current_user: dict =
|
|||||||
steps=row["steps"] or [],
|
steps=row["steps"] or [],
|
||||||
image=row.get("image"),
|
image=row.get("image"),
|
||||||
user_id=row.get("user_id"),
|
user_id=row.get("user_id"),
|
||||||
|
owner_display_name=current_user.get("display_name"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -239,6 +243,7 @@ def random_recipe(
|
|||||||
steps=r["steps"] or [],
|
steps=r["steps"] or [],
|
||||||
image=r.get("image"),
|
image=r.get("image"),
|
||||||
user_id=r.get("user_id"),
|
user_id=r.get("user_id"),
|
||||||
|
owner_display_name=r.get("owner_display_name"),
|
||||||
)
|
)
|
||||||
for r in rows
|
for r in rows
|
||||||
]
|
]
|
||||||
@ -288,6 +293,17 @@ def register(user: UserRegister):
|
|||||||
detail="האימייל כבר רשום במערכת"
|
detail="האימייל כבר רשום במערכת"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Check if display_name already exists
|
||||||
|
print(f"[REGISTER] Checking if display_name exists...")
|
||||||
|
from user_db_utils import get_user_by_display_name
|
||||||
|
existing_display_name = get_user_by_display_name(user.display_name)
|
||||||
|
if existing_display_name:
|
||||||
|
print(f"[REGISTER] Display name already exists")
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=400,
|
||||||
|
detail="שם התצוגה כבר קיים במערכת"
|
||||||
|
)
|
||||||
|
|
||||||
# Hash password and create user
|
# Hash password and create user
|
||||||
print(f"[REGISTER] Hashing password...")
|
print(f"[REGISTER] Hashing password...")
|
||||||
password_hash = hash_password(user.password)
|
password_hash = hash_password(user.password)
|
||||||
|
|||||||
@ -6,7 +6,7 @@ CREATE TABLE IF NOT EXISTS users (
|
|||||||
password_hash TEXT NOT NULL,
|
password_hash TEXT NOT NULL,
|
||||||
first_name TEXT,
|
first_name TEXT,
|
||||||
last_name TEXT,
|
last_name TEXT,
|
||||||
display_name TEXT NOT NULL,
|
display_name TEXT UNIQUE NOT NULL,
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -84,3 +84,19 @@ def get_user_by_id(user_id: int):
|
|||||||
finally:
|
finally:
|
||||||
cur.close()
|
cur.close()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
def get_user_by_display_name(display_name: str):
|
||||||
|
"""Get user by display name"""
|
||||||
|
conn = get_db_connection()
|
||||||
|
cur = conn.cursor(cursor_factory=RealDictCursor)
|
||||||
|
try:
|
||||||
|
cur.execute(
|
||||||
|
"SELECT id, username, email, display_name, created_at FROM users WHERE display_name = %s",
|
||||||
|
(display_name,)
|
||||||
|
)
|
||||||
|
user = cur.fetchone()
|
||||||
|
return dict(user) if user else None
|
||||||
|
finally:
|
||||||
|
cur.close()
|
||||||
|
conn.close()
|
||||||
|
|||||||
@ -27,7 +27,7 @@ function App() {
|
|||||||
const [filterMealType, setFilterMealType] = useState("");
|
const [filterMealType, setFilterMealType] = useState("");
|
||||||
const [filterMaxTime, setFilterMaxTime] = useState("");
|
const [filterMaxTime, setFilterMaxTime] = useState("");
|
||||||
const [filterTags, setFilterTags] = useState([]);
|
const [filterTags, setFilterTags] = useState([]);
|
||||||
const [filterMadeBy, setFilterMadeBy] = useState("");
|
const [filterOwner, setFilterOwner] = useState("");
|
||||||
|
|
||||||
// Random recipe filters
|
// Random recipe filters
|
||||||
const [mealTypeFilter, setMealTypeFilter] = useState("");
|
const [mealTypeFilter, setMealTypeFilter] = useState("");
|
||||||
@ -126,8 +126,8 @@ function App() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter by made_by
|
// Filter by made_by (username)
|
||||||
if (filterMadeBy && (!recipe.made_by || recipe.made_by !== filterMadeBy)) {
|
if (filterOwner && (!recipe.made_by || recipe.made_by !== filterOwner)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -343,8 +343,8 @@ function App() {
|
|||||||
onMaxTimeChange={setFilterMaxTime}
|
onMaxTimeChange={setFilterMaxTime}
|
||||||
filterTags={filterTags}
|
filterTags={filterTags}
|
||||||
onTagsChange={setFilterTags}
|
onTagsChange={setFilterTags}
|
||||||
filterMadeBy={filterMadeBy}
|
filterOwner={filterOwner}
|
||||||
onMadeByChange={setFilterMadeBy}
|
onOwnerChange={setFilterOwner}
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|||||||
@ -35,8 +35,8 @@ function RecipeDetails({ recipe, onEditClick, onDeleteClick, onShowDeleteModal,
|
|||||||
<p className="recipe-subtitle">
|
<p className="recipe-subtitle">
|
||||||
{translateMealType(recipe.meal_type)} · {recipe.time_minutes} דקות הכנה
|
{translateMealType(recipe.meal_type)} · {recipe.time_minutes} דקות הכנה
|
||||||
</p>
|
</p>
|
||||||
{recipe.made_by && (
|
{(recipe.owner_display_name || recipe.made_by) && (
|
||||||
<h4 className="recipe-made-by">המתכון של: {recipe.made_by}</h4>
|
<h4 className="recipe-made-by">המתכון של: {recipe.owner_display_name || recipe.made_by}</h4>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="pill-row">
|
<div className="pill-row">
|
||||||
|
|||||||
@ -14,8 +14,8 @@ function RecipeSearchList({
|
|||||||
onMaxTimeChange,
|
onMaxTimeChange,
|
||||||
filterTags,
|
filterTags,
|
||||||
onTagsChange,
|
onTagsChange,
|
||||||
filterMadeBy,
|
filterOwner,
|
||||||
onMadeByChange,
|
onOwnerChange,
|
||||||
}) {
|
}) {
|
||||||
const [expandFilters, setExpandFilters] = useState(false);
|
const [expandFilters, setExpandFilters] = useState(false);
|
||||||
|
|
||||||
@ -27,8 +27,14 @@ function RecipeSearchList({
|
|||||||
// Extract unique meal types from ALL recipes (not filtered)
|
// Extract unique meal types from ALL recipes (not filtered)
|
||||||
const mealTypes = Array.from(new Set(allRecipes.map((r) => r.meal_type))).sort();
|
const mealTypes = Array.from(new Set(allRecipes.map((r) => r.meal_type))).sort();
|
||||||
|
|
||||||
// Extract unique made_by from ALL recipes (not filtered)
|
// Extract unique made_by (username) from ALL recipes and map to display names
|
||||||
const allMadeBy = Array.from(new Set(allRecipes.map((r) => r.made_by).filter(Boolean))).sort();
|
const madeByMap = new Map();
|
||||||
|
allRecipes.forEach((r) => {
|
||||||
|
if (r.made_by && r.owner_display_name) {
|
||||||
|
madeByMap.set(r.made_by, r.owner_display_name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const allMadeBy = Array.from(madeByMap.keys()).sort();
|
||||||
|
|
||||||
// Extract max time for slider from ALL recipes (not filtered) - add 10 to make it comfortable to select max time recipes
|
// Extract max time for slider from ALL recipes (not filtered) - add 10 to make it comfortable to select max time recipes
|
||||||
const maxTimeInRecipes = Math.max(...allRecipes.map((r) => r.time_minutes), 0);
|
const maxTimeInRecipes = Math.max(...allRecipes.map((r) => r.time_minutes), 0);
|
||||||
@ -47,10 +53,10 @@ function RecipeSearchList({
|
|||||||
onMealTypeChange("");
|
onMealTypeChange("");
|
||||||
onMaxTimeChange("");
|
onMaxTimeChange("");
|
||||||
onTagsChange([]);
|
onTagsChange([]);
|
||||||
onMadeByChange("");
|
onOwnerChange("");
|
||||||
};
|
};
|
||||||
|
|
||||||
const hasActiveFilters = searchQuery || filterMealType || filterMaxTime || filterTags.length > 0 || filterMadeBy;
|
const hasActiveFilters = searchQuery || filterMealType || filterMaxTime || filterTags.length > 0 || filterOwner;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="panel secondary recipe-search-list">
|
<section className="panel secondary recipe-search-list">
|
||||||
@ -165,18 +171,18 @@ function RecipeSearchList({
|
|||||||
<label className="filter-label">המתכונים של:</label>
|
<label className="filter-label">המתכונים של:</label>
|
||||||
<div className="filter-options">
|
<div className="filter-options">
|
||||||
<button
|
<button
|
||||||
className={`filter-btn ${filterMadeBy === "" ? "active" : ""}`}
|
className={`filter-btn ${filterOwner === "" ? "active" : ""}`}
|
||||||
onClick={() => onMadeByChange("")}
|
onClick={() => onOwnerChange("")}
|
||||||
>
|
>
|
||||||
הכל
|
הכל
|
||||||
</button>
|
</button>
|
||||||
{allMadeBy.map((person) => (
|
{allMadeBy.map((madeBy) => (
|
||||||
<button
|
<button
|
||||||
key={person}
|
key={madeBy}
|
||||||
className={`filter-btn ${filterMadeBy === person ? "active" : ""}`}
|
className={`filter-btn ${filterOwner === madeBy ? "active" : ""}`}
|
||||||
onClick={() => onMadeByChange(person)}
|
onClick={() => onOwnerChange(madeBy)}
|
||||||
>
|
>
|
||||||
{person}
|
{madeByMap.get(madeBy) || madeBy}
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user