2576 - Photo upload component
gitea/salix/pipeline/head There was a failure building this commit Details

This commit is contained in:
Joan Sanchez 2020-11-27 13:10:39 +01:00
parent 34c1115954
commit 1ba1d27ba0
52 changed files with 527 additions and 110 deletions

10
.gitignore vendored
View File

@ -1,11 +1,11 @@
coverage
node_modules
dist
e2e/dms/*/
!e2e/dms/c4c
!e2e/dms/c81
!e2e/dms/ecc
!e2e/dms/a87
storage
!storage/dms/c4c
!storage/dms/c81
!storage/dms/ecc
!storage/dms/a87
npm-debug.log
.eslintcache
datasources.*.json

View File

@ -84,7 +84,7 @@ module.exports = Self => {
};
async function uploadNewFile(ctx, dms, myOptions) {
const storageConnector = Self.app.dataSources.storage.connector;
const storageConnector = Self.app.dataSources.dmsStorage.connector;
const models = Self.app.models;
const fileOptions = {};

View File

@ -46,7 +46,7 @@ module.exports = Self => {
});
Self.uploadFile = async(ctx, options) => {
const storageConnector = Self.app.dataSources.storage.connector;
const storageConnector = Self.app.dataSources.dmsStorage.connector;
const models = Self.app.models;
const fileOptions = {};
const args = ctx.args;
@ -98,7 +98,7 @@ module.exports = Self => {
async function createDms(ctx, file, myOptions) {
const models = Self.app.models;
const storageConnector = Self.app.dataSources.storage.connector;
const storageConnector = Self.app.dataSources.dmsStorage.connector;
const myUserId = ctx.req.accessToken.userId;
const myWorker = await models.Worker.findOne({where: {userFk: myUserId}}, myOptions);
const args = ctx.args;
@ -121,7 +121,6 @@ module.exports = Self => {
return newDms.updateAttribute('file', fileName, myOptions);
}
/**
* Returns a container instance
* If doesn't exists creates a new one

View File

@ -2,7 +2,7 @@ const UserError = require('vn-loopback/util/user-error');
const fs = require('fs-extra');
module.exports = Self => {
Self.remoteMethod('download', {
Self.remoteMethodCtx('download', {
description: 'Get the user image',
accessType: 'READ',
accepts: [
@ -49,15 +49,9 @@ module.exports = Self => {
}
});
Self.download = async function(collection, size, id) {
Self.download = async function(ctx, collection, size, id) {
const models = Self.app.models;
const filter = {
where: {
name: collection},
include: {
relation: 'readRole'
}
};
const filter = {where: {name: collection}};
const imageCollection = await models.ImageCollection.findOne(filter);
const entity = await models[imageCollection.model].findById(id, {
fields: ['id', imageCollection.property]
@ -69,28 +63,22 @@ module.exports = Self => {
if (!image) return false;
const imageRole = imageCollection.readRole().name;
const hasRole = await models.Account.hasRole(id, imageRole);
if (!hasRole)
const hasReadRole = models.ImageCollection.hasReadRole(ctx, collection);
if (!hasReadRole)
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}/${image.name}.png`,
const container = await models.ImageContainer.getContainer(collection);
const rootPath = container.client.root;
const file = {
path: `${rootPath}/${collection}/${size}/${image.name}.png`,
contentType: 'image/png',
name: `${image.name}.png`
};
} else {
file = {
path: `${process.cwd()}/storage/image/${collection}/${size}/${image.name}.png`,
contentType: 'image/png',
name: `${image.name}.png`
};
}
if (!fs.existsSync(file.path)) return [];
await fs.access(file.path);
let stream = fs.createReadStream(file.path);
const stream = fs.createReadStream(file.path);
return [stream, file.contentType, `filename="${file.name}"`];
};
};

View File

@ -0,0 +1,77 @@
const UserError = require('vn-loopback/util/user-error');
const fs = require('fs-extra');
module.exports = Self => {
Self.remoteMethodCtx('upload', {
description: 'Uploads a file and inserts into dms model',
accessType: 'WRITE',
accepts: [
{
arg: 'id',
type: 'Number',
description: 'The entity id',
required: true
},
{
arg: 'collection',
type: 'string',
description: 'The collection name',
required: true
}],
returns: {
type: 'Object',
root: true
},
http: {
path: `/upload`,
verb: 'POST'
}
});
Self.upload = async ctx => {
const models = Self.app.models;
const fileOptions = {};
const args = ctx.args;
const hasWriteRole = await models.ImageCollection.hasWriteRole(ctx, args.collection);
if (!hasWriteRole)
throw new UserError(`You don't have enough privileges`);
if (process.env.NODE_ENV == 'test')
throw new UserError(`You can't upload images on the test instance`);
// Upload file to temporary path
const container = await getContainer(args.collection);
const uploaded = await models.ImageContainer.upload(container.name, ctx.req, ctx.result, fileOptions);
const [uploadedFile] = Object.values(uploaded.files).map(file => {
return file[0];
});
const file = await models.ImageContainer.getFile(container.name, uploadedFile.name);
const srcFile = `${file.client.root}/${file.container}/${file.name}`;
await models.Image.registerImage(container.name, srcFile, args.id);
};
/**
* Returns a container instance
* If doesn't exists creates a new one
*
* @param {String} name Container name
* @return {Object} Container instance
*/
async function getContainer(name) {
const models = Self.app.models;
let container;
try {
container = await models.ImageContainer.getContainer(name);
} catch (err) {
if (err.code === 'ENOENT') {
container = await models.ImageContainer.createContainer({
name: name
});
} else throw err;
}
return container;
}
};

