diff --git a/.gitignore b/.gitignore index b7064cdbb..04a977352 100644 --- a/.gitignore +++ b/.gitignore @@ -2,10 +2,6 @@ coverage node_modules dist storage -!storage/dms/c4c -!storage/dms/c81 -!storage/dms/ecc -!storage/dms/a87 npm-debug.log .eslintcache datasources.*.json diff --git a/back/methods/image/specs/download.spec.js b/back/methods/image/specs/download.spec.js index e646d829d..328d932a1 100644 --- a/back/methods/image/specs/download.spec.js +++ b/back/methods/image/specs/download.spec.js @@ -3,10 +3,12 @@ const app = require('vn-loopback/server/server'); describe('image download()', () => { const collection = 'user'; const size = '160x160'; + const employeeId = 1; + const ctx = {req: {accessToken: {userId: employeeId}}}; it('should return the image content-type of the user', async() => { const userId = 9; - const image = await app.models.Image.download(collection, size, userId); + const image = await app.models.Image.download(ctx, collection, size, userId); const contentType = image[1]; expect(contentType).toEqual('image/png'); @@ -14,7 +16,7 @@ describe('image download()', () => { it(`should return false if the user doesn't have image`, async() => { const userId = 110; - const image = await app.models.Image.download(collection, size, userId); + const image = await app.models.Image.download(ctx, collection, size, userId); expect(image).toBeFalse(); }); diff --git a/back/methods/image/specs/upload.spec.js b/back/methods/image/specs/upload.spec.js new file mode 100644 index 000000000..3f2cb6f64 --- /dev/null +++ b/back/methods/image/specs/upload.spec.js @@ -0,0 +1,154 @@ +const app = require('vn-loopback/server/server'); + +describe('image upload()', () => { + afterEach(() => { + // RESTORE NODE ENV + delete process.env.NODE_ENV; + }); + + describe('as buyer', () => { + const buyerId = 35; + const workerId = 106; + const itemId = 4; + + it('should try to upload a file for the collection "catalog" and throw a privileges error', async() => { + const ctx = {req: {accessToken: {userId: buyerId}}, + args: { + id: workerId, + collection: 'user' + } + }; + + let error; + try { + await app.models.Image.upload(ctx); + } catch (err) { + error = err; + } + + expect(error.message).toEqual(`You don't have enough privileges`); + }); + + it('should call to the ImageContainer upload method for the collection "catalog"', async() => { + const containerModel = app.models.ImageContainer; + spyOn(containerModel, 'upload'); + + const ctx = {req: {accessToken: {userId: buyerId}}, + args: { + id: itemId, + collection: 'catalog' + } + }; + + try { + await app.models.Image.upload(ctx); + } catch (err) { } + + expect(containerModel.upload).toHaveBeenCalled(); + }); + + it('should throw an error to upload a photo on test environment', async() => { + process.env.NODE_ENV = 'test'; + + const ctx = {req: {accessToken: {userId: buyerId}}, + args: { + id: itemId, + collection: 'catalog' + } + }; + + let error; + try { + await app.models.Image.upload(ctx); + } catch (err) { + error = err; + } + + expect(error.message).toEqual(`You can't upload images on the test instance`); + }); + }); + + describe('as marketing', () => { + const marketingId = 51; + const workerId = 106; + const itemId = 4; + + it('should be able to call to the ImageContainer upload method for the collection "user"', async() => { + const containerModel = app.models.ImageContainer; + spyOn(containerModel, 'upload'); + + const ctx = {req: {accessToken: {userId: marketingId}}, + args: { + id: workerId, + collection: 'user' + } + }; + + try { + await app.models.Image.upload(ctx); + } catch (err) { } + + expect(containerModel.upload).toHaveBeenCalled(); + }); + + it('should be able to call to the ImageContainer upload method for the collection "catalog"', async() => { + const containerModel = app.models.ImageContainer; + spyOn(containerModel, 'upload'); + + const ctx = {req: {accessToken: {userId: marketingId}}, + args: { + id: itemId, + collection: 'catalog' + } + }; + + try { + await app.models.Image.upload(ctx); + } catch (err) { } + + expect(containerModel.upload).toHaveBeenCalled(); + }); + }); + + describe('as hhrr', () => { + const hhrrId = 37; + const workerId = 106; + const itemId = 4; + + it('should upload a file for the collection "user" and call to the ImageContainer upload method', async() => { + const containerModel = app.models.ImageContainer; + spyOn(containerModel, 'upload'); + + const ctx = {req: {accessToken: {userId: hhrrId}}, + args: { + id: itemId, + collection: 'user' + } + }; + + try { + await app.models.Image.upload(ctx); + } catch (err) { } + + expect(containerModel.upload).toHaveBeenCalled(); + }); + + it('should try to upload a file for the collection "catalog" and throw a privilege error', async() => { + const ctx = {req: {accessToken: {userId: hhrrId}}, + args: { + id: workerId, + collection: 'catalog' + } + }; + + let error; + try { + await app.models.Image.upload(ctx); + } catch (err) { + error = err; + } + + expect(error.message).toEqual(`You don't have enough privileges`); + }); + }); +}); diff --git a/back/models/image-collection.js b/back/models/image-collection.js index 2b541dcd6..8ea3c6f12 100644 --- a/back/models/image-collection.js +++ b/back/models/image-collection.js @@ -28,10 +28,11 @@ module.exports = Self => { * @return {boolean} True for user with write privileges */ Self.hasWriteRole = async(ctx, name, options) => { - const collection = await Self.findOne({where: {name}}, { + const collection = await Self.findOne({ include: { relation: 'writeRole' - } + }, + where: {name} }, options); return await hasRole(ctx, collection, options); diff --git a/db/changes/10260-holidays/00-imageCollection.sql b/db/changes/10260-holidays/00-imageCollection.sql deleted file mode 100644 index 28ffdff9c..000000000 --- a/db/changes/10260-holidays/00-imageCollection.sql +++ /dev/null @@ -1,8 +0,0 @@ -ALTER TABLE `hedera`.`imageCollection` - ADD writeRoleFk INT NULL DEFAULT 1; - -ALTER TABLE `hedera`.`imageCollection` - ADD CONSTRAINT role_id___fk - FOREIGN KEY (writeRoleFk) REFERENCES account.role (id) - ON UPDATE CASCADE; - diff --git a/db/changes/10260-holidays/01-role.sql b/db/changes/10260-holidays/01-role.sql new file mode 100644 index 000000000..e5b1e313e --- /dev/null +++ b/db/changes/10260-holidays/01-role.sql @@ -0,0 +1,13 @@ +INSERT INTO account.role (id, name, description) + VALUES + (74, 'userPhotos', 'Privilegios para subir fotos de usuario'), + (75, 'catalogPhotos', 'Privilegios para subir fotos del catálogo'); + +INSERT INTO account.roleInherit (role, inheritsFrom) + VALUES + (37, (SELECT id FROM account.role WHERE name = 'userPhotos')), + (51, (SELECT id FROM account.role WHERE name = 'userPhotos')), + (51, (SELECT id FROM account.role WHERE name = 'catalogPhotos')), + (35, (SELECT id FROM account.role WHERE name = 'catalogPhotos')); + +CALL account.role_sync(); \ No newline at end of file diff --git a/db/changes/10260-holidays/02-imageCollection.sql b/db/changes/10260-holidays/02-imageCollection.sql new file mode 100644 index 000000000..b32e591c7 --- /dev/null +++ b/db/changes/10260-holidays/02-imageCollection.sql @@ -0,0 +1,27 @@ +ALTER TABLE `hedera`.`imageCollection` + ADD writeRoleFk INT UNSIGNED NULL DEFAULT 1; + +ALTER TABLE `hedera`.`imageCollection` + ADD CONSTRAINT role_id_writeRoleFk + FOREIGN KEY (writeRoleFk) REFERENCES account.role (id) + ON UPDATE CASCADE; + +ALTER TABLE `hedera`.`imageCollection` modify readRoleFk INT UNSIGNED default 1 null; + +ALTER TABLE `hedera`.`imageCollection` + ADD CONSTRAINT role_id_readRoleFk + FOREIGN KEY (readRoleFk) REFERENCES account.role (id) + ON UPDATE CASCADE; + +UPDATE hedera.imageCollection t SET t.writeRoleFk = ( + SELECT id FROM `account`.`role` WHERE name = 'catalogPhotos' +) +WHERE t.name = 'catalog'; + +UPDATE hedera.imageCollection t SET t.writeRoleFk = ( + SELECT id FROM `account`.`role` WHERE name = 'userPhotos' +) +WHERE t.name = 'user'; + +UPDATE hedera.imageCollection t SET t.writeRoleFk = 9 +WHERE t.name IN ('link', 'news'); diff --git a/front/salix/components/upload-photo/index.spec.js b/front/salix/components/upload-photo/index.spec.js new file mode 100644 index 000000000..0ae7a5425 --- /dev/null +++ b/front/salix/components/upload-photo/index.spec.js @@ -0,0 +1,57 @@ +import './index.js'; + +describe('Salix', () => { + describe('Component vnUploadPhoto', () => { + let controller; + let $scope; + let $httpBackend; + + beforeEach(ngModule('salix')); + + beforeEach(inject(($componentController, $rootScope, _$httpBackend_) => { + $scope = $rootScope.$new(); + $httpBackend = _$httpBackend_; + const $element = angular.element(''); + controller = $componentController('vnUploadPhoto', {$element, $scope}); + controller.newPhoto = {}; + })); + + afterEach(() => { + $scope.$destroy(); + }); + + describe('onUploadAccept()', () => { + it('should throw an error message containing "Select an image"', () => { + jest.spyOn(controller.vnApp, 'showError'); + + controller.onUploadAccept(); + + expect(controller.vnApp.showError).toHaveBeenCalledWith('Select an image'); + }); + + it('should call to the makeRequest() method', () => { + jest.spyOn(controller, 'makeRequest'); + + controller.newPhoto.files = [0]; + controller.onUploadAccept(); + + expect(controller.makeRequest).toHaveBeenCalledWith(); + }); + }); + + describe('makeRequest()', () => { + it('should make an http query and then emit a response event', () => { + jest.spyOn(controller.vnApp, 'showSuccess'); + jest.spyOn(controller, 'emit'); + + controller.newPhoto.files = [{name: 'hola'}]; + $httpBackend.expectRoute('POST', 'Images/upload').respond(200); + controller.makeRequest(); + $httpBackend.flush(); + + expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Data saved!'); + expect(controller.emit).toHaveBeenCalledWith('response'); + }); + }); + }); +}); diff --git a/front/salix/components/user-popover/index.spec.js b/front/salix/components/user-popover/index.spec.js index 7a088fc51..aaba3c189 100644 --- a/front/salix/components/user-popover/index.spec.js +++ b/front/salix/components/user-popover/index.spec.js @@ -2,14 +2,16 @@ import './index.js'; describe('Salix', () => { describe('Component vnUserPopover', () => { + const userId = 9; let controller; let $scope; + let $root; beforeEach(ngModule('salix')); beforeEach(inject(($componentController, $rootScope, $httpBackend) => { $httpBackend.expectGET('UserConfigs/getUserConfig'); - + $root = $rootScope; $scope = $rootScope.$new(); controller = $componentController('vnUserPopover', {$scope}); })); @@ -60,9 +62,10 @@ describe('Salix', () => { describe('getImageUrl()', () => { it('should return de url image', () => { - const url = controller.getImageUrl(); + const url = $root.imagePath('user', '160x160', userId); expect(url).toBeDefined(); + expect(url).toEqual(`/api/Images/user/160x160/${userId}/download?access_token=null`); }); }); }); diff --git a/modules/item/front/descriptor/index.html b/modules/item/front/descriptor/index.html index 0722a9a9e..f20ddf2ea 100644 --- a/modules/item/front/descriptor/index.html +++ b/modules/item/front/descriptor/index.html @@ -23,7 +23,7 @@ on-error-src/> + vn-visible-by="catalogPhotos"> diff --git a/modules/worker/front/descriptor/index.html b/modules/worker/front/descriptor/index.html index 99f68491b..ad0b9e5c3 100644 --- a/modules/worker/front/descriptor/index.html +++ b/modules/worker/front/descriptor/index.html @@ -9,7 +9,7 @@ on-error-src/> + vn-visible-by="userPhotos"> diff --git a/storage/image/user/160x160/e7723f0b24ff05b32ed09d95196f2f29.png b/storage/image/user/160x160/e7723f0b24ff05b32ed09d95196f2f29.png deleted file mode 100644 index 2085c85f3..000000000 Binary files a/storage/image/user/160x160/e7723f0b24ff05b32ed09d95196f2f29.png and /dev/null differ