- Scope update/destroy queries by userId (Computers & Components), matching the pattern already used in index/show/edit - Add missing auth.authenticate() calls on destroy actions - handleComponents now requires userId and scopes component lookups to the current user, preventing cross-user component takeover - handleComponents rejects attaching more than one component of the same 'unique' type to a computer (new InvalidComponentSelectionException, 422) - handlePictures scopes picture lookups by computerId - destroy(Computer) now detaches its components (computerId = null) instead of losing them to cascade delete, and removes the computer's uploads dir - Switch store/update actions to request.validateUsing() for consistency - Fix relative redirects to absolute paths (/computers, /computers/:id) - Untrack .env.production and add it to .gitignore (secrets must not be committed); local file kept on disk
86 lines
3.0 KiB
TypeScript
86 lines
3.0 KiB
TypeScript
import type { HttpContext } from '@adonisjs/core/http'
|
|
import { DateTime } from 'luxon'
|
|
import { storeComponentValidator } from '#validators/Components/store'
|
|
import { updateComponentValidator } from '#validators/Components/update'
|
|
import Component from '#models/component'
|
|
import ComponentType from '#models/component_type'
|
|
|
|
export default class ComponentsController {
|
|
async index({ inertia, auth }: HttpContext) {
|
|
const user = await auth.authenticate()
|
|
const components = await Component.query().preload('type').where('userId', user.id)
|
|
return inertia.render('components/index', { components: components.map((c) => c.serialize()) })
|
|
}
|
|
|
|
async create({ inertia }: HttpContext) {
|
|
const types = await ComponentType.all()
|
|
return inertia.render('components/create', { types: types.map((t) => t.serialize()) })
|
|
}
|
|
|
|
async store({ request, response, auth }: HttpContext) {
|
|
const user = await auth.authenticate()
|
|
const { quantity, ...componentData } = await request.validateUsing(storeComponentValidator)
|
|
await ComponentType.findOrFail(componentData.typeId)
|
|
for (let i = 0; i < quantity; i++) {
|
|
await Component.create({
|
|
...componentData,
|
|
purchaseDate: DateTime.fromFormat(componentData.purchaseDate, 'yyyy-MM-dd'),
|
|
userId: user.id,
|
|
})
|
|
}
|
|
response.redirect('/components')
|
|
}
|
|
|
|
async show({ params, auth, inertia }: HttpContext) {
|
|
const user = await auth.authenticate()
|
|
const componentId = params.id
|
|
const component = await Component.query()
|
|
.preload('type')
|
|
.where('userId', user.id)
|
|
.andWhere('id', componentId)
|
|
.firstOrFail()
|
|
return inertia.render('components/show', { component: component.serialize() })
|
|
}
|
|
|
|
async edit({ params, auth, inertia }: HttpContext) {
|
|
const user = await auth.authenticate()
|
|
const types = await ComponentType.all()
|
|
const componentId = params.id
|
|
const component = await Component.query()
|
|
.preload('type')
|
|
.where('userId', user.id)
|
|
.andWhere('id', componentId)
|
|
.firstOrFail()
|
|
return inertia.render('components/edit', {
|
|
component: component.serialize(),
|
|
types: types.map((t) => t.serialize()),
|
|
})
|
|
}
|
|
|
|
async update({ params, auth, request, response }: HttpContext) {
|
|
const user = await auth.authenticate()
|
|
const componentData = await request.validateUsing(updateComponentValidator)
|
|
const component = await Component.query()
|
|
.where('userId', user.id)
|
|
.andWhere('id', params.id)
|
|
.firstOrFail()
|
|
component.merge({
|
|
...componentData,
|
|
purchaseDate: DateTime.fromFormat(componentData.purchaseDate, 'yyyy-MM-dd'),
|
|
})
|
|
await component.save()
|
|
return response.redirect('/components')
|
|
}
|
|
|
|
async destroy({ params, auth, response }: HttpContext) {
|
|
const user = await auth.authenticate()
|
|
const componentId = params.id
|
|
const component = await Component.query()
|
|
.where('userId', user.id)
|
|
.andWhere('id', componentId)
|
|
.firstOrFail()
|
|
await component.delete()
|
|
return response.redirect('/components')
|
|
}
|
|
}
|