2575-image_download #448

Merged
joan merged 14 commits from 2575-image_download into dev 2020-11-18 10:36:17 +00:00
18 changed files with 205 additions and 11 deletions
Showing only changes of commit 4ea5993dcc - Show all commits

View File

@ -0,0 +1,94 @@
const UserError = require('vn-loopback/util/user-error');
const fs = require('fs-extra');
module.exports = Self => {
Self.remoteMethod('download', {
description: 'Get the user image',
accessType: 'READ',
accepts: [
{
arg: 'collection',
type: 'String',
description: 'The image collection',
http: {source: 'path'}
},
{
arg: 'size',
type: 'String',
description: 'The image size',
http: {source: 'path'}
},
{
arg: 'id',
type: 'Number',
description: 'The user id',
http: {source: 'path'}
}
],
returns: [
{
arg: 'body',
type: 'file',
root: true
},
{
arg: 'Content-Type',
type: 'String',
http: {target: 'header'}
},
{
arg: 'Content-Disposition',
type: 'String',
http: {target: 'header'}
}
],
http: {
path: `/:collection/:size/:id/download`,
verb: 'GET'
}
});
Self.download = async function(collection, size, id) {
const filter = {
where: {
collectionFk: collection,
name: id},
include: {
relation: 'collection',
scope: {
fields: ['name', 'readRoleFk'],
include: {
relation: 'readRole'
}
}
}
};
const image = await Self.app.models.Image.findOne(filter);
if (!image) return;
const imageRole = image.collection().readRole().name;
const hasRole = await Self.app.models.Account.hasRole(id, imageRole);
if (!hasRole)
throw new UserError(`You don't have enough privileges`);
let file;
let env = process.env.NODE_ENV;
if (env && env != 'development') {
file = {
path: `/var/lib/salix/image/${collection}/${size}/${id}.png`,
contentType: 'image/png',
name: `${id}.png`
};
} else {
file = {
path: `${process.cwd()}/storage/image/${collection}/${size}/${id}.png`,
contentType: 'image/png',
name: `${id}.png`
};
}
await fs.access(file.path);
let stream = fs.createReadStream(file.path);
return [stream, file.contentType, `filename="${file.name}"`];
};
};

View File

@ -0,0 +1,20 @@
const app = require('vn-loopback/server/server');
describe('image download()', () => {
const collection = 'user';
const size = '160x160';
it('should return the image content-type of the user', async() => {
const userId = 9;
const image = await app.models.Image.download(collection, size, userId);
expect(image[1]).toEqual('image/png');
bernat marked this conversation as resolved
Review

expect(contentType).toEqual....

expect(contentType).toEqual....
});
it(`should don't return an image if the user don't have it`, async() => {
const userId = 8;
const image = await app.models.Image.download(collection, size, userId);
expect(image).toBeUndefined();
});
});

View File

