This commit is contained in:
Kiss Dávid
2026-03-29 11:18:31 +02:00
parent 1ebb2e53a9
commit d55e085741
16 changed files with 4130 additions and 0 deletions
+96
View File
@@ -0,0 +1,96 @@
import type { HttpContext } from '@adonisjs/core/http'
import Category from '#models/category'
import logger from '@adonisjs/core/services/logger'
import { createCategoryValidator, updateCategoryValidator } from '#validators/category'
export default class CategoriesController {
/**
* Retrieve all categories.
*
* @returns An array of all categories.
*/
async getAll() {
const categories = await Category.all()
return categories
}
/**
* Retrieve a single category.
*
* @param request - The HTTP context containing the request data.
* @returns The category with the specified id.
*/
async getOne({ request }: HttpContext) {
try {
const id = request.body().id
const category = await Category.find(id)
return category
} catch (error) {
logger.error('Category retrieval failed: %s', error)
}
}
/**
* Create a category.
*
* @bodyParam *name* - string | The name of the category.
* @bodyParam *slug* - string | The slug of the category.
* @returns The created category.
*/
async create({ request, auth }: HttpContext) {
try {
const data = await request.validateUsing(createCategoryValidator)
const category = await Category.create(data)
logger.info('Category created: %s by %s', category.name, auth.getUserOrFail().email)
return category
} catch (error) {
logger.error('Category creation failed: %s', error)
throw error
}
}
/**
* Update a category.
*
* @bodyParam *id* - number | The id of the category to update.
* @bodyParam *name* - string | The new name of the category.
* @bodyParam *slug* - string | The new slug of the category.
*/
async update({ request, auth }: HttpContext) {
try {
const data = await request.validateUsing(updateCategoryValidator)
const category = await Category.find(data.id)
if (!category) {
return { message: 'Category not found' }
}
category.merge(data)
await category.save()
logger.info('Category updated: %s by %s', category.name, auth.getUserOrFail().email)
return category
} catch (error) {
logger.error('Category update failed: %s', error)
throw error
}
}
/**
* Delete a category.
*
* @bodyParam *id* - number | The id of the category to delete.
*/
async delete({ request, auth }: HttpContext) {
const id = request.body().id
try {
const category = await Category.find(id)
if (!category) {
return { message: 'Category not found' }
}
await category.delete()
logger.info('Category deleted: %s by %s', category.name, auth.getUserOrFail().email)
return { message: 'Category deleted' }
} catch (error) {
logger.error('Category deletion failed: %s', error)
throw error
}
}
}
+74
View File
@@ -0,0 +1,74 @@
import type { HttpContext } from '@adonisjs/core/http'
import app from '@adonisjs/core/services/app'
import logger from '@adonisjs/core/services/logger'
import { cuid } from '@adonisjs/core/helpers'
import { createReadStream } from 'node:fs'
import { promises as fs } from 'node:fs'
import { extname } from 'node:path'
const allowedExtnames = ['jpg', 'jpeg', 'png', 'webp', 'gif']
const imageMimeByExt: Record<string, string> = {
'.jpg': 'image/jpeg',
'.jpeg': 'image/jpeg',
'.png': 'image/png',
'.webp': 'image/webp',
'.gif': 'image/gif',
}
export default class ImagesController {
async upload({ request, response }: HttpContext) {
const image = request.file('image', {
size: '10mb',
extnames: allowedExtnames,
})
if (!image) {
return response.badRequest({ message: 'Image file is required' })
}
if (!image.isValid) {
const message = image.errors.map((error) => error.message).join(', ')
return response.badRequest({ message: message || 'Invalid image file' })
}
const uploadsDir = app.makePath('storage', 'uploads')
await fs.mkdir(uploadsDir, { recursive: true })
const extension = image.extname || 'bin'
const filename = `${cuid()}.${extension}`
await image.move(uploadsDir, { name: filename, overwrite: false })
if (image.state !== 'moved') {
logger.error('Image upload failed: %s', image.errors)
return response.internalServerError({ message: 'Image upload failed' })
}
return response.ok({
filename,
url: `/api/images/${filename}`,
})
}
async show({ params, response }: HttpContext) {
const filename = String(params.filename || '')
if (!filename || filename.includes('/') || filename.includes('\\')) {
return response.badRequest({ message: 'Invalid image name' })
}
const filePath = app.makePath('storage', 'uploads', filename)
try {
await fs.access(filePath)
} catch {
return response.notFound({ message: 'Image not found' })
}
const mimeType = imageMimeByExt[extname(filename).toLowerCase()] || 'application/octet-stream'
response.header('Content-Type', mimeType)
response.header('Cache-Control', 'public, max-age=86400')
return response.stream(createReadStream(filePath))
}
}
+93
View File
@@ -0,0 +1,93 @@
import type { HttpContext } from '@adonisjs/core/http'
import User from '#models/user'
import logger from '@adonisjs/core/services/logger'
import { createUserValidator, updateUserValidator } from '#validators/user'
export default class UsersController {
/**
* Retrieve all users.
*
* @returns An array of all users.
*/
async getAll() {
const users = await User.all()
return users
}
/**
* Retrieve a single user.
*
* @param request - The HTTP context containing the request data.
* @returns The user with the specified id.
*/
async getOne({ request, response }: HttpContext) {
try {
const id = request.body().id
const user = await User.find(id)
if (!user) {
return response.notFound({ message: 'User not found' })
}
return user
} catch (error) {
logger.error('User retrieval failed: %s', error)
return response.internalServerError({ message: 'User retrieval failed' })
}
}
async create({ request, auth, response }: HttpContext) {
try {
const data = await request.validateUsing(createUserValidator)
const user = await User.create(data)
logger.info('User created: %s by %s', user.email, auth.getUserOrFail().email)
return user
} catch (error) {
logger.error('User creation failed: %s', error)
return response.internalServerError({ message: 'User creation failed' })
}
}
/**
* Update a user.
*
* @bodyParam *id* - number | The id of the user to update.
* @bodyParam *email* - string | The new email of the user.
* @bodyParam *fullName* - string | The new full name of the user.
* @bodyParam *role* - string | The new role of the user.
*/
async update({ request, auth, response }: HttpContext) {
try {
const data = await request.validateUsing(updateUserValidator)
const user = await User.find(data.id)
if (!user) {
return response.notFound({ message: 'User not found' })
}
user.merge(data)
await user.save()
logger.info('User updated: %s by %s', user.email, auth.getUserOrFail().email)
return user
} catch (error) {
logger.error('User update failed: %s', error)
return response.internalServerError({ message: 'User update failed' })
}
}
/**
* Delete a user.
*
* @bodyParam *id* - number | The id of the user to delete.
*/
async delete({ request, auth, response }: HttpContext) {
const id = request.body().id
try {
const user = await User.find(id)
if (!user) {
return response.notFound({ message: 'User not found' })
}
await user.delete()
logger.info('User deleted: %s by %s', user.email, auth.getUserOrFail().email)
return response.ok({ message: 'User deleted' })
} catch (error) {
logger.error('User deletion failed: %s', error)
return response.internalServerError({ message: 'User deletion failed' })
}
}
}