Wire Newbook credentials to settings service
This commit is contained in:
commit
63a5a72fa3
32 changed files with 3386 additions and 0 deletions
99
backend/src/index.js
Normal file
99
backend/src/index.js
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
import Fastify from 'fastify'
|
||||
import cookie from '@fastify/cookie'
|
||||
import cors from '@fastify/cors'
|
||||
import multipart from '@fastify/multipart'
|
||||
import staticFiles from '@fastify/static'
|
||||
import { fileURLToPath } from 'url'
|
||||
import { dirname, join } from 'path'
|
||||
import { initDb } from './db.js'
|
||||
import { cashupRoutes } from './routes/cashup.js'
|
||||
import { newbookRoutes } from './routes/newbook.js'
|
||||
import { reportRoutes } from './routes/reports.js'
|
||||
import { floatRoutes } from './routes/floats.js'
|
||||
import { settingsRoutes } from './routes/settings.js'
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
const UPLOADS_DIR = join(__dirname, '..', '..', 'uploads')
|
||||
|
||||
const app = Fastify({ logger: true, trustProxy: true })
|
||||
|
||||
await app.register(cookie)
|
||||
await app.register(cors, {
|
||||
origin: process.env.CORS_ORIGIN || false,
|
||||
credentials: true,
|
||||
})
|
||||
await app.register(multipart, { limits: { fileSize: 10 * 1024 * 1024 } })
|
||||
await app.register(staticFiles, {
|
||||
root: UPLOADS_DIR,
|
||||
prefix: '/api/uploads/',
|
||||
decorateReply: false,
|
||||
})
|
||||
|
||||
app.get('/health', async () => ({ status: 'healthy' }))
|
||||
|
||||
await app.register(cashupRoutes)
|
||||
await app.register(newbookRoutes)
|
||||
await app.register(reportRoutes)
|
||||
await app.register(floatRoutes)
|
||||
await app.register(settingsRoutes)
|
||||
|
||||
// File upload for cash up receipt attachments
|
||||
import { requireAuth } from './auth.js'
|
||||
import { pool } from './db.js'
|
||||
import { createWriteStream } from 'fs'
|
||||
import { mkdir } from 'fs/promises'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { extname } from 'path'
|
||||
|
||||
app.post('/api/attachments/upload/:cash_up_id', { preHandler: requireAuth }, async (req, reply) => {
|
||||
const cashUpId = parseInt(req.params.cash_up_id)
|
||||
const { rows } = await pool.query('SELECT id FROM cash_ups WHERE id = $1', [cashUpId])
|
||||
if (!rows.length) return reply.status(404).send({ error: 'Cash up not found' })
|
||||
|
||||
const data = await req.file()
|
||||
if (!data) return reply.status(400).send({ error: 'No file uploaded' })
|
||||
|
||||
const allowed = ['image/jpeg', 'image/jpg', 'image/png', 'application/pdf']
|
||||
if (!allowed.includes(data.mimetype)) {
|
||||
return reply.status(400).send({ error: 'Only JPEG, PNG and PDF files are allowed' })
|
||||
}
|
||||
|
||||
const ext = extname(data.filename) || '.bin'
|
||||
const filename = randomUUID() + ext
|
||||
const dir = join(UPLOADS_DIR, 'cashup', String(cashUpId))
|
||||
await mkdir(dir, { recursive: true })
|
||||
|
||||
let size = 0
|
||||
const dest = createWriteStream(join(dir, filename))
|
||||
for await (const chunk of data.file) { dest.write(chunk); size += chunk.length }
|
||||
await new Promise(r => dest.end(r))
|
||||
|
||||
const filePath = `/cashup/${cashUpId}/${filename}`
|
||||
const { rows: ins } = await pool.query(
|
||||
`INSERT INTO cash_count_attachments (cash_up_id, file_name, file_path, file_size, mime_type, uploaded_by)
|
||||
VALUES ($1,$2,$3,$4,$5,$6) RETURNING *`,
|
||||
[cashUpId, data.filename, filePath, size, data.mimetype, req.user.email]
|
||||
)
|
||||
|
||||
return ins.rows[0]
|
||||
})
|
||||
|
||||
app.delete('/api/attachments/:id', { preHandler: requireAuth }, async (req, reply) => {
|
||||
const { rows } = await pool.query('SELECT * FROM cash_count_attachments WHERE id = $1', [req.params.id])
|
||||
if (!rows.length) return reply.status(404).send({ error: 'Not found' })
|
||||
|
||||
// Delete file from disk (best effort)
|
||||
const { unlink } = await import('fs/promises')
|
||||
await unlink(join(UPLOADS_DIR, rows[0].file_path)).catch(() => {})
|
||||
|
||||
await pool.query('DELETE FROM cash_count_attachments WHERE id = $1', [req.params.id])
|
||||
return { message: 'Deleted' }
|
||||
})
|
||||
|
||||
try {
|
||||
await initDb()
|
||||
await app.listen({ port: 3001, host: '0.0.0.0' })
|
||||
} catch (err) {
|
||||
app.log.error(err)
|
||||
process.exit(1)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue