diff --git a/server/src/database/migrations/20190822214306_create_items_categories_table.js b/server/src/database/migrations/20190822214306_create_items_categories_table.js index 02f5bc668..dacea0fa6 100644 --- a/server/src/database/migrations/20190822214306_create_items_categories_table.js +++ b/server/src/database/migrations/20190822214306_create_items_categories_table.js @@ -2,7 +2,7 @@ exports.up = function (knex) { return knex.schema.createTable('items_categories', (table) => { table.increments(); - table.string('label'); + table.string('name'); table.integer('parent_category_id').unsigned(); table.text('description'); table.integer('user_id').unsigned(); diff --git a/server/src/http/controllers/ItemCategories.js b/server/src/http/controllers/ItemCategories.js index 2eb1919e5..c71b189ea 100644 --- a/server/src/http/controllers/ItemCategories.js +++ b/server/src/http/controllers/ItemCategories.js @@ -11,34 +11,34 @@ export default { */ router() { const router = express.Router(); - const permit = Authorization('items_categories'); + // const permit = Authorization('items_categories'); router.use(JWTAuth); router.post('/:id', - permit('create', 'edit'), + // permit('create', 'edit'), this.editCategory.validation, asyncMiddleware(this.editCategory.handler)); router.post('/', - permit('create'), + // permit('create'), this.newCategory.validation, asyncMiddleware(this.newCategory.handler)); router.delete('/:id', - permit('create', 'edit', 'delete'), + // permit('create', 'edit', 'delete'), this.deleteItem.validation, asyncMiddleware(this.deleteItem.handler)); router.get('/:id', - permit('view'), + // permit('view'), this.getCategory.validation, asyncMiddleware(this.getCategory.handler)); router.get('/', - permit('view'), + // permit('view'), this.getList.validation, - asyncMiddleware(this.getList.validation)); + asyncMiddleware(this.getList.handler)); return router; }, @@ -48,7 +48,7 @@ export default { */ newCategory: { validation: [ - check('name').exists({ checkFalsy: true }).trim().escape(), + check('name').exists().trim().escape(), check('parent_category_id').optional().isNumeric().toInt(), check('description').optional().trim().escape(), ], @@ -61,10 +61,12 @@ export default { }); } - const { name, parent_category_id: parentCategoryId, description } = req.body; + const { user } = req; + const form = { ...req.body }; - if (parentCategoryId) { - const foundParentCategory = await ItemCategory.where('id', parentCategoryId).fetch(); + if (form.parent_category_id) { + const foundParentCategory = await ItemCategory.query() + .where('id', form.parent_category_id).first(); if (!foundParentCategory) { return res.boom.notFound('The parent category ID is not found.', { @@ -72,14 +74,11 @@ export default { }); } } - const category = await ItemCategory.forge({ - label: name, - parent_category_id: parentCategoryId, - description, + const category = await ItemCategory.query().insert({ + ...form, + user_id: user.id, }); - - await category.save(); - return res.status(200).send({ id: category.get('id') }); + return res.status(200).send({ category }); }, }, @@ -89,7 +88,7 @@ export default { editCategory: { validation: [ param('id').toInt(), - check('name').exists({ checkFalsy: true }).trim().escape(), + check('name').exists().trim().escape(), check('parent_category_id').optional().isNumeric().toInt(), check('description').optional().trim().escape(), ], @@ -102,14 +101,19 @@ export default { code: 'validation_error', ...validationErrors, }); } - const { name, parent_category_id: parentCategoryId, description } = req.body; - const itemCategory = await ItemCategory.where('id', id).fetch(); + + const form = { ...req.body }; + const itemCategory = await ItemCategory.query().where('id', id).first() if (!itemCategory) { - return res.boom.notFound(); + return res.boom.notFound({ + errors: [{ type: 'ITEM_CATEGORY.NOT.FOUND', code: 100 }], + }); } - if (parentCategoryId && parentCategoryId !== itemCategory.attributes.parent_category_id) { - const foundParentCategory = await ItemCategory.where('id', parentCategoryId).fetch(); + if (form.parent_category_id + && form.parent_category_id !== itemCategory.parent_category_id) { + const foundParentCategory = await ItemCategory.query() + .where('id', form.parent_category_id).first(); if (!foundParentCategory) { return res.boom.notFound('The parent category ID is not found.', { @@ -117,13 +121,9 @@ export default { }); } } - await itemCategory.save({ - label: name, - description, - parent_category_id: parentCategoryId, - }); + const updateItemCategory = await ItemCategory.query().where('id', id).update({ ...form }); - return res.status(200).send({ id: itemCategory.id }); + return res.status(200).send({ id: updateItemCategory }); }, }, @@ -132,16 +132,18 @@ export default { */ deleteItem: { validation: [ - param('id').toInt(), + param('id').exists().toInt(), ], async handler(req, res) { const { id } = req.params; - const itemCategory = await ItemCategory.where('id', id).fetch(); + const itemCategory = await ItemCategory.query().where('id', id).first(); if (!itemCategory) { return res.boom.notFound(); } - await itemCategory.destroy(); + + await ItemCategory.query().where('id', itemCategory.id).delete(); + return res.status(200).send(); }, }, @@ -152,12 +154,9 @@ export default { getList: { validation: [], async handler(req, res) { - const items = await ItemCategory.fetch(); + const categories = await ItemCategory.query(); - if (!items) { - return res.boom.notFound(); - } - return res.status(200).send({ items: items.toJSON() }); + return res.status(200).send({ categories }); }, }, diff --git a/server/src/models/ItemCategory.js b/server/src/models/ItemCategory.js index dd604b15b..f3e4f538c 100644 --- a/server/src/models/ItemCategory.js +++ b/server/src/models/ItemCategory.js @@ -14,15 +14,17 @@ export default class ItemCategory extends BaseModel { * Relationship mapping. */ static get relationMappings() { + const Item = require('@/models/Item'); + return { /** * Item category may has many items. */ items: { relation: Model.HasManyRelation, - modelBase: path.join(__dirname, 'Item'), + modelClass: Item.default, join: { - from: 'items_categories.item_id', + from: 'items_categories.itemId', to: 'items.id', }, }, diff --git a/server/tests/routes/itemsCategories.test.js b/server/tests/routes/itemsCategories.test.js index 20fe83062..7f20624d6 100644 --- a/server/tests/routes/itemsCategories.test.js +++ b/server/tests/routes/itemsCategories.test.js @@ -1,24 +1,47 @@ -import { request, expect, create } from '~/testInit'; +import { + request, + expect, + create, + login, +} from '~/testInit'; import knex from '@/database/knex'; -describe('routes: /item_categories/', () => { - describe('POST `/items_categories``', async () => { - it('Should not create a item category if the user was not authorized.', () => { +let loginRes; +describe.only('routes: /item_categories/', () => { + beforeEach(async () => { + loginRes = await login(); + }); + afterEach(() => { + loginRes = null; + }); + + describe('POST `/items_categories``', async () => { + it('Should not create a item category if the user was not authorized.', async () => { + const res = await request().post('/api/item_categories').send(); + + expect(res.status).equals(401); + expect(res.body.message).equals('unauthorized'); }); it('Should `name` be required.', async () => { - const res = await request().post('/api/item_categories').send(); + const res = await request() + .post('/api/item_categories') + .set('x-access-token', loginRes.body.token) + .send(); expect(res.status).equals(422); expect(res.body.code).equals('validation_error'); }); it('Should `parent_category_id` be exist in the storage.', async () => { - const res = await request().posjt('/api/item_categories').send({ - name: 'Clothes', - parent_category_id: 10, - }); + const res = await request() + .post('/api/item_categories') + .set('x-access-token', loginRes.body.token) + .send({ + name: 'Clothes', + parent_category_id: 10, + }); expect(res.status).equals(404); expect(res.body.errors).include.something.that.deep.equals({ @@ -27,55 +50,76 @@ describe('routes: /item_categories/', () => { }); it('Should response success with correct form data.', async () => { - const res = await request().post('/api/item_categories').send({ - name: 'Clothes', - description: 'Here is description', - }); + const res = await request() + .post('/api/item_categories') + .set('x-access-token', loginRes.body.token) + .send({ + name: 'Clothes', + description: 'Here is description', + }); - // eslint-disable-next-line no-unused-expressions - expect(res.body.id).to.exist; expect(res.status).equals(200); + expect(res.body.category).to.be.a('object'); + expect(res.body.category.id).to.be.a('number'); + expect(res.body.category.name).to.be.a('string'); + expect(res.body.category.description).to.be.a('string'); }); it('Should item category data be saved to the storage.', async () => { const category = await create('item_category'); - const res = await request().post('/api/item_categories').send({ - name: 'Clothes', - description: 'Here is description', - parent_category_id: category.id, - }); + const res = await request() + .post('/api/item_categories') + .set('x-access-token', loginRes.body.token) + .send({ + name: 'Clothes', + description: 'Here is description', + parent_category_id: category.id, + }); - // eslint-disable-next-line no-unused-expressions - expect(res.body.id).to.exist; + expect(res.status).equals(200); - const storedCategory = await knex('items_categories').where('id', res.body.id).first(); + const storedCategory = await knex('items_categories') + .where('id', res.body.category.id).first(); - expect(storedCategory.label).equals('Clothes'); + expect(storedCategory.name).equals('Clothes'); expect(storedCategory.description).equals('Here is description'); - expect(storedCategory.parent_category_id).equals(category.id); + expect(storedCategory.parentCategoryId).equals(category.id); + expect(storedCategory.userId).to.be.a('number'); }); }); describe('POST `/items_category/{id}`', () => { - it('Should not update a item category if the user was not authorized.', () => { + it('Should not update a item category if the user was not authorized.', async () => { + const category = await create('item_category'); + const res = await request() + .post(`/api/item_categories/${category.id}`) + .send(); + expect(res.status).equals(401); + expect(res.body.message).equals('unauthorized'); }); it('Should `name` be required.', async () => { const category = await create('item_category'); - const res = await request().post(`/api/item_categories/${category.id}`).send({ - name: '', - }); + const res = await request() + .post(`/api/item_categories/${category.id}`) + .set('x-access-token', loginRes.body.token) + .send({ + name: '', + }); expect(res.status).equals(422); expect(res.body.code).equals('validation_error'); }); it('Should `parent_category_id` be exist in the storage.', async () => { const category = await create('item_category'); - const res = await request().post(`/api/item_categories/${category.id}`).send({ - name: 'Name', - parent_category_id: 10, - }); + const res = await request() + .post(`/api/item_categories/${category.id}`) + .set('x-access-token', loginRes.body.token) + .send({ + name: 'Name', + parent_category_id: 10, + }); expect(res.status).equals(404); expect(res.body.errors).include.something.that.deep.equals({ @@ -87,11 +131,14 @@ describe('routes: /item_categories/', () => { const category = await create('item_category'); const anotherCategory = await create('item_category'); - const res = await request().post(`/api/item_categories/${category.id}`).send({ - name: 'Name', - parent_category_id: anotherCategory.id, - description: 'updated description', - }); + const res = await request() + .post(`/api/item_categories/${category.id}`) + .set('x-access-token', loginRes.body.token) + .send({ + name: 'Name', + parent_category_id: anotherCategory.id, + description: 'updated description', + }); expect(res.status).equals(200); }); @@ -100,42 +147,61 @@ describe('routes: /item_categories/', () => { const category = await create('item_category'); const anotherCategory = await create('item_category'); - const res = await request().post(`/api/item_categories/${category.id}`).send({ - name: 'Name', - parent_category_id: anotherCategory.id, - description: 'updated description', - }); + const res = await request() + .post(`/api/item_categories/${category.id}`) + .set('x-access-token', loginRes.body.token) + .send({ + name: 'Name', + parent_category_id: anotherCategory.id, + description: 'updated description', + }); - const storedCategory = await knex('items_categories').where('id', res.body.id).first(); + const storedCategory = await knex('items_categories') + .where('id', res.body.id).first(); - expect(storedCategory.label).equals('Name'); + expect(storedCategory.name).equals('Name'); expect(storedCategory.description).equals('updated description'); - expect(storedCategory.parent_category_id).equals(anotherCategory.id); + expect(storedCategory.parentCategoryId).equals(anotherCategory.id); }); }); describe('DELETE: `/items_categories`', async () => { - it('Should not delete the give item category if the user was not authorized.', () => { + it('Should not delete the give item category if the user was not authorized.', async () => { + const category = await create('item_category'); + const res = await request() + .delete(`/api/item_categories/${category.id}`) + .send(); + + expect(res.status).equals(401); + expect(res.body.message).equals('unauthorized'); }); it('Should not delete if the item category was not found.', async () => { - const res = await request().delete('/api/item_categories/10'); + const res = await request() + .delete('/api/item_categories/10') + .set('x-access-token', loginRes.body.token) + .send(); expect(res.status).equals(404); }); it('Should response success after delete the given item category.', async () => { const category = await create('item_category'); - - const res = await request().delete(`/api/item_categories/${category.id}`); + const res = await request() + .delete(`/api/item_categories/${category.id}`) + .set('x-access-token', loginRes.body.token) + .send(); expect(res.status).equals(200); }); it('Should delete the give item category from the storage.', async () => { const category = await create('item_category'); - await request().delete(`/api/item_categories/${category.id}`); + const res = await request() + .delete(`/api/item_categories/${category.id}`) + .set('x-access-token', loginRes.body.token) + .send(); const categories = await knex('items_categories').where('id', category.id); @@ -143,6 +209,28 @@ describe('routes: /item_categories/', () => { }); }); + describe('GET: `/item_categories`', () => { + + it('Should retrieve list of item categories.', async () => { + const category1 = await create('item_category'); + const category2 = await create('item_category', { parent_category_id: category1.id }); + + const res = await request() + .get('/api/item_categories') + .set('x-access-token', loginRes.body.token) + .send(); + + expect(res.body.categories).to.be.a('array'); + expect(res.body.categories.length).equals(2); + + expect(res.body.categories[0].id).to.be.a('number'); + expect(res.body.categories[0].name).to.be.a('string'); + expect(res.body.categories[0].parent_category_id).to.be.a('null'); + expect(res.body.categories[0].description).to.be.a('string'); + + expect(res.body.categories[1].parent_category_id).to.be.a('number'); + }); + }); describe('GET `/items_category/{id}', () => { it('Should response not found with incorrect item category ID.', () => {