You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
73 lines
2.3 KiB
73 lines
2.3 KiB
/**
|
|
* GET /api/products
|
|
*
|
|
* Returns a list of products visible to the current user based on their active role.
|
|
*
|
|
* Role-based Visibility (MVP):
|
|
* - Unauthenticated users: See NO products (empty array)
|
|
* - Authenticated users: See products assigned to their ACTIVE role only
|
|
* - Products WITHOUT role assignments: NOT visible (opt-in visibility)
|
|
*
|
|
* Query Parameters:
|
|
* - category: Filter by category (optional, comma-separated for multiple)
|
|
*
|
|
* Phase 2/3: This will be extended with role request/approval workflow
|
|
*/
|
|
|
|
import { eq, and, inArray } from 'drizzle-orm'
|
|
import { products } from '../../database/schema'
|
|
import { getVisibleProductIdsForRole } from '../../utils/roles'
|
|
import { getUserActiveRole } from '../../utils/role-session'
|
|
|
|
export default defineEventHandler(async (event) => {
|
|
const db = useDatabase()
|
|
const query = getQuery(event)
|
|
const categoryParam = query.category as string | undefined
|
|
|
|
try {
|
|
// Get user session (if authenticated)
|
|
const { user } = await getUserSession(event)
|
|
|
|
// MVP: Unauthenticated users cannot see any products
|
|
if (!user) {
|
|
return []
|
|
}
|
|
|
|
// Get user's active role (validates with TTL, auto-fallback if revoked)
|
|
const activeRole = await getUserActiveRole(event)
|
|
|
|
// Get product IDs visible for the active role only
|
|
const visibleProductIds = await getVisibleProductIdsForRole(user.id, activeRole)
|
|
|
|
// If user has no access to products in their active role
|
|
if (visibleProductIds.length === 0) {
|
|
return []
|
|
}
|
|
|
|
// Build where conditions
|
|
const conditions = [
|
|
eq(products.active, true),
|
|
inArray(products.id, visibleProductIds), // Role-based filtering
|
|
]
|
|
|
|
// Filter by category if provided
|
|
if (categoryParam) {
|
|
const categories = categoryParam.split(',').map((c) => c.trim())
|
|
conditions.push(inArray(products.category, categories))
|
|
}
|
|
|
|
// Fetch products with filters
|
|
const visibleProducts = await db.query.products.findMany({
|
|
where: and(...conditions),
|
|
orderBy: (products, { asc }) => [asc(products.category), asc(products.name)],
|
|
})
|
|
|
|
return visibleProducts
|
|
} catch (error) {
|
|
console.error('Error fetching products:', error)
|
|
throw createError({
|
|
statusCode: 500,
|
|
statusMessage: 'Failed to fetch products',
|
|
})
|
|
}
|
|
})
|
|
|