View File

@ -18,7 +18,7 @@
"dataSource": "vn"
},
"Container": {
"dataSource": "storage"
"dataSource": "dmsStorage"
},
"Continent": {
"dataSource": "vn"
@ -44,6 +44,9 @@
"ImageCollectionSize": {
"dataSource": "vn"
},
"ImageContainer": {
"dataSource": "imageStorage"
},
"Language": {
"dataSource": "vn"
},

View File

@ -14,7 +14,7 @@ module.exports = Self => {
};
Self.getFile = async function(id) {
const storageConnector = Self.app.dataSources.storage.connector;
const storageConnector = Self.app.dataSources.dmsStorage.connector;
const models = Self.app.models;
const dms = await Self.findById(id);
const pathHash = storageConnector.getPathHash(dms.id);

View File

@ -0,0 +1,63 @@
module.exports = Self => {
/**
* Checks if current user has
* read privileges over a collection
*
* @param {object} ctx - Request context
* @param {interger} name - Collection name
* @param {object} options - Query options
* @return {boolean} True for user with read privileges
*/
Self.hasReadRole = async(ctx, name, options) => {
const collection = await Self.findOne({where: {name}}, {
include: {
relation: 'readRole'
}
}, options);
return await hasRole(ctx, collection, options);
};
/**
* Checks if current user has
* write privileges over a collection
*
* @param {object} ctx - Request context
* @param {string} name - Collection name
* @param {object} options - Query options
* @return {boolean} True for user with write privileges
*/
Self.hasWriteRole = async(ctx, name, options) => {
const collection = await Self.findOne({where: {name}}, {
include: {
relation: 'writeRole'
}
}, options);
return await hasRole(ctx, collection, options);
};
/**
* Checks if current user has
* read or write privileges
* @param {Object} ctx - Context
* @param {Object} collection - Collection [read/write]
* @param {Object} options - Query options
*/
async function hasRole(ctx, collection, options) {
const models = Self.app.models;
const myUserId = ctx.req.accessToken.userId;
const readRole = collection.readRole() && collection.readRole().name;
const writeRole = collection.writeRole() && collection.writeRole().name;
const requiredRole = readRole || writeRole;
const hasRequiredRole = await models.Account.hasRole(myUserId, requiredRole, options);
const isRoot = await models.Account.hasRole(myUserId, 'root', options);
if (isRoot || hasRequiredRole)
return true;
return false;
}
};

View File

@ -48,6 +48,11 @@
"type": "belongsTo",
"model": "Role",
"foreignKey": "readRoleFk"
},
"writeRole": {
"type": "belongsTo",
"model": "Role",
"foreignKey": "writeRoleFk"
}
},
"acls": [

View File

@ -0,0 +1,13 @@
{
"name": "ImageContainer",
"base": "VnModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {},
"validations": [],
"relations": {},
"acls": [],
"methods": []
}

View File

@ -4,12 +4,9 @@ const path = require('path');
module.exports = Self => {
require('../methods/image/download')(Self);
require('../methods/image/upload')(Self);
Self.getPath = function() {
return '/var/lib/salix/image';
};
Self.registerImage = async(collectionName, file, srcFilePath) => {
Self.registerImage = async(collectionName, srcFile, entityId) => {
const models = Self.app.models;
const tx = await Self.beginTransaction({});
const myOptions = {transaction: tx};
@ -33,8 +30,8 @@ module.exports = Self => {
}
}, myOptions);
const file = srcFile.split('/').pop();
const fileName = file.split('.')[0];
const rootPath = Self.getPath();
const data = {
name: fileName,
collectionFk: collectionName
@ -47,6 +44,8 @@ module.exports = Self => {
}, myOptions);
// Resizes and saves the image
const container = await models.ImageContainer.getContainer(collectionName);
const rootPath = container.client.root;
const collectionDir = path.join(rootPath, collectionName);
const dstDir = path.join(collectionDir, 'full');
const dstFile = path.join(dstDir, file);
@ -57,7 +56,7 @@ module.exports = Self => {
};
await fs.mkdir(dstDir, {recursive: true});
await sharp(srcFilePath, {failOnError: false})
await sharp(srcFile, {failOnError: false})
.resize(collection.maxWidth, collection.maxHeight, resizeOpts)
.png()
.toFile(dstFile);
@ -72,7 +71,7 @@ module.exports = Self => {
};
await fs.mkdir(dstDir, {recursive: true});
await sharp(srcFilePath, {failOnError: false})
await sharp(srcFile, {failOnError: false})
.resize(size.width, size.height, resizeOpts)
.png()
.toFile(dstFile);
@ -83,7 +82,7 @@ module.exports = Self => {
if (!model)
throw new Error('Matching model not found');
const item = await model.findById(fileName, null, myOptions);
const item = await model.findById(entityId, null, myOptions);
if (item) {
await item.updateAttribute(
collection.property,
@ -92,8 +91,8 @@ module.exports = Self => {
);
}
if (fs.existsSync(srcFilePath))
await fs.unlink(srcFilePath);
if (fs.existsSync(srcFile))
await fs.unlink(srcFile);
await tx.commit();
return newImage;

View File

@ -0,0 +1 @@
INSERT INTO salix.ACL (model, property, accessType, permission, principalType, principalId) VALUES ('Image', '*', 'WRITE', 'ALLOW', 'ROLE', 'employee')

View File

@ -0,0 +1,8 @@
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;

View File

@ -447,6 +447,25 @@ INSERT INTO `imageCollection` VALUES (1,'catalog','Artículo',3840,2160,'Item','
/*!40000 ALTER TABLE `imageCollection` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Dumping data for table `imageCollectionSize`
--
LOCK TABLES `imageCollectionSize` WRITE;
/*!40000 ALTER TABLE `imageCollectionSize` DISABLE KEYS */;
INSERT INTO `imageCollectionSize` (`id`, `collectionFk`, `width`, `height`, `crop`)
VALUES
(2, 1, 50, 50, 1),
(3, 1, 200, 200, 1),
(5, 5, 200, 200, 1),
(6, 1, 70, 70, 1),
(8, 5, 50, 50, 1),
(9, 1, 1600, 900, 0),
(13, 6, 160, 160, 1),
(14, 6, 520, 520, 1),
(15, 6, 1600, 1600, 1);
/*!40000 ALTER TABLE `imageCollectionSize` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Dumping data for table `tpvError`
--

View File

@ -1 +0,0 @@
File: 4.txt. It works!

View File

@ -1 +0,0 @@
It works!

View File

@ -1 +0,0 @@
It works!

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

View File

@ -1 +0,0 @@
It works!

View File

@ -46,7 +46,7 @@ export function directive($timeout) {
$element.on('click', function(event) {
if (event.defaultPrevented) return;
let src = $attrs.zoomImage || $attrs.src;
let src = $element[0].getAttribute('zoom-image') || $element[0].src;
if (src)
createContainers(src);
else

View File

@ -5,6 +5,24 @@
vn-descriptor-content {
display: block;
.photo {
position: relative;
& > img[ng-src] {
min-height: 16em;
display: block;
height: 100%;
width: 100%;
}
vn-float-button {
position: absolute;
margin: 1em;
bottom: 0;
right: 0
}
}
& > vn-spinner {
display: block;
height: 40px;

View File

@ -13,3 +13,4 @@ import './section';
import './summary';
import './topbar/topbar';
import './user-popover';
import './upload-photo';

View File

@ -0,0 +1,23 @@
<vn-dialog class="edit"
vn-id="dialog"
on-accept="$ctrl.onUploadAccept()"
message="Upload new photo">
<tpl-body class="upload-photo">
<vn-horizontal ng-show="file.value" class="photo vn-mb-md">
<div><img vn-id="photo" ng-src=""/></div>
</vn-horizontal>
<vn-horizontal>
<vn-input-file vn-id="file"
vn-one
label="File"
ng-model="$ctrl.newPhoto.files"
on-change="$ctrl.updatePhotoPreview(value)"
required="true">
</vn-input-file>
</vn-horizontal>
</tpl-body>
<tpl-buttons>
<input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/>
<button response="accept" translate>Upload</button>
</tpl-buttons>
</vn-dialog>

View File

@ -0,0 +1,87 @@
import ngModule from '../../module';
import Component from 'core/lib/component';
import './style.scss';
/**
* Small card with basing entity information and actions.
*/
export default class UploadPhoto extends Component {
/**
* Opens the dialog and sets the default data
* @param {*} collection - Collection name
* @param {*} id - Entity id
*/
show(collection, id) {
this.newPhoto = {id, collection};
this.$.dialog.show();
}
/**
* Updates the image preview
*
* @param {string} value
*/
updatePhotoPreview(value) {
if (value && value[0]) {
const reader = new FileReader();
reader.onload = e => this.$.photo.src = e.target.result;
reader.readAsDataURL(value[0]);
}
}
/**
* Dialog response handler
*
* @return {boolean} Response
*/
onUploadAccept() {
try {
if (!this.newPhoto.files)
throw new Error(`Select an image`);
this.makeRequest();
} catch (e) {
this.vnApp.showError(this.$t(e.message));
return false;
}
return true;
}
/**
* Performs a cancellable request.
*
*/
makeRequest() {
if (this.canceler) this.canceler.resolve();
this.canceler = this.$q.defer();
const options = {
method: 'POST',
url: `Images/upload`,
params: this.newPhoto,
headers: {'Content-Type': undefined},
timeout: this.canceler.promise,
transformRequest: files => {
const formData = new FormData();
for (let i = 0; i < files.length; i++)
formData.append(files[i].name, files[i]);
return formData;
},
data: this.newPhoto.files
};
this.$http(options)
.then(() => this.vnApp.showSuccess(this.$t('Data saved!')))
.then(() => this.emit('response'))
.finally(() => this.canceler = null);
}
}
ngModule.vnComponent('vnUploadPhoto', {
controller: UploadPhoto,
template: require('./index.html'),
bindings: {
data: '<'
}
});

View File

@ -0,0 +1,2 @@
Upload new photo: Subir una nueva foto
Select an image: Selecciona una imagen

View File

@ -0,0 +1,31 @@
@import "./variables";
.upload-photo {
.photo {
position: relative;
margin: 0 auto;
text-align: center;
& > div {
border: 3px solid $color-primary;
max-width: 256px;
max-height: 256px;
border-radius: 50%;
overflow: hidden
}
& > div > img[ng-src] {
width: 256px;
height: 256px;
display: block;
height: 100%;
width: 100%;
}
}
& > vn-spinner {
display: block;
height: 40px;
padding: $spacing-md;
}
}

View File

@ -14,7 +14,7 @@
<vn-vertical class="user-popover vn-pa-md">
<div class="profile-card vn-pb-md">
<img
ng-src="{{$ctrl.getImageUrl($root.user.id)}}"
ng-src="{{::$root.imagePath('user', '160x160', $root.user.id)}}"
on-error-src/>
<div class="vn-pl-sm">
<div>

View File

@ -78,10 +78,6 @@ class Controller {
this.$.companies.refresh();
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', 'vnToken'];

View File

@ -7,9 +7,14 @@ export const appName = 'salix';
const ngModule = ng.module('salix', ['vnCore']);
export default ngModule;
run.$inject = ['$window', '$rootScope', 'vnAuth', 'vnApp', '$state'];
export function run($window, $rootScope, vnAuth, vnApp, $state) {
$rootScope.imagePath = appConfig.imagePath;
run.$inject = ['$window', '$rootScope', 'vnAuth', 'vnApp', 'vnToken', '$state'];
export function run($window, $rootScope, vnAuth, vnApp, vnToken, $state) {
$rootScope.imagePath = (collection, size, id) => {
if (!collection || !size || !id) return;
const basePath = `/api/Images/${collection}/${size}/${id}`;
return `${basePath}/download?access_token=${vnToken.token}`;
};
$window.validations = {};
vnApp.name = appName;

View File

@ -160,5 +160,6 @@
"The social name cannot be empty": "La razón social no puede quedar en blanco",
"The nif cannot be empty": "El NIF no puede quedar en blanco",
"You need to fill sage information before you check verified data": "Debes rellenar la información de sage antes de marcar datos comprobados",
"ASSIGN_ZONE_FIRST": "Asigna una zona primero"
"ASSIGN_ZONE_FIRST": "Asigna una zona primero",
"You can't upload images on the test environment": "No puedes subir imágenes en el entorno de pruebas"
}

View File

@ -2,7 +2,7 @@ const uuid = require('uuid/v1');
const md5 = require('md5');
module.exports = app => {
const storageConnector = app.dataSources.storage.connector;
const storageConnector = app.dataSources.dmsStorage.connector;
storageConnector.getFilename = function(file) {
return `${uuid()}.${storageConnector.getFileExtension(file.name)}`;
@ -15,4 +15,17 @@ module.exports = app => {
storageConnector.getPathHash = function(id) {
return md5(id.toString()).substring(0, 3);
};
const imageStorageConnector = app.dataSources.imageStorage.connector;
imageStorageConnector.getFilename = function(file) {
return `${uuid()}.png`;
};
/* imageStorageConnector.getFileExtension = function(fileName) {
return fileName.split('.').pop().toLowerCase();
};
imageStorageConnector.getPathHash = function(id) {
return md5(id.toString()).substring(0, 3);
}; */
};

View File

@ -17,11 +17,11 @@
"connectTimeout": 40000,
"acquireTimeout": 20000
},
"storage": {
"name": "storage",
"dmsStorage": {
"name": "dmsStorage",
"connector": "loopback-component-storage",
"provider": "filesystem",
"root": "./e2e/dms",
"root": "./storage/dms",
"maxFileSize": "262144000",
"allowedContentTypes": [
"application/x-7z-compressed",
@ -36,5 +36,17 @@
"image/jpeg",
"image/jpg"
]
},
"imageStorage": {
"name": "imageStorage",
"connector": "loopback-component-storage",
"provider": "filesystem",
"root": "./storage/image",
"maxFileSize": "52428800",
"allowedContentTypes": [
"image/png",
"image/jpeg",
"image/jpg"
]
}
}

View File

@ -13,7 +13,7 @@ module.exports = Self => {
});
Self.allowedContentTypes = async() => {
const storageConnector = Self.app.dataSources.storage.connector;
const storageConnector = Self.app.dataSources.dmsStorage.connector;
const allowedContentTypes = storageConnector.allowedContentTypes;
const modelAllowedContentTypes = Self.definition.settings.allowedContentTypes;

View File

@ -13,7 +13,7 @@ module.exports = Self => {
});
Self.allowedContentTypes = async() => {
const storageConnector = Self.app.dataSources.storage.connector;
const storageConnector = Self.app.dataSources.dmsStorage.connector;
const allowedContentTypes = storageConnector.allowedContentTypes;
const modelAllowedContentTypes = Self.definition.settings.allowedContentTypes;

View File

@ -70,8 +70,8 @@
</vn-td>
<vn-td shrink >
<img
ng-src="{{::$root.imagePath}}/catalog/50x50/{{::buy.image}}"
zoom-image="{{::$root.imagePath}}/catalog/1600x900/{{::buy.image}}"
ng-src="{{::$root.imagePath('catalog', '50x50', buy.itemFk)}}"
zoom-image="{{::$root.imagePath('catalog', '1600x900', buy.itemFk)}}"
vn-click-stop
on-error-src/>
</vn-td>

View File

@ -57,7 +57,7 @@ module.exports = Self => {
writeStream.on('finish', async function() {
try {
await models.Image.registerImage('catalog', fileName, filePath);
await models.Image.registerImage('catalog', filePath, image.itemFk);
await image.destroy();
} catch (error) {
await errorHandler(image.itemFk, error, filePath);

View File

@ -1,5 +1,5 @@
<vn-portal slot="menu">
<vn-item-descriptor item="$ctrl.item"></vn-item-descriptor>
<vn-item-descriptor item="$ctrl.item" card-reload="$ctrl.reload()"></vn-item-descriptor>
<vn-left-menu source="card"></vn-left-menu>
</vn-portal>
<ui-view></ui-view>

View File

@ -16,19 +16,15 @@
</vn-item>
</slot-menu>
<slot-before>
<div style="position: relative" text-center>
<img
ng-src="{{::$root.imagePath}}/catalog/200x200/{{$ctrl.item.image}}"
zoom-image="{{::$root.imagePath}}/catalog/1600x900/{{$ctrl.item.image}}"
on-error-src
/>
<a href="//verdnatura.es/#!form=admin/items&filter={{$ctrl.item.id}}" target="_blank">
<vn-float-button
<div class="photo" text-center>
<img vn-id="photo"
ng-src="{{$root.imagePath('catalog', '200x200', $ctrl.item.id)}}"
zoom-image="{{$root.imagePath('catalog', '1600x900', $ctrl.item.id)}}"
on-error-src/>
<vn-float-button ng-click="uploadPhoto.show('catalog', $ctrl.item.id)"
icon="edit"
style="position: absolute; margin: 1em; bottom: 0; right: 0;"
vn-visible-by="marketing, buyer">
</vn-float-button>
</a>
</div>
<vn-horizontal class="item-state">
<vn-one>
@ -103,3 +99,9 @@
<vn-worker-descriptor-popover
vn-id="workerDescriptor">
</vn-worker-descriptor-popover>
<!-- Upload photo dialog -->
<vn-upload-photo
vn-id="uploadPhoto"
on-response="$ctrl.onUploadResponse()">
</vn-upload-photo>

View File

@ -3,6 +3,11 @@ import Descriptor from 'salix/components/descriptor';
import './style.scss';
class Controller extends Descriptor {
constructor($element, $, $rootScope) {
super($element, $);
this.$rootScope = $rootScope;
}
get item() {
return this.entity;
}
@ -65,13 +70,27 @@ class Controller extends Descriptor {
this.$http.post(`Items/${this.item.id}/clone`)
.then(res => this.$state.go('item.card.tags', {id: res.data.id}));
}
onUploadResponse() {
const timestamp = new Date().getTime();
const src = this.$rootScope.imagePath('catalog', '200x200', this.item.id);
const zoomSrc = this.$rootScope.imagePath('catalog', '1600x900', this.item.id);
const newSrc = `${src}&t=${timestamp}`;
const newZoomSrc = `${zoomSrc}&t=${timestamp}`;
this.$.photo.setAttribute('src', newSrc);
this.$.photo.setAttribute('zoom-image', newZoomSrc);
}
}
Controller.$inject = ['$element', '$scope', '$rootScope'];
ngModule.vnComponent('vnItemDescriptor', {
template: require('./index.html'),
controller: Controller,
bindings: {
item: '<',
dated: '<'
dated: '<',
cardReload: '&'
}
});

View File

@ -35,8 +35,8 @@
ui-sref="item.card.summary({id: item.id})">
<vn-td shrink>
<img
ng-src="{{::$root.imagePath}}/catalog/50x50/{{::item.image}}"
zoom-image="{{::$root.imagePath}}/catalog/1600x900/{{::item.image}}"
ng-src="{{::$root.imagePath('catalog', '50x50', item.id)}}"
zoom-image="{{::$root.imagePath('catalog', '1600x900', item.id)}}"
vn-click-stop
on-error-src/>
</vn-td>
@ -44,7 +44,7 @@
<span
vn-click-stop="itemDescriptor.show($event, item.id)"
class="link">
{{::item.id | zeroFill:6}}
{{::item.id}}
</span>
</vn-td>
<vn-td shrink>{{::item.grouping | dashIfEmpty}}</vn-td>

View File

@ -11,8 +11,8 @@
<vn-horizontal>
<vn-one>
<img style="width: 100%; display: block;"
ng-src="{{::$root.imagePath}}/catalog/200x200/{{$ctrl.item.image}}"
zoom-image="{{::$root.imagePath}}/catalog/1600x900/{{$ctrl.item.image}}" on-error-src/>
ng-src="{{$root.imagePath('catalog', '200x200', $ctrl.item.id)}}"
zoom-image="{{$root.imagePath('catalog', '1600x900', $ctrl.item.id)}}" on-error-src/>
<vn-horizontal class="item-state">
<vn-one>
<p translate>Visible</p>

View File

@ -5,11 +5,11 @@
<vn-card>
<div class="image">
<div ng-if="::item.hex != null" class="item-color-background">
<div class="item-color" style="background-color: #{{::item.hex}}"></div>
<div class="item-color" ng-style="{'background-color': '#' + item.hex}"></div>
</div>
<img
ng-src="{{::$root.imagePath}}/catalog/200x200/{{::item.image}}"
zoom-image="{{::$root.imagePath}}/catalog/1600x900/{{::item.image}}"
ng-src="{{::$root.imagePath('catalog', '200x200', item.id)}}"
zoom-image="{{::$root.imagePath('catalog', '1600x900', item.id)}}"
on-error-src/>
</div>
<div class="description">

View File

@ -32,8 +32,8 @@
<vn-tr ng-repeat="row in $ctrl.rows">
<vn-td shrink>
<img
ng-src="{{::$root.imagePath}}/catalog/50x50/{{::row.item.image}}"
zoom-image="{{::$root.imagePath}}/catalog/1600x900/{{::row.item.image}}"
ng-src="{{::$root.imagePath('catalog', '50x50', row.item.id)}}"
zoom-image="{{::$root.imagePath('catalog', '1600x900', row.item.id)}}"
on-error-src/>
</vn-td>
<vn-td number>

View File

@ -13,7 +13,7 @@ module.exports = Self => {
});
Self.allowedContentTypes = async() => {
const storageConnector = Self.app.dataSources.storage.connector;
const storageConnector = Self.app.dataSources.dmsStorage.connector;
const allowedContentTypes = storageConnector.allowedContentTypes;
const modelAllowedContentTypes = Self.definition.settings.allowedContentTypes;

View File

@ -19,8 +19,8 @@
<vn-card>
<div class="image">
<img
ng-src="{{::$root.imagePath}}/catalog/200x200/{{::sale.item.image}}"
zoom-image="{{::$root.imagePath}}/catalog/1600x900/{{::sale.item.image}}"
ng-src="{{::$root.imagePath('catalog', '200x200', sale.itemFk)}}"
zoom-image="{{::$root.imagePath('catalog', '1600x900', sale.itemFk)}}"
on-error-src/>
</div>
<div class="description">

View File

@ -93,8 +93,8 @@
</vn-td>
<vn-td shrink>
<img
ng-src="{{::$root.imagePath}}/catalog/50x50/{{sale.image}}"
zoom-image="{{::$root.imagePath}}/catalog/1600x900/{{sale.image}}"
ng-src="{{::$root.imagePath('catalog', '50x50', sale.itemFk)}}"
zoom-image="{{::$root.imagePath('catalog', '1600x900', sale.itemFk)}}"
on-error-src/>
</vn-td>
<vn-td number>

View File

@ -13,7 +13,7 @@ module.exports = Self => {
});
Self.allowedContentTypes = async() => {
const storageConnector = Self.app.dataSources.storage.connector;
const storageConnector = Self.app.dataSources.dmsStorage.connector;
const allowedContentTypes = storageConnector.allowedContentTypes;
const modelAllowedContentTypes = Self.definition.settings.allowedContentTypes;

View File

@ -46,7 +46,7 @@ class Controller extends Section {
warehouseId: warehouseId,
companyId: companyId,
dmsTypeId: dmsTypeId,
description: this.$t('FileDescription', {
description: this.$t('TravelFileDescription', {
travelId: this.travel.id
}).toUpperCase()
};

View File

@ -8,7 +8,7 @@ Upload file: Subir fichero
Edit file: Editar fichero
Upload: Subir
File: Fichero
FileDescription: Travel id {{travelId}}
TravelFileDescription: Travel id {{travelId}}
ContentTypesInfo: 'Tipos de archivo permitidos: {{allowedContentTypes}}'
Are you sure you want to continue?: ¿Seguro que quieres continuar?
Add thermograph: Añadir termógrafo

View File

@ -13,7 +13,7 @@ module.exports = Self => {
});
Self.allowedContentTypes = async() => {
const storageConnector = Self.app.dataSources.storage.connector;
const storageConnector = Self.app.dataSources.dmsStorage.connector;
const allowedContentTypes = storageConnector.allowedContentTypes;
const modelAllowedContentTypes = Self.definition.settings.allowedContentTypes;

View File

@ -1,6 +1,18 @@
<vn-descriptor-content
module="worker"
description="$ctrl.worker.firstName +' '+ $ctrl.worker.lastName">
<slot-before>
<div class="photo" text-center>
<img vn-id="photo"
ng-src="{{$root.imagePath('user', '520x520', $ctrl.worker.id)}}"
zoom-image="{{$root.imagePath('user', '1600x900', $ctrl.worker.id)}}"
on-error-src/>
<vn-float-button ng-click="uploadPhoto.show('user', $ctrl.worker.id)"
icon="edit"
vn-visible-by="marketing, hr">
</vn-float-button>
</div>
</slot-before>
<slot-body>
<div class="attributes">
<vn-label-value
@ -43,3 +55,9 @@
</div>
</slot-body>
</vn-descriptor-content>
<!-- Upload photo dialog -->
<vn-upload-photo
vn-id="uploadPhoto"
on-response="$ctrl.onUploadResponse()">
</vn-upload-photo>

View File

@ -2,6 +2,11 @@ import ngModule from '../module';
import Descriptor from 'salix/components/descriptor';
class Controller extends Descriptor {
constructor($element, $, $rootScope) {
super($element, $);
this.$rootScope = $rootScope;
}
get worker() {
return this.entity;
}
@ -48,7 +53,20 @@ class Controller extends Descriptor {
return this.getData(`Workers/${this.id}`, {filter})
.then(res => this.entity = res.data);
}
onUploadResponse() {
const timestamp = new Date().getTime();
const src = this.$rootScope.imagePath('user', '520x520', this.worker.id);
const zoomSrc = this.$rootScope.imagePath('user', '1600x900', this.worker.id);
const newSrc = `${src}&t=${timestamp}`;
const newZoomSrc = `${zoomSrc}&t=${timestamp}`;
this.$.photo.setAttribute('src', newSrc);
this.$.photo.setAttribute('zoom-image', newZoomSrc);
}
}
Controller.$inject = ['$element', '$scope', '$rootScope'];
ngModule.vnComponent('vnWorkerDescriptor', {
template: require('./index.html'),