@ -43,6 +43,11 @@
"model": "ImageCollectionSize", "model": "ImageCollectionSize",
"foreignKey": "collectionFk", "foreignKey": "collectionFk",
"property": "id" "property": "id"
},
"readRole": {
"type": "belongsTo",
"model": "Role",
"foreignKey": "readRoleFk"
} }
}, },
"acls": [ "acls": [

View File

@ -3,6 +3,8 @@ const sharp = require('sharp');
const path = require('path'); const path = require('path');
module.exports = Self => { module.exports = Self => {
require('../methods/image/download')(Self);
Self.getPath = function() { Self.getPath = function() {
return '/var/lib/salix/image'; return '/var/lib/salix/image';
}; };

View File

@ -29,6 +29,14 @@
"default": 0 "default": 0
} }
}, },
"relations": {
"collection": {
"type": "belongsTo",
"model": "ImageCollection",
"foreignKey": "collectionFk",
"primaryKey": "name"
}
},
"acls": [ "acls": [
{ {
"accessType": "READ", "accessType": "READ",

View File

@ -1,2 +1,2 @@
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('supplier', '*', 'WRITE', 'ALLOW', 'ROLE', 'administrative'); INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('Supplier', '*', 'WRITE', 'ALLOW', 'ROLE', 'administrative');
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('SupplierContact', '*', 'WRITE', 'ALLOW', 'ROLE', 'administrative'); INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('SupplierContact', '*', 'WRITE', 'ALLOW', 'ROLE', 'administrative');

View File

@ -0,0 +1,5 @@
ALTER TABLE `hedera`.`imageCollection`
ADD COLUMN `readRoleFk` VARCHAR(45) NULL DEFAULT NULL AFTER `column`;
update `hedera`.`imageCollection` set `readRoleFk` = 1 where id = 6;

View File

@ -443,7 +443,7 @@ USE `hedera`;
LOCK TABLES `imageCollection` WRITE; LOCK TABLES `imageCollection` WRITE;
/*!40000 ALTER TABLE `imageCollection` DISABLE KEYS */; /*!40000 ALTER TABLE `imageCollection` DISABLE KEYS */;
INSERT INTO `imageCollection` VALUES (1,'catalog','Artículo',3840,2160,'Item','image','vn','item','image'),(4,'link','Enlace',200,200,'Link','image','hedera','link','image'),(5,'news','Noticias',800,1200,'New','image','hedera','news','image'); INSERT INTO `imageCollection` VALUES (1,'catalog','Artículo',3840,2160,'Item','image','vn','item','image'),(4,'link','Enlace',200,200,'Link','image','hedera','link','image'),(5,'news','Noticias',800,1200,'New','image','hedera','news','image'),('6','user','Usuario','800','1200','Account','image','account','user','image');
/*!40000 ALTER TABLE `imageCollection` ENABLE KEYS */; /*!40000 ALTER TABLE `imageCollection` ENABLE KEYS */;
UNLOCK TABLES; UNLOCK TABLES;

View File

@ -2141,3 +2141,10 @@ INSERT INTO `vn`.`campaign`(`code`, `dated`)
('allSaints', CONCAT(YEAR(DATE_ADD(CURDATE(), INTERVAL -2 YEAR)), '-11-01')), ('allSaints', CONCAT(YEAR(DATE_ADD(CURDATE(), INTERVAL -2 YEAR)), '-11-01')),
('allSaints', CONCAT(YEAR(DATE_ADD(CURDATE(), INTERVAL -3 YEAR)), '-11-01')); ('allSaints', CONCAT(YEAR(DATE_ADD(CURDATE(), INTERVAL -3 YEAR)), '-11-01'));
INSERT INTO `hedera`.`image`(`collectionFk`, `name`)
VALUES
('user', 9);
INSERT INTO `hedera`.`imageCollectionSize`(`id`, `collectionFk`,`width`, `height`)
VALUES
(1, 4, 160, 160);

View File

@ -31,12 +31,14 @@
ng-if="$ctrl.rightMenu" ng-if="$ctrl.rightMenu"
ng-click="$ctrl.rightMenu.show()"> ng-click="$ctrl.rightMenu.show()">
</vn-icon-button> </vn-icon-button>
<vn-icon-button <button class="buttonAccount">
id="user" <img
bernat marked this conversation as resolved
Review

please add the id to the element.

please add the id to the element.
icon="account_circle" ng-src="{{$ctrl.getImageUrl()}}"
ng-click="userPopover.show($event)" ng-click="userPopover.show($event)"
translate-attr="{title: 'Account'}"> translate-attr="{title: 'Account'}"
</vn-icon-button> on-error-src/>
</button>
</div> </div>
<vn-menu vn-id="apps-menu"> <vn-menu vn-id="apps-menu">
<vn-list class="modules-menu"> <vn-list class="modules-menu">

View File

@ -18,6 +18,14 @@ export class Layout extends Component {
window.localStorage.currentUserWorkerId = json.data.id; window.localStorage.currentUserWorkerId = json.data.id;
}); });
} }
getImageUrl() {
if (!this.$.$root.user) return;
const userId = this.$.$root.user.id;
const token = this.vnToken.token;
return `/api/Images/user/160x160/${userId}/download?access_token=${token}`;
}
} }
Layout.$inject = ['$element', '$scope', 'vnModules']; Layout.$inject = ['$element', '$scope', 'vnModules'];

