Model controllers added

This commit is contained in:
Kiss Dávid
2025-07-28 13:00:46 +02:00
parent 590adb271d
commit 465613f6a0
17 changed files with 470 additions and 100 deletions
+12
View File
@@ -0,0 +1,12 @@
TZ=UTC
PORT=3333
HOST=localhost
LOG_LEVEL=info
APP_KEY=
NODE_ENV=test
DB_HOST=localhost
DB_PORT=5432
DB_USER=paprika
DB_PASSWORD=Paprika_2025
DB_DATABASE=paprika_test
LIMITER_STORE=database
+33 -1
View File
@@ -5,11 +5,19 @@ import logger from '@adonisjs/core/services/logger'
export default class AuthController { export default class AuthController {
/**
* Registers a user using the provided email, password, and full name.
*
* @bodyParam *email* - string | The email of the user.
* @bodyParam *password* - string | The password of the user.
* @bodyParam *fullName* - string | The full name of the user.
* @returns The user access token.
*/
async register({ request }: HttpContext) { async register({ request }: HttpContext) {
try { try {
const data = await request.validateUsing(registerValidator) const data = await request.validateUsing(registerValidator)
const user = await User.create(data) const user = await User.create(data)
logger.info('User registered: %s', user.fullName, user.email, request.ip()) logger.info('User registered: %s, %s, %s', user.fullName, user.email, request.ip())
return User.accessTokens.create(user) return User.accessTokens.create(user)
} }
catch(error) { catch(error) {
@@ -18,6 +26,13 @@ export default class AuthController {
} }
} }
/**
* Log in a user using the provided email and password.
*
* @bodyParam *email* - string | The email of the user.
* @bodyParam *password* - string | The password of the user.
* @returns The access token of the user.
*/
async login({ request }: HttpContext) { async login({ request }: HttpContext) {
try { try {
const { email, password } = await request.validateUsing(loginValidator) const { email, password } = await request.validateUsing(loginValidator)
@@ -31,6 +46,14 @@ export default class AuthController {
} }
} }
/**
* Deletes the user's access token and logs them out. If the user is not
* authenticated, returns an unauthorized message.
*/
async logout({ auth }: HttpContext) { async logout({ auth }: HttpContext) {
const user = auth.user! const user = auth.user!
logger.info('User logout: %s', auth.getUserOrFail().email) logger.info('User logout: %s', auth.getUserOrFail().email)
@@ -44,6 +67,15 @@ export default class AuthController {
} }
} }
/**
* Retrieves the authenticated user's information if authenticated,
* otherwise deletes the access token and returns an unauthorized message.
*
* @param auth - The HTTP context's auth object.
* @returns An object containing the user data if authenticated,
* otherwise an unauthorized message.
*/
async me({ auth }: HttpContext) { async me({ auth }: HttpContext) {
if (await auth.check()) { if (await auth.check()) {
return { user: auth.user } return { user: auth.user }
@@ -0,0 +1,120 @@
import type { HttpContext } from '@adonisjs/core/http'
import RestaurantMenuItem from '#models/restaurant_menu_item'
import logger from '@adonisjs/core/services/logger'
import { menuItemValidator } from '#validators/menu'
export default class RestaurantMenuItemsController {
/**
* Retrieve all restaurant menu items.
*
* @returns An array of all restaurant menu items.
*/
async getAll() {
const items = await RestaurantMenuItem.all()
return items
}
/**
* Retrieve a single restaurant menu item.
*
* @param request - The HTTP context containing the request data.
* @returns The restaurant menu item with the specified id.
*/
async getOne({request}: HttpContext) {
try {
const id = request.body().id
const item = await RestaurantMenuItem.find(id)
return item
}
catch (error) {
logger.error('Menu item retrieval failed: %s',error)
}
}
// The following methods require authentication. Log user activity.
/**
* Create a restaurant menu item.
*
* @bodyParam *name* - string | The name of the menu item.
* @bodyParam *priceSmall* - number | The price of the small serving of the menu item.
* @bodyParam *priceLarge* - number | The price of the large serving of the menu item.
* @bodyParam *description* - string | The description of the menu item.
* @bodyParam *menu_id* - number | The menu id of the menu item.
* @returns The created menu item.
*/
async create({request, auth}: HttpContext) {
const data = await request.validateUsing(menuItemValidator)
try {
const item = await RestaurantMenuItem.create(data)
logger.info('Menu item created: %s by %s', item.name, auth.getUserOrFail().email)
return item
}
catch(error) {
logger.error('Menu item creation failed: %s',error)
}
}
/**
* Update a restaurant menu item.
*
* @bodyParam *id* - number | The id of the menu item to update.
* @bodyParam *name* - string | The new name of the menu item.
* @bodyParam *priceSmall* - number | The new price of the small size of the menu item.
* @bodyParam *priceLarge* - number | The new price of the large size of the menu item.
* @bodyParam *description* - string | The new description of the menu item.
* @bodyParam *menu_id* - number | The new menu id of the menu item.
*/
async update({request, auth}: HttpContext) {
const data = request.body()
try {
const item = await RestaurantMenuItem.find(data.id)
item?.merge(data)
await item?.save()
logger.info('Menu item updated: %s by %s', item?.name, auth.getUserOrFail().email)
}
catch(error) {
logger.error('Menu item update failed: %s',error)
}
}
/**
* Delete a restaurant menu item.
*
* @bodyParam *id* - number | The id of the menu item to delete.
*/
async delete({request, auth}: HttpContext) {
const id = request.body().id
try {
const item = await RestaurantMenuItem.find(id)
await item?.delete()
logger.info('Menu item deleted: %s by %s', item?.name, auth.getUserOrFail().email)
}
catch(error) {
logger.error('Menu item deletion failed: %s',error)
}
}
// This method connects the menu item to a menu.
/**
* Connect a restaurant menu item to a restaurant menu.
*
* @bodyParam *item_id* - number | The id of the menu item to connect.
* @bodyParam *menu_id* - number | The id of the menu to connect the menu item to.
*/
async connectToMenu({request}: HttpContext) {
const data = request.body()
try {
const item = await RestaurantMenuItem.find(data.item_id)
const menu = await data.menu_id
item?.merge({menu_id: menu})
await item?.save()
}
catch(error) {
logger.error('Menu item connection failed: %s',error)
}
}
}
@@ -0,0 +1,90 @@
// import type { HttpContext } from '@adonisjs/core/http'
import RestaurantMenu from "#models/restaurant_menu"
import { HttpContext } from "@adonisjs/core/http"
import logger from "@adonisjs/core/services/logger"
export default class RestaurantMenusController {
/**
* Retrieve all restaurant menus.
*
* @returns An array of all restaurant menus.
*/
async getAll() {
const menus = await RestaurantMenu.all()
return menus
}
/**
* Retrieve a restaurant menu.
*
* @bodyParam id number The id of the menu to retrieve.
* @returns The retrieved menu.
*/
async getOne({ request }: HttpContext) {
const id = request.body().id
try {
const menu = await RestaurantMenu.find(id)
return menu
}
catch (error) {
logger.error('Menu retrieval failed: %s', error)
}
}
/**
* Create a restaurant menu.
*
* @bodyParam name string The name of the menu.
* @bodyParam description string The description of the menu.
* @returns The created menu.
*/
async create({ request, auth }: HttpContext) {
const data = request.body()
try {
const menu = await RestaurantMenu.create(data)
logger.info('Menu created: %s by %s', menu.name, auth.getUserOrFail().email)
return menu
}
catch (error) {
logger.error('Menu creation failed: %s', error)
}
}
/**
* Update a restaurant menu.
*
* @bodyParam id number The id of the menu to update.
* @bodyParam name string The new name of the menu.
*/
async update({ request, auth }: HttpContext) {
const data = request.body()
try {
const menu = await RestaurantMenu.find(data.id)
menu?.merge(data)
await menu?.save()
logger.info('Menu updated: %s by %s', menu?.name, auth.getUserOrFail().email)
}
catch (error) {
logger.error('Menu update failed: %s', error)
}
}
/**
* Delete a restaurant menu.
*
* @bodyParam id number The id of the menu to delete.
*/
async delete({ request, auth }: HttpContext) {
const id = request.body().id
try {
const menu = await RestaurantMenu.find(id)
await menu?.delete()
logger.info('Menu deleted: %s by %s', menu?.name, auth.getUserOrFail().email)
}
catch (error) {
logger.error('Menu deletion failed: %s', error)
}
}
}
+9 -1
View File
@@ -1,5 +1,7 @@
import { DateTime } from 'luxon' import { DateTime } from 'luxon'
import { BaseModel, column } from '@adonisjs/lucid/orm' import { BaseModel, column, hasMany } from '@adonisjs/lucid/orm'
import type { HasMany } from '@adonisjs/lucid/types/relations'
import RestaurantMenuItem from './restaurant_menu_item.js'
export default class RestaurantMenu extends BaseModel { export default class RestaurantMenu extends BaseModel {
@column({ isPrimary: true }) @column({ isPrimary: true })
@@ -10,4 +12,10 @@ export default class RestaurantMenu extends BaseModel {
@column.dateTime({ autoCreate: true, autoUpdate: true }) @column.dateTime({ autoCreate: true, autoUpdate: true })
declare updatedAt: DateTime declare updatedAt: DateTime
@column()
declare name: string
@hasMany(() => RestaurantMenuItem)
declare items: HasMany<typeof RestaurantMenuItem>
} }
+18
View File
@@ -10,4 +10,22 @@ export default class RestaurantMenuItem extends BaseModel {
@column.dateTime({ autoCreate: true, autoUpdate: true }) @column.dateTime({ autoCreate: true, autoUpdate: true })
declare updatedAt: DateTime declare updatedAt: DateTime
@column()
declare name: string
@column()
declare priceSmall: number
@column()
declare priceLarge: number
@column()
declare description: string | null
//connet to restaurant_menu
@column()
declare menu_id: number | null
} }
+1
View File
@@ -13,6 +13,7 @@ export const registerValidator = vine.compile(
return !match return !match
}), }),
password, password,
fullName: vine.string()
}) })
) )
export const loginValidator = vine.compile( export const loginValidator = vine.compile(
+10
View File
@@ -0,0 +1,10 @@
import vine from "@vinejs/vine";
export const menuItemValidator = vine.compile(
vine.object({
name: vine.string(),
priceSmall: vine.number(),
priceLarge: vine.number(),
description: vine.string(),
})
);
+6 -1
View File
@@ -9,12 +9,17 @@
| command to run this file and monitor file changes. | command to run this file and monitor file changes.
| |
*/ */
process.env.NODE_ENV = 'test' process.env.NODE_ENV = 'test'
import 'reflect-metadata' import 'reflect-metadata'
import { Ignitor, prettyPrintError } from '@adonisjs/core' import { Ignitor, prettyPrintError } from '@adonisjs/core'
import { configure, processCLIArgs, run } from '@japa/runner' import { configure, processCLIArgs, run } from '@japa/runner'
import { apiClient } from '@japa/api-client'
configure({
files: ['tests/**/*.spec.js'],
plugins: [apiClient('https://localhost:3333')]
})
/** /**
* URL to the application root. AdonisJS need it to resolve * URL to the application root. AdonisJS need it to resolve
+1 -1
View File
@@ -10,7 +10,7 @@ const limiterConfig = defineConfig({
*/ */
database: stores.database({ database: stores.database({
connectionName: 'postgres', connectionName: 'postgres',
dbName:'paprika', dbName: env.get('DB_DATABASE'),
tableName: 'rate_limits', tableName: 'rate_limits',
clearExpiredByTimeout: false clearExpiredByTimeout: false
}), }),
@@ -0,0 +1,20 @@
import { BaseSchema } from '@adonisjs/lucid/schema'
export default class extends BaseSchema {
protected tableName = 'restaurant_menus'
async up() {
this.schema.createTable(this.tableName, (table) => {
table.increments('id').primary()
table.string('name').notNullable()
table.timestamp('created_at')
table.timestamp('updated_at')
})
}
async down() {
this.schema.dropTable(this.tableName)
}
}
@@ -0,0 +1,23 @@
import { BaseSchema } from '@adonisjs/lucid/schema'
export default class extends BaseSchema {
protected tableName = 'restaurant_menu_items'
async up() {
this.schema.createTable(this.tableName, (table) => {
table.increments('id').primary()
table.integer('restaurant_menu_id').unsigned().references('restaurant_menus.id')
table.string('name').notNullable()
table.integer('price_small').notNullable()
table.integer('price_large').notNullable()
table.string('description').nullable()
table.timestamp('created_at')
table.timestamp('updated_at')
})
}
async down() {
this.schema.dropTable(this.tableName)
}
}
+77 -93
View File
@@ -24,7 +24,7 @@
"@adonisjs/eslint-config": "^2.0.0", "@adonisjs/eslint-config": "^2.0.0",
"@adonisjs/prettier-config": "^1.4.0", "@adonisjs/prettier-config": "^1.4.0",
"@adonisjs/tsconfig": "^1.4.0", "@adonisjs/tsconfig": "^1.4.0",
"@japa/api-client": "^3.0.3", "@japa/api-client": "^3.1.0",
"@japa/assert": "^4.0.1", "@japa/assert": "^4.0.1",
"@japa/plugin-adonisjs": "^4.0.0", "@japa/plugin-adonisjs": "^4.0.0",
"@japa/runner": "^4.2.0", "@japa/runner": "^4.2.0",
@@ -744,9 +744,9 @@
} }
}, },
"node_modules/@eslint/config-array": { "node_modules/@eslint/config-array": {
"version": "0.20.0", "version": "0.21.0",
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.0.tgz", "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz",
"integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==", "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
@@ -759,9 +759,9 @@
} }
}, },
"node_modules/@eslint/config-array/node_modules/brace-expansion": { "node_modules/@eslint/config-array/node_modules/brace-expansion": {
"version": "1.1.11", "version": "1.1.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -783,9 +783,9 @@
} }
}, },
"node_modules/@eslint/config-helpers": { "node_modules/@eslint/config-helpers": {
"version": "0.2.1", "version": "0.3.0",
"resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.1.tgz", "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.0.tgz",
"integrity": "sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw==", "integrity": "sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"engines": { "engines": {
@@ -793,9 +793,9 @@
} }
}, },
"node_modules/@eslint/core": { "node_modules/@eslint/core": {
"version": "0.12.0", "version": "0.15.1",
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.12.0.tgz", "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.1.tgz",
"integrity": "sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==", "integrity": "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
@@ -830,9 +830,9 @@
} }
}, },
"node_modules/@eslint/eslintrc/node_modules/brace-expansion": { "node_modules/@eslint/eslintrc/node_modules/brace-expansion": {
"version": "1.1.11", "version": "1.1.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -854,13 +854,16 @@
} }
}, },
"node_modules/@eslint/js": { "node_modules/@eslint/js": {
"version": "9.24.0", "version": "9.31.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.24.0.tgz", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.31.0.tgz",
"integrity": "sha512-uIY/y3z0uvOGX8cp1C2fiC4+ZmBhp6yZWkojtHL1YEMnRt1Y63HB9TM17proGEmeG7HeUY+UP36F0aknKYTpYA==", "integrity": "sha512-LOm5OVt7D4qiKCqoiPbA7LWmI+tbw1VbTUowBcUMgQSuM6poJufkFkYDcQpo5KfgD39TnNySV26QjOh7VFpSyw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://eslint.org/donate"
} }
}, },
"node_modules/@eslint/object-schema": { "node_modules/@eslint/object-schema": {
@@ -874,32 +877,19 @@
} }
}, },
"node_modules/@eslint/plugin-kit": { "node_modules/@eslint/plugin-kit": {
"version": "0.2.8", "version": "0.3.4",
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz", "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.4.tgz",
"integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==", "integrity": "sha512-Ul5l+lHEcw3L5+k8POx6r74mxEYKG5kOb6Xpy2gCRW6zweT6TEhAf8vhxGgjhqrd/VO/Dirhsb+1hNpD1ue9hw==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@eslint/core": "^0.13.0", "@eslint/core": "^0.15.1",
"levn": "^0.4.1" "levn": "^0.4.1"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
} }
}, },
"node_modules/@eslint/plugin-kit/node_modules/@eslint/core": {
"version": "0.13.0",
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz",
"integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@types/json-schema": "^7.0.15"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
"node_modules/@faker-js/faker": { "node_modules/@faker-js/faker": {
"version": "9.7.0", "version": "9.7.0",
"resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-9.7.0.tgz", "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-9.7.0.tgz",
@@ -983,9 +973,9 @@
} }
}, },
"node_modules/@japa/api-client": { "node_modules/@japa/api-client": {
"version": "3.0.4", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/@japa/api-client/-/api-client-3.0.4.tgz", "resolved": "https://registry.npmjs.org/@japa/api-client/-/api-client-3.1.0.tgz",
"integrity": "sha512-MSjC8Ds4jjcuKM+2tm4uUjQQ8Jg13ggPRsQGJ3DxKJ3pC39JWsAYedgDU7G18OK7R6GsdC1glKJieFtuqilfVw==", "integrity": "sha512-wrJVRgu8kF7odTnpNCsV6zpQgNOBrer3BHVBXm3qnS0FiqLlv8a6UZ5EKOqoLSRwfHV0LwBE7kcZq9f4yTvUfw==",
"devOptional": true, "devOptional": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -994,7 +984,7 @@
"@types/superagent": "^8.1.9", "@types/superagent": "^8.1.9",
"cookie": "^1.0.2", "cookie": "^1.0.2",
"set-cookie-parser": "^2.7.1", "set-cookie-parser": "^2.7.1",
"superagent": "^10.2.0" "superagent": "^10.2.1"
}, },
"engines": { "engines": {
"node": ">=18.16.0" "node": ">=18.16.0"
@@ -2146,9 +2136,9 @@
} }
}, },
"node_modules/acorn": { "node_modules/acorn": {
"version": "8.14.1", "version": "8.15.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
"integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"bin": { "bin": {
@@ -3294,20 +3284,20 @@
} }
}, },
"node_modules/eslint": { "node_modules/eslint": {
"version": "9.24.0", "version": "9.31.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.24.0.tgz", "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.31.0.tgz",
"integrity": "sha512-eh/jxIEJyZrvbWRe4XuVclLPDYSYYYgLy5zXGGxD6j8zjSAxFEzI2fL/8xNq6O2yKqVt+eF2YhV+hxjV6UKXwQ==", "integrity": "sha512-QldCVh/ztyKJJZLr4jXNUByx3gR+TDYZCRXEktiZoUR3PGy4qCmSbkxcIle8GEwGpb5JBZazlaJ/CxLidXdEbQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.12.1", "@eslint-community/regexpp": "^4.12.1",
"@eslint/config-array": "^0.20.0", "@eslint/config-array": "^0.21.0",
"@eslint/config-helpers": "^0.2.0", "@eslint/config-helpers": "^0.3.0",
"@eslint/core": "^0.12.0", "@eslint/core": "^0.15.0",
"@eslint/eslintrc": "^3.3.1", "@eslint/eslintrc": "^3.3.1",
"@eslint/js": "9.24.0", "@eslint/js": "9.31.0",
"@eslint/plugin-kit": "^0.2.7", "@eslint/plugin-kit": "^0.3.1",
"@humanfs/node": "^0.16.6", "@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/module-importer": "^1.0.1",
"@humanwhocodes/retry": "^0.4.2", "@humanwhocodes/retry": "^0.4.2",
@@ -3318,9 +3308,9 @@
"cross-spawn": "^7.0.6", "cross-spawn": "^7.0.6",
"debug": "^4.3.2", "debug": "^4.3.2",
"escape-string-regexp": "^4.0.0", "escape-string-regexp": "^4.0.0",
"eslint-scope": "^8.3.0", "eslint-scope": "^8.4.0",
"eslint-visitor-keys": "^4.2.0", "eslint-visitor-keys": "^4.2.1",
"espree": "^10.3.0", "espree": "^10.4.0",
"esquery": "^1.5.0", "esquery": "^1.5.0",
"esutils": "^2.0.2", "esutils": "^2.0.2",
"fast-deep-equal": "^3.1.3", "fast-deep-equal": "^3.1.3",
@@ -3446,9 +3436,9 @@
} }
}, },
"node_modules/eslint-scope": { "node_modules/eslint-scope": {
"version": "8.3.0", "version": "8.4.0",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
"integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==", "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
"dev": true, "dev": true,
"license": "BSD-2-Clause", "license": "BSD-2-Clause",
"dependencies": { "dependencies": {
@@ -3463,9 +3453,9 @@
} }
}, },
"node_modules/eslint-visitor-keys": { "node_modules/eslint-visitor-keys": {
"version": "4.2.0", "version": "4.2.1",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
"integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"engines": { "engines": {
@@ -3476,9 +3466,9 @@
} }
}, },
"node_modules/eslint/node_modules/brace-expansion": { "node_modules/eslint/node_modules/brace-expansion": {
"version": "1.1.11", "version": "1.1.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -3509,15 +3499,15 @@
} }
}, },
"node_modules/espree": { "node_modules/espree": {
"version": "10.3.0", "version": "10.4.0",
"resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
"integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
"dev": true, "dev": true,
"license": "BSD-2-Clause", "license": "BSD-2-Clause",
"dependencies": { "dependencies": {
"acorn": "^8.14.0", "acorn": "^8.15.0",
"acorn-jsx": "^5.3.2", "acorn-jsx": "^5.3.2",
"eslint-visitor-keys": "^4.2.0" "eslint-visitor-keys": "^4.2.1"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -3851,15 +3841,16 @@
} }
}, },
"node_modules/form-data": { "node_modules/form-data": {
"version": "4.0.2", "version": "4.0.4",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
"integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
"devOptional": true, "devOptional": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"asynckit": "^0.4.0", "asynckit": "^0.4.0",
"combined-stream": "^1.0.8", "combined-stream": "^1.0.8",
"es-set-tostringtag": "^2.1.0", "es-set-tostringtag": "^2.1.0",
"hasown": "^2.0.2",
"mime-types": "^2.1.12" "mime-types": "^2.1.12"
}, },
"engines": { "engines": {
@@ -3867,16 +3858,19 @@
} }
}, },
"node_modules/formidable": { "node_modules/formidable": {
"version": "3.5.2", "version": "3.5.4",
"resolved": "https://registry.npmjs.org/formidable/-/formidable-3.5.2.tgz", "resolved": "https://registry.npmjs.org/formidable/-/formidable-3.5.4.tgz",
"integrity": "sha512-Jqc1btCy3QzRbJaICGwKcBfGWuLADRerLzDqi2NwSt/UkXLsHJw2TVResiaoBufHVHy9aSgClOHCeJsSsFLTbg==", "integrity": "sha512-YikH+7CUTOtP44ZTnUhR7Ic2UASBPOqmaRkRKxRbywPTe5VxF7RRCck4af9wutiZ/QKM5nME9Bie2fFaPz5Gug==",
"devOptional": true, "devOptional": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@paralleldrive/cuid2": "^2.2.2",
"dezalgo": "^1.0.4", "dezalgo": "^1.0.4",
"hexoid": "^2.0.0",
"once": "^1.4.0" "once": "^1.4.0"
}, },
"engines": {
"node": ">=14.0.0"
},
"funding": { "funding": {
"url": "https://ko-fi.com/tunnckoCore/commissions" "url": "https://ko-fi.com/tunnckoCore/commissions"
} }
@@ -4173,16 +4167,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/hexoid": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/hexoid/-/hexoid-2.0.0.tgz",
"integrity": "sha512-qlspKUK7IlSQv2o+5I7yhUd7TxlOG2Vr5LTa3ve2XSNVKAL/n/u/7KLvKmFNimomDIKvZFXWHv0T12mv7rT8Aw==",
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/hosted-git-info": { "node_modules/hosted-git-info": {
"version": "7.0.2", "version": "7.0.2",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz",
@@ -6932,21 +6916,21 @@
} }
}, },
"node_modules/superagent": { "node_modules/superagent": {
"version": "10.2.0", "version": "10.2.3",
"resolved": "https://registry.npmjs.org/superagent/-/superagent-10.2.0.tgz", "resolved": "https://registry.npmjs.org/superagent/-/superagent-10.2.3.tgz",
"integrity": "sha512-IKeoGox6oG9zyDeizaezkJ2/aK0wc5la9st7WsAKyrAkfJ56W3whVbVtF68k6wuc87/y9T85NyON5FLz7Mrzzw==", "integrity": "sha512-y/hkYGeXAj7wUMjxRbB21g/l6aAEituGXM9Rwl4o20+SX3e8YOSV6BxFXl+dL3Uk0mjSL3kCbNkwURm8/gEDig==",
"devOptional": true, "devOptional": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"component-emitter": "^1.3.0", "component-emitter": "^1.3.1",
"cookiejar": "^2.1.4", "cookiejar": "^2.1.4",
"debug": "^4.3.4", "debug": "^4.3.7",
"fast-safe-stringify": "^2.1.1", "fast-safe-stringify": "^2.1.1",
"form-data": "^4.0.0", "form-data": "^4.0.4",
"formidable": "^3.5.2", "formidable": "^3.5.4",
"methods": "^1.1.2", "methods": "^1.1.2",
"mime": "2.6.0", "mime": "2.6.0",
"qs": "^6.11.0" "qs": "^6.11.2"
}, },
"engines": { "engines": {
"node": ">=14.18.0" "node": ">=14.18.0"
+1 -1
View File
@@ -36,7 +36,7 @@
"@adonisjs/eslint-config": "^2.0.0", "@adonisjs/eslint-config": "^2.0.0",
"@adonisjs/prettier-config": "^1.4.0", "@adonisjs/prettier-config": "^1.4.0",
"@adonisjs/tsconfig": "^1.4.0", "@adonisjs/tsconfig": "^1.4.0",
"@japa/api-client": "^3.0.3", "@japa/api-client": "^3.1.0",
"@japa/assert": "^4.0.1", "@japa/assert": "^4.0.1",
"@japa/plugin-adonisjs": "^4.0.0", "@japa/plugin-adonisjs": "^4.0.0",
"@japa/runner": "^4.2.0", "@japa/runner": "^4.2.0",
+20
View File
@@ -12,8 +12,28 @@ import { middleware } from '#start/kernel'
import { throttle } from '#start/limiter' import { throttle } from '#start/limiter'
const AuthController = () => import('#controllers/auth_controller') const AuthController = () => import('#controllers/auth_controller')
const RestaurantMenuItemsController = () => import('#controllers/restaurant_menu_items_controller')
const RestaurantMenusController = () => import('#controllers/restaurant_menus_controller')
//Auth routes
router.post('/register', [AuthController, 'register']).as('auth.register').use(throttle) router.post('/register', [AuthController, 'register']).as('auth.register').use(throttle)
router.post('/login', [AuthController, 'login']).as('auth.login').use(throttle) router.post('/login', [AuthController, 'login']).as('auth.login').use(throttle)
router.delete('/logout', [AuthController, 'logout']).as('auth.logout').use(middleware.auth()) router.delete('/logout', [AuthController, 'logout']).as('auth.logout').use(middleware.auth())
router.get('/me', [AuthController, 'me']).as('auth.me').use(middleware.auth()) router.get('/me', [AuthController, 'me']).as('auth.me').use(middleware.auth())
// RestaurantMenuItem routes
router.get('/api/menu-items', [RestaurantMenuItemsController, 'getAll']).as('menu-items.getAll')
router.post('/api/menu-items', [RestaurantMenuItemsController, 'getOne']).as('menu-items.getOne')
router.post('/api/menu-items/create', [RestaurantMenuItemsController, 'create']).as('menu-items.create').use(middleware.auth())
router.put('/api/menu-items', [RestaurantMenuItemsController, 'update']).as('menu-items.update').use(middleware.auth())
router.delete('/api/menu-items', [RestaurantMenuItemsController, 'delete']).as('menu-items.delete').use(middleware.auth()).use(throttle)
// RestaurantMenu routes
router.get('/api/menus', [RestaurantMenusController, 'getAll']).as('menus.getAll')
router.post('/api/menus', [RestaurantMenusController, 'getOne']).as('menus.getOne')
router.post('/api/menus/create', [RestaurantMenusController, 'create']).as('menus.create').use(middleware.auth())
router.put('/api/menus', [RestaurantMenusController, 'update']).as('menus.update').use(middleware.auth())
router.delete('/api/menus', [RestaurantMenusController, 'delete']).as('menus.delete').use(middleware.auth()).use(throttle)
+7 -1
View File
@@ -5,6 +5,7 @@ import type { Config } from '@japa/runner/types'
import { pluginAdonisJS } from '@japa/plugin-adonisjs' import { pluginAdonisJS } from '@japa/plugin-adonisjs'
import testUtils from '@adonisjs/core/services/test_utils' import testUtils from '@adonisjs/core/services/test_utils'
/** /**
* This file is imported by the "bin/test.ts" entrypoint file * This file is imported by the "bin/test.ts" entrypoint file
*/ */
@@ -13,7 +14,12 @@ import testUtils from '@adonisjs/core/services/test_utils'
* Configure Japa plugins in the plugins array. * Configure Japa plugins in the plugins array.
* Learn more - https://japa.dev/docs/runner-config#plugins-optional * Learn more - https://japa.dev/docs/runner-config#plugins-optional
*/ */
export const plugins: Config['plugins'] = [assert(), apiClient(), pluginAdonisJS(app)] export const plugins: Config['plugins'] = [
assert(),
apiClient({
baseURL: 'http://localhost:3333',
}),
pluginAdonisJS(app)]
/** /**
* Configure lifecycle function to run before and after all the * Configure lifecycle function to run before and after all the
@@ -0,0 +1,21 @@
import { test } from '@japa/runner'
test.group('Restaurant menu items', () => {
test('create', async ({ assert, client }) => {
const item = {
name: 'test',
priceSmall: 10,
priceLarge: 20,
description: 'test'
}
const response = await client.post('/api/menu-items/create').json(item)
assert.equal(response.body().name, item.name)
assert.equal(response.body().priceSmall, item.priceSmall)
assert.equal(response.body().priceLarge, item.priceLarge)
assert.equal(response.body().description, item.description)
}),
test('get all', async ({ assert, client }) => {
const response = await client.get('/api/menu-items')
assert.isArray(response.body())
})
})