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