View File

@ -22,4 +22,19 @@ describe('Component vnLayout', () => {
expect(controller.$.$root.user.name).toEqual('batman'); expect(controller.$.$root.user.name).toEqual('batman');
}); });
}); });
describe('getImageUrl()', () => {
it('should return the url image if the user is defined', () => {
controller.$.$root.user = {id: 1};
const url = controller.getImageUrl();
expect(url).not.toBe(3);
});
it('should return undefined if the user is not defined', () => {
const url = controller.getImageUrl();
expect(url).not.toBeDefined();
});
});
}); });

View File

@ -109,6 +109,14 @@ vn-layout {
} }
} }
} }
img {
width: 40px;
border-radius: 50%;
}
.buttonAccount {
background: none;
border: none;
}
@media screen and (max-width: $mobile-width) { @media screen and (max-width: $mobile-width) {
& > vn-topbar { & > vn-topbar {
& > .start > .logo { & > .start > .logo {
@ -147,3 +155,4 @@ vn-layout {
font-size: 1.5rem; font-size: 1.5rem;
height: auto; height: auto;
} }

View File

@ -13,7 +13,9 @@
<vn-popover vn-id="popover"> <vn-popover vn-id="popover">
<vn-vertical class="user-popover vn-pa-md"> <vn-vertical class="user-popover vn-pa-md">
<div class="profile-card vn-pb-md"> <div class="profile-card vn-pb-md">
<vn-icon icon="account_circle"></vn-icon> <img
ng-src="{{$ctrl.getImageUrl($root.user.id)}}"
on-error-src/>
<div class="vn-pl-sm"> <div class="vn-pl-sm">
<div> <div>
<div class="user"> <div class="user">

View File

@ -3,12 +3,13 @@ import './style.scss';
import config from '../../config.json'; import config from '../../config.json';
class Controller { class Controller {
constructor($, $translate, vnConfig, vnAuth) { constructor($, $translate, vnConfig, vnAuth, vnToken) {
Object.assign(this, { Object.assign(this, {
$, $,
$translate, $translate,
vnConfig, vnConfig,
vnAuth, vnAuth,
vnToken,
lang: $translate.use(), lang: $translate.use(),
langs: [] langs: []
}); });
@ -77,8 +78,12 @@ class Controller {
this.$.companies.refresh(); this.$.companies.refresh();
this.$.popover.show(event.target); this.$.popover.show(event.target);
} }
getImageUrl(userId) {
return '/api/Images/user/160x160/' + userId + '/download?access_token=' + this.vnToken.token;
}
} }
Controller.$inject = ['$scope', '$translate', 'vnConfig', 'vnAuth']; Controller.$inject = ['$scope', '$translate', 'vnConfig', 'vnAuth', 'vnToken'];
ngModule.vnComponent('vnUserPopover', { ngModule.vnComponent('vnUserPopover', {
template: require('./index.html'), template: require('./index.html'),

View File

@ -57,5 +57,13 @@ describe('Salix', () => {
expect(controller.companyFk).toBe(4); expect(controller.companyFk).toBe(4);
}); });
}); });
describe('getImageUrl()', () => {
it('should return de url image', () => {
const url = controller.getImageUrl();
expect(url).not.toBeDefined();
});
});
}); });
}); });

View File

@ -11,6 +11,10 @@
font-size: 5rem; font-size: 5rem;
color: $color-font-bg-marginal; color: $color-font-bg-marginal;
} }
img {
width: 80px;
border-radius: 50%;
}
& > div { & > div {
display: flex; display: flex;
flex-direction: column; flex-direction: column;

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB