Files
stepview/src/server/routes/viewer.ts
T
2026-04-22 15:47:27 -05:00

80 lines
2.5 KiB
TypeScript

import { Router, Request, Response } from 'express'
import path from 'path'
import fs from 'fs'
import { q, Model, ModelPdf, Category } from '../db/index'
import { geometryOutputPath } from '../services/stepConverter'
const UPLOADS_DIR = process.env.UPLOADS_DIR ?? path.join(process.cwd(), 'uploads')
const router = Router()
router.get('/view/:slug', (req: Request, res: Response) => {
const model = q<Model & { category_name: string | null }>(`
SELECT m.*, c.name AS category_name
FROM models m
LEFT JOIN categories c ON c.id = m.category_id
WHERE m.slug = ?
`).get(req.params.slug)
if (!model) {
res.status(404).render('error', { status: 404, message: 'Model not found.' })
return
}
if (!model.is_public && !(req.session as { isAdmin?: boolean }).isAdmin) {
res.status(403).render('error', { status: 403, message: 'This model is not publicly available.' })
return
}
const pdfs = q<ModelPdf>(`SELECT * FROM model_pdfs WHERE model_id = ? ORDER BY sort_order`).all(model.id)
const baseUrl = process.env.BASE_URL ?? `http://localhost:${process.env.PORT ?? 3000}`
// Determine whether pre-processed geometry is available for STEP/STP
let hasGeometry = false
if (model.file_type === 'step' || model.file_type === 'stp') {
const absPath = path.resolve(UPLOADS_DIR, model.file_path)
hasGeometry = fs.existsSync(geometryOutputPath(absPath))
}
res.render('viewer', {
model,
pdfs,
shareUrl: `${baseUrl}/view/${model.slug}`,
hasGeometry,
})
})
// ---- Public model index --------------------------------------------------
router.get('/', (_req: Request, res: Response) => {
// Fetch categories that have at least one public model, plus their models
const categories = q<Category & { model_count: number }>(`
SELECT c.*, COUNT(m.id) AS model_count
FROM categories c
INNER JOIN models m ON m.category_id = c.id AND m.is_public = 1
GROUP BY c.id
HAVING model_count > 0
ORDER BY c.sort_order, c.name
`).all()
// For each category, fetch its models
const categorised = categories.map(cat => ({
category: cat,
models: q<Model>(`
SELECT * FROM models
WHERE is_public = 1 AND category_id = ?
ORDER BY created_at DESC
`).all(cat.id),
}))
const uncategorized = q<Model>(`
SELECT * FROM models
WHERE is_public = 1 AND category_id IS NULL
ORDER BY created_at DESC
`).all()
res.render('index', { categorised, uncategorized })
})
export default router