diff --git a/.env b/.env
index 60eb969019..941830019b 100644
--- a/.env
+++ b/.env
@@ -1,4 +1,5 @@
PHRASEANET_PROJECT_NAME=Phraseanet
+PHRASEANET_SERVER_NAME=localhost
# Registry from where you pull Docker images
PHRASEANET_DOCKER_REGISTRY=local
# Tag of the Docker images
@@ -37,6 +38,11 @@ SESSION_CACHE_LIMITER=off
# PHP LOG LEVEL : Possible Values: alert, error, warning, notice, debug
PHP_LOG_LEVEL=warning
+# --------------- MYSQL CONFIGURATION --------------------
+
+# Mysql max allowed packet
+MYSQL_MAX_ALLOWED_PACKET=16M
+
# --------------- PHRASEANET CONFIGURATION --------------------
# These variables are used in the configuration.yml .
@@ -54,11 +60,6 @@ PHRASEANET_DB_PASSWORD=root
INSTALL_DB_TEMPLATE=DublinCore
INSTALL_APPBOX=ab_master
INSTALL_DATABOX=db_databox1
-PHRASEANET_SERVER_NAME=localhost
-
-# Mysql max allowed packet
-MYSQL_MAX_ALLOWED_PACKET=16M
-
# binaries execution timeouts
PHRASEANET_FFMPEG_TIMEOUT=7200
PHRASEANET_FFPROBE_TIMEOUT=120
@@ -79,15 +80,32 @@ PHRASEANET_API_AUTH_TOKEN_HEADER_ONLY=false
# Phraseanet mail configuration
PHRASEANET_EMITTER_EMAIL=phraseanet@example.com
-PHRASEANET_MAIL_OBJECT_PREFIX=
-PHRASEANET_SMTP_ENABLED=false
-PHRASEANET_SMTP_HOST=
-PHRASEANET_SMTP_PORT=
+PHRASEANET_MAIL_OBJECT_PREFIX="phraseanet"
+PHRASEANET_SMTP_ENABLED=true
+PHRASEANET_SMTP_HOST=mailhog
+PHRASEANET_SMTP_PORT=1025
PHRASEANET_SMTP_AUTH_ENABLED=false
-PHRASEANET_SMTP_SECURE_MODE=tls
+PHRASEANET_SMTP_SECURE_MODE=null
PHRASEANET_SMTP_USER=
PHRASEANET_SMTP_PASSWORD=
+# Phraseanet Workers setting
+PHRASEANET_EXPLODE_WORKER=1
+PHRASEANET_WORKER_assetsIngest=1
+PHRASEANET_WORKER_createRecord=2
+PHRASEANET_WORKER_deleteRecord=2
+PHRASEANET_WORKER_exportMail=2
+PHRASEANET_WORKER_exposeUpload=2
+PHRASEANET_WORKER_ftp=1
+PHRASEANET_WORKER_mainQueue=3
+PHRASEANET_WORKER_populateIndex=1
+PHRASEANET_WORKER_pullAssets=1
+PHRASEANET_WORKER_recordEdit=2
+PHRASEANET_WORKER_subdefCreation=1
+PHRASEANET_WORKER_subtitle=1
+PHRASEANET_WORKER_validationReminder=1
+PHRASEANET_WORKER_webhook=1
+PHRASEANET_WORKER_writeMetadatas=1
# Locale setting
@@ -100,6 +118,18 @@ LC_CTYPE=C.UTF-8
LC_TIME=C.UTF-8
LC_NAME=C.UTF-8
+# --- EXTERNAL BINARIES SETTING ----
+
+# ImageMagick default policy override
+IMAGEMAGICK_POLICY_VERSION=6
+IMAGEMAGICK_POLICY_WIDTH=16KP
+IMAGEMAGICK_POLICY_HEIGHT=16KP
+IMAGEMAGICK_POLICY_MAP=512MiB
+IMAGEMAGICK_POLICY_MEMORY=256MiB
+IMAGEMAGICK_POLICY_AREA=128MB
+IMAGEMAGICK_POLICY_DISK=1GiB
+IMAGEMAGICK_POLICY_TEMPORARY_PATH=/tmp
+
# --- DEV purpose ---
# PhpMyAdmin port
@@ -140,3 +170,4 @@ SSH_AUTH_SOCK=/dev/null
# Plugin support
PHRASEANET_PLUGINS=
PHRASEANET_SSH_PRIVATE_KEY=
+
diff --git a/Dockerfile b/Dockerfile
index adf98b9b06..df7a049884 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -215,7 +215,7 @@ CMD ["php-fpm", "-F"]
FROM phraseanet-fpm as phraseanet-worker
ENTRYPOINT ["docker/phraseanet/worker/entrypoint.sh"]
-CMD ["bin/console", "worker:execute"]
+CMD ["/bin/bash", "bin/run-worker.sh"]
#########################################################################
# phraseanet-nginx
diff --git a/Phraseanet-production-client/dist/production.js b/Phraseanet-production-client/dist/production.js
index 2b1c8ef5b3..d18157d6ca 100644
--- a/Phraseanet-production-client/dist/production.js
+++ b/Phraseanet-production-client/dist/production.js
@@ -10230,15 +10230,15 @@ var workzone = function workzone(services) {
selection: new _selectable2.default(services, (0, _jquery2.default)('#baskets'), { selector: '.CHIM' }),
refresh: refreshBaskets,
addElementToBasket: function addElementToBasket(options) {
- var sbas_id = options.sbas_id,
- record_id = options.record_id,
+ var dbId = options.dbId,
+ recordId = options.recordId,
event = options.event,
singleSelection = options.singleSelection;
singleSelection = !!singleSelection || false;
if ((0, _jquery2.default)('#baskets .SSTT.active').length === 1) {
- return dropOnBask(event, (0, _jquery2.default)('#IMGT_' + sbas_id + '_' + record_id), (0, _jquery2.default)('#baskets .SSTT.active'), singleSelection);
+ return dropOnBask(event, (0, _jquery2.default)('#IMGT_' + dbId + '_' + recordId), (0, _jquery2.default)('#baskets .SSTT.active'), singleSelection);
} else {
humane.info(localeService.t('noActiveBasket'));
}
@@ -10397,9 +10397,9 @@ var workzone = function workzone(services) {
});
function WorkZoneElementRemover(el, confirm) {
- var context = el.data('context');
+ var context = (0, _jquery2.default)(el).data('context');
- if (confirm !== true && (0, _jquery2.default)(el).hasClass('groupings') && warnOnRemove) {
+ if (confirm !== true && ((0, _jquery2.default)(el).hasClass('groupings') || (0, _jquery2.default)(el).closest('.chim-wrapper').hasClass('chim-feedback-item')) && warnOnRemove) {
var buttons = {};
buttons[localeService.t('valider')] = function () {
@@ -10411,9 +10411,18 @@ var workzone = function workzone(services) {
(0, _jquery2.default)('#DIALOG-baskets').dialog('close').remove();
};
- var texte = '
' + localeService.t('confirmRemoveReg') + '
' + localeService.t('hideMessage') + '
';
+ var texte = '';
+ var title = '';
+ if ((0, _jquery2.default)(el).hasClass('groupings')) {
+ texte = '' + localeService.t('confirmRemoveReg') + '
' + localeService.t('hideMessage') + '
';
+ title = localeService.t('removeTitle');
+ } else {
+ texte = '' + localeService.t('confirmRemoveFeedBack') + '
';
+ title = localeService.t('removeRecordFeedbackTitle');
+ }
+
(0, _jquery2.default)('body').append('');
- (0, _jquery2.default)('#DIALOG-baskets').attr('title', localeService.t('removeTitle')).empty().append(texte).dialog({
+ (0, _jquery2.default)('#DIALOG-baskets').attr('title', title).empty().append(texte).dialog({
autoOpen: false,
closeOnEscape: true,
resizable: false,
@@ -10519,7 +10528,9 @@ var workzone = function workzone(services) {
uiactive.addClass('ui-state-focus active');
+ // reset selection when opening a basket type
workzoneOptions.selection.empty();
+ appEvents.emit('broadcast.workzoneResultSelection', { asArray: [], serialized: "" });
getContent(uiactive);
},
@@ -10884,6 +10895,10 @@ var workzone = function workzone(services) {
left: -20
},
start: function start(event, ui) {
+ if (!(0, _jquery2.default)(this).hasClass('selected')) {
+ return false;
+ }
+
var baskets = (0, _jquery2.default)('#baskets');
baskets.append('' + '');
(0, _jquery2.default)('.bottom-scroller', baskets).bind('mousemove', function () {
@@ -10898,9 +10913,9 @@ var workzone = function workzone(services) {
},
drag: function drag(event, ui) {
if (appCommons.utilsModule.is_ctrl_key(event) || (0, _jquery2.default)(this).closest('.content').hasClass('grouping')) {
- (0, _jquery2.default)('#dragDropCursor div').empty().append('+ ' + workzoneOptions.selection.length());
+ (0, _jquery2.default)('#dragDropCursor div').empty().append(workzoneOptions.selection.length() + ', ' + localeService.t('movedRecord'));
} else {
- (0, _jquery2.default)('#dragDropCursor div').empty().append(workzoneOptions.selection.length());
+ (0, _jquery2.default)('#dragDropCursor div').empty().append('+ ' + workzoneOptions.selection.length());
}
}
});
@@ -11042,7 +11057,7 @@ var workzone = function workzone(services) {
switch (action) {
case 'CHU2CHU':
- if (!appCommons.utilsModule.is_ctrl_key(event)) act = 'MOV';
+ if (appCommons.utilsModule.is_ctrl_key(event)) act = 'MOV';
break;
case 'IMGT2REG':
case 'CHU2REG':
@@ -11125,25 +11140,28 @@ var workzone = function workzone(services) {
var publicationId = destKey.attr('data-publication-id');
var exposeName = (0, _jquery2.default)('#expose_list').val();
var assetsContainer = destKey.find('.expose_item_deployed');
- assetsContainer.empty().addClass('loading');
- _jquery2.default.ajax({
- type: 'POST',
- url: '/prod/expose/publication/add-assets',
- data: {
- publicationId: publicationId,
- exposeName: exposeName,
- lst: data.lst
- },
- dataType: 'json',
- success: function success(data) {
- setTimeout(function () {
- getPublicationAssetsList(publicationId, exposeName, assetsContainer, 1);
- }, 6000);
+ if (publicationId !== undefined) {
+ assetsContainer.empty().addClass('loading');
- console.log(data.message);
- }
- });
+ _jquery2.default.ajax({
+ type: 'POST',
+ url: '/prod/expose/publication/add-assets',
+ data: {
+ publicationId: publicationId,
+ exposeName: exposeName,
+ lst: data.lst
+ },
+ dataType: 'json',
+ success: function success(data) {
+ setTimeout(function () {
+ getPublicationAssetsList(publicationId, exposeName, assetsContainer, 1);
+ }, 6000);
+
+ console.log(data.message);
+ }
+ });
+ }
}
}
@@ -63419,7 +63437,7 @@ var addToBasket = function addToBasket(services) {
var dbId = $el.data('db-id');
var recordId = $el.data('record-id');
appEvents.emit('workzone.doAddToBasket', {
- dbId: dbId, recordId: recordId, event: event.currentTarget
+ dbId: dbId, recordId: recordId, event: event.currentTarget, singleSelection: true
});
});
};
@@ -65231,13 +65249,12 @@ var previewRecordService = function previewRecordService(services) {
event.preventDefault();
closePreview();
}).on('dblclick', '.open-preview-action', function (event) {
- var $el = (0, _jquery2.default)(event.currentTarget);
- // env, pos, contId, reload
- var reload = $el.data('reload') === true ? true : false;
- _openPreview(event.currentTarget, $el.data('kind'), $el.data('position'), $el.data('id'), $el.data('kind'));
+ var $element = (0, _jquery2.default)(event.currentTarget);
+ openPreview($element);
}).on('click', '.to-open-preview-action', function (event) {
event.preventDefault();
- (0, _jquery2.default)('.open-preview-action').trigger("dblclick");
+ var $element = (0, _jquery2.default)(event.currentTarget);
+ openPreview($element);
});
$previewContainer.on('click', '.preview-navigate-action', function (event) {
event.preventDefault();
@@ -65481,7 +65498,18 @@ var previewRecordService = function previewRecordService(services) {
(0, _jquery2.default)('#PREVIEWBOX img.record.zoomable').draggable();
}
- (0, _jquery2.default)('#SPANTITLE').empty().append(data.title);
+ var basketIcon = '';
+ if (data.containerType !== null) {
+ if (data.containerType === 'feedback') {
+ basketIcon = "
";
+ } else if (data.containerType === 'push') {
+ basketIcon = "
";
+ } else {
+ basketIcon = "
";
+ }
+ }
+
+ (0, _jquery2.default)('#SPANTITLE').empty().append(basketIcon + data.title);
(0, _jquery2.default)('#PREVIEWTITLE_COLLLOGO').empty().append(data.collection_logo);
(0, _jquery2.default)('#PREVIEWTITLE_COLLNAME').empty().append(data.databox_name + ' / ' + data.collection_name);
@@ -65544,6 +65572,12 @@ var previewRecordService = function previewRecordService(services) {
(0, _jquery2.default)("iframe", $sel).css('width', NW).css('height', NH);
}
+ function openPreview($element) {
+ var reload = $element.data('reload') === true ? true : false;
+ // env, pos, contId, reload
+ _openPreview(event.currentTarget, $element.data('kind'), $element.data('position'), $element.data('id'), reload);
+ }
+
function closePreview() {
options.open = false;
if (activeThumbnailFrame !== false) {
diff --git a/Phraseanet-production-client/dist/production.min.js b/Phraseanet-production-client/dist/production.min.js
index 2b1c8ef5b3..d18157d6ca 100644
--- a/Phraseanet-production-client/dist/production.min.js
+++ b/Phraseanet-production-client/dist/production.min.js
@@ -10230,15 +10230,15 @@ var workzone = function workzone(services) {
selection: new _selectable2.default(services, (0, _jquery2.default)('#baskets'), { selector: '.CHIM' }),
refresh: refreshBaskets,
addElementToBasket: function addElementToBasket(options) {
- var sbas_id = options.sbas_id,
- record_id = options.record_id,
+ var dbId = options.dbId,
+ recordId = options.recordId,
event = options.event,
singleSelection = options.singleSelection;
singleSelection = !!singleSelection || false;
if ((0, _jquery2.default)('#baskets .SSTT.active').length === 1) {
- return dropOnBask(event, (0, _jquery2.default)('#IMGT_' + sbas_id + '_' + record_id), (0, _jquery2.default)('#baskets .SSTT.active'), singleSelection);
+ return dropOnBask(event, (0, _jquery2.default)('#IMGT_' + dbId + '_' + recordId), (0, _jquery2.default)('#baskets .SSTT.active'), singleSelection);
} else {
humane.info(localeService.t('noActiveBasket'));
}
@@ -10397,9 +10397,9 @@ var workzone = function workzone(services) {
});
function WorkZoneElementRemover(el, confirm) {
- var context = el.data('context');
+ var context = (0, _jquery2.default)(el).data('context');
- if (confirm !== true && (0, _jquery2.default)(el).hasClass('groupings') && warnOnRemove) {
+ if (confirm !== true && ((0, _jquery2.default)(el).hasClass('groupings') || (0, _jquery2.default)(el).closest('.chim-wrapper').hasClass('chim-feedback-item')) && warnOnRemove) {
var buttons = {};
buttons[localeService.t('valider')] = function () {
@@ -10411,9 +10411,18 @@ var workzone = function workzone(services) {
(0, _jquery2.default)('#DIALOG-baskets').dialog('close').remove();
};
- var texte = '' + localeService.t('confirmRemoveReg') + '
' + localeService.t('hideMessage') + '
';
+ var texte = '';
+ var title = '';
+ if ((0, _jquery2.default)(el).hasClass('groupings')) {
+ texte = '' + localeService.t('confirmRemoveReg') + '
' + localeService.t('hideMessage') + '
';
+ title = localeService.t('removeTitle');
+ } else {
+ texte = '' + localeService.t('confirmRemoveFeedBack') + '
';
+ title = localeService.t('removeRecordFeedbackTitle');
+ }
+
(0, _jquery2.default)('body').append('');
- (0, _jquery2.default)('#DIALOG-baskets').attr('title', localeService.t('removeTitle')).empty().append(texte).dialog({
+ (0, _jquery2.default)('#DIALOG-baskets').attr('title', title).empty().append(texte).dialog({
autoOpen: false,
closeOnEscape: true,
resizable: false,
@@ -10519,7 +10528,9 @@ var workzone = function workzone(services) {
uiactive.addClass('ui-state-focus active');
+ // reset selection when opening a basket type
workzoneOptions.selection.empty();
+ appEvents.emit('broadcast.workzoneResultSelection', { asArray: [], serialized: "" });
getContent(uiactive);
},
@@ -10884,6 +10895,10 @@ var workzone = function workzone(services) {
left: -20
},
start: function start(event, ui) {
+ if (!(0, _jquery2.default)(this).hasClass('selected')) {
+ return false;
+ }
+
var baskets = (0, _jquery2.default)('#baskets');
baskets.append('' + '');
(0, _jquery2.default)('.bottom-scroller', baskets).bind('mousemove', function () {
@@ -10898,9 +10913,9 @@ var workzone = function workzone(services) {
},
drag: function drag(event, ui) {
if (appCommons.utilsModule.is_ctrl_key(event) || (0, _jquery2.default)(this).closest('.content').hasClass('grouping')) {
- (0, _jquery2.default)('#dragDropCursor div').empty().append('+ ' + workzoneOptions.selection.length());
+ (0, _jquery2.default)('#dragDropCursor div').empty().append(workzoneOptions.selection.length() + ', ' + localeService.t('movedRecord'));
} else {
- (0, _jquery2.default)('#dragDropCursor div').empty().append(workzoneOptions.selection.length());
+ (0, _jquery2.default)('#dragDropCursor div').empty().append('+ ' + workzoneOptions.selection.length());
}
}
});
@@ -11042,7 +11057,7 @@ var workzone = function workzone(services) {
switch (action) {
case 'CHU2CHU':
- if (!appCommons.utilsModule.is_ctrl_key(event)) act = 'MOV';
+ if (appCommons.utilsModule.is_ctrl_key(event)) act = 'MOV';
break;
case 'IMGT2REG':
case 'CHU2REG':
@@ -11125,25 +11140,28 @@ var workzone = function workzone(services) {
var publicationId = destKey.attr('data-publication-id');
var exposeName = (0, _jquery2.default)('#expose_list').val();
var assetsContainer = destKey.find('.expose_item_deployed');
- assetsContainer.empty().addClass('loading');
- _jquery2.default.ajax({
- type: 'POST',
- url: '/prod/expose/publication/add-assets',
- data: {
- publicationId: publicationId,
- exposeName: exposeName,
- lst: data.lst
- },
- dataType: 'json',
- success: function success(data) {
- setTimeout(function () {
- getPublicationAssetsList(publicationId, exposeName, assetsContainer, 1);
- }, 6000);
+ if (publicationId !== undefined) {
+ assetsContainer.empty().addClass('loading');
- console.log(data.message);
- }
- });
+ _jquery2.default.ajax({
+ type: 'POST',
+ url: '/prod/expose/publication/add-assets',
+ data: {
+ publicationId: publicationId,
+ exposeName: exposeName,
+ lst: data.lst
+ },
+ dataType: 'json',
+ success: function success(data) {
+ setTimeout(function () {
+ getPublicationAssetsList(publicationId, exposeName, assetsContainer, 1);
+ }, 6000);
+
+ console.log(data.message);
+ }
+ });
+ }
}
}
@@ -63419,7 +63437,7 @@ var addToBasket = function addToBasket(services) {
var dbId = $el.data('db-id');
var recordId = $el.data('record-id');
appEvents.emit('workzone.doAddToBasket', {
- dbId: dbId, recordId: recordId, event: event.currentTarget
+ dbId: dbId, recordId: recordId, event: event.currentTarget, singleSelection: true
});
});
};
@@ -65231,13 +65249,12 @@ var previewRecordService = function previewRecordService(services) {
event.preventDefault();
closePreview();
}).on('dblclick', '.open-preview-action', function (event) {
- var $el = (0, _jquery2.default)(event.currentTarget);
- // env, pos, contId, reload
- var reload = $el.data('reload') === true ? true : false;
- _openPreview(event.currentTarget, $el.data('kind'), $el.data('position'), $el.data('id'), $el.data('kind'));
+ var $element = (0, _jquery2.default)(event.currentTarget);
+ openPreview($element);
}).on('click', '.to-open-preview-action', function (event) {
event.preventDefault();
- (0, _jquery2.default)('.open-preview-action').trigger("dblclick");
+ var $element = (0, _jquery2.default)(event.currentTarget);
+ openPreview($element);
});
$previewContainer.on('click', '.preview-navigate-action', function (event) {
event.preventDefault();
@@ -65481,7 +65498,18 @@ var previewRecordService = function previewRecordService(services) {
(0, _jquery2.default)('#PREVIEWBOX img.record.zoomable').draggable();
}
- (0, _jquery2.default)('#SPANTITLE').empty().append(data.title);
+ var basketIcon = '';
+ if (data.containerType !== null) {
+ if (data.containerType === 'feedback') {
+ basketIcon = "
";
+ } else if (data.containerType === 'push') {
+ basketIcon = "
";
+ } else {
+ basketIcon = "
";
+ }
+ }
+
+ (0, _jquery2.default)('#SPANTITLE').empty().append(basketIcon + data.title);
(0, _jquery2.default)('#PREVIEWTITLE_COLLLOGO').empty().append(data.collection_logo);
(0, _jquery2.default)('#PREVIEWTITLE_COLLNAME').empty().append(data.databox_name + ' / ' + data.collection_name);
@@ -65544,6 +65572,12 @@ var previewRecordService = function previewRecordService(services) {
(0, _jquery2.default)("iframe", $sel).css('width', NW).css('height', NH);
}
+ function openPreview($element) {
+ var reload = $element.data('reload') === true ? true : false;
+ // env, pos, contId, reload
+ _openPreview(event.currentTarget, $element.data('kind'), $element.data('position'), $element.data('id'), reload);
+ }
+
function closePreview() {
options.open = false;
if (activeThumbnailFrame !== false) {
diff --git a/Phraseanet-production-client/src/components/record/addToBasket.js b/Phraseanet-production-client/src/components/record/addToBasket.js
index 95a31f9b5a..c898896b02 100644
--- a/Phraseanet-production-client/src/components/record/addToBasket.js
+++ b/Phraseanet-production-client/src/components/record/addToBasket.js
@@ -11,7 +11,7 @@ const addToBasket = (services) => {
let dbId = $el.data('db-id');
let recordId = $el.data('record-id');
appEvents.emit('workzone.doAddToBasket', {
- dbId, recordId, event: event.currentTarget
+ dbId, recordId, event: event.currentTarget, singleSelection: true
});
});
};
diff --git a/Phraseanet-production-client/src/components/record/recordPreview/index.js b/Phraseanet-production-client/src/components/record/recordPreview/index.js
index ba2066e304..38b0089fb8 100644
--- a/Phraseanet-production-client/src/components/record/recordPreview/index.js
+++ b/Phraseanet-production-client/src/components/record/recordPreview/index.js
@@ -81,20 +81,14 @@ const previewRecordService = services => {
closePreview();
})
.on('dblclick', '.open-preview-action', event => {
- let $el = $(event.currentTarget);
- // env, pos, contId, reload
- let reload = $el.data('reload') === true ? true : false;
- _openPreview(
- event.currentTarget,
- $el.data('kind'),
- $el.data('position'),
- $el.data('id'),
- $el.data('kind')
- );
+ let $element = $(event.currentTarget);
+ openPreview($element);
+
})
.on('click', '.to-open-preview-action', event => {
event.preventDefault();
- $( '.open-preview-action' ).trigger( "dblclick" );
+ let $element = $(event.currentTarget);
+ openPreview($element);
})
;
$previewContainer
@@ -387,7 +381,18 @@ const previewRecordService = services => {
$('#PREVIEWBOX img.record.zoomable').draggable();
}
- $('#SPANTITLE').empty().append(data.title);
+ let basketIcon = '';
+ if (data.containerType !== null ) {
+ if (data.containerType === 'feedback') {
+ basketIcon = "
";
+ } else if (data.containerType === 'push') {
+ basketIcon = "
";
+ } else {
+ basketIcon = "
";
+ }
+ }
+
+ $('#SPANTITLE').empty().append(basketIcon + data.title);
$('#PREVIEWTITLE_COLLLOGO')
.empty()
.append(data.collection_logo);
@@ -466,6 +471,18 @@ const previewRecordService = services => {
}
+ function openPreview($element) {
+ let reload = $element.data('reload') === true ? true : false;
+ // env, pos, contId, reload
+ _openPreview(
+ event.currentTarget,
+ $element.data('kind'),
+ $element.data('position'),
+ $element.data('id'),
+ reload
+ );
+ }
+
function closePreview() {
options.open = false;
if (activeThumbnailFrame !== false) {
diff --git a/Phraseanet-production-client/src/components/ui/workzone/index.js b/Phraseanet-production-client/src/components/ui/workzone/index.js
index 4a399757ff..4cef61e3a0 100644
--- a/Phraseanet-production-client/src/components/ui/workzone/index.js
+++ b/Phraseanet-production-client/src/components/ui/workzone/index.js
@@ -214,11 +214,11 @@ const workzone = (services) => {
selection: new Selectable(services, $('#baskets'), {selector: '.CHIM'}),
refresh: refreshBaskets,
addElementToBasket: function (options) {
- let {sbas_id, record_id, event, singleSelection} = options;
+ let {dbId, recordId, event, singleSelection} = options;
singleSelection = !!singleSelection || false;
if ($('#baskets .SSTT.active').length === 1) {
- return dropOnBask(event, $('#IMGT_' + sbas_id + '_' + record_id), $('#baskets .SSTT.active'), singleSelection);
+ return dropOnBask(event, $('#IMGT_' + dbId + '_' + recordId), $('#baskets .SSTT.active'), singleSelection);
} else {
humane.info(localeService.t('noActiveBasket'));
}
@@ -373,9 +373,9 @@ const workzone = (services) => {
});
function WorkZoneElementRemover(el, confirm) {
- var context = el.data('context');
+ var context = $(el).data('context');
- if (confirm !== true && $(el).hasClass('groupings') && warnOnRemove) {
+ if (confirm !== true && ($(el).hasClass('groupings') || $(el).closest('.chim-wrapper').hasClass('chim-feedback-item')) && warnOnRemove) {
var buttons = {};
buttons[localeService.t('valider')] = function () {
@@ -387,9 +387,18 @@ const workzone = (services) => {
$('#DIALOG-baskets').dialog('close').remove();
};
- var texte = '' + localeService.t('confirmRemoveReg') + '
' + localeService.t('hideMessage') + '
';
+ var texte = '';
+ var title = '';
+ if ($(el).hasClass('groupings')) {
+ texte = '' + localeService.t('confirmRemoveReg') + '
' + localeService.t('hideMessage') + '
';
+ title = localeService.t('removeTitle');
+ } else {
+ texte = '' + localeService.t('confirmRemoveFeedBack') + '
';
+ title = localeService.t('removeRecordFeedbackTitle');
+ }
+
$('body').append('');
- $('#DIALOG-baskets').attr('title', localeService.t('removeTitle'))
+ $('#DIALOG-baskets').attr('title', title)
.empty()
.append(texte)
.dialog({
@@ -500,7 +509,9 @@ const workzone = (services) => {
uiactive.addClass('ui-state-focus active');
+ // reset selection when opening a basket type
workzoneOptions.selection.empty();
+ appEvents.emit('broadcast.workzoneResultSelection', {asArray:[], serialized:""});
getContent(uiactive);
@@ -874,6 +885,10 @@ const workzone = (services) => {
left: -20
},
start: function (event, ui) {
+ if (!$(this).hasClass('selected')) {
+ return false;
+ }
+
var baskets = $('#baskets');
baskets.append('' +
'');
@@ -891,11 +906,10 @@ const workzone = (services) => {
},
drag: function (event, ui) {
if (appCommons.utilsModule.is_ctrl_key(event) || $(this).closest('.content').hasClass('grouping')) {
- $('#dragDropCursor div').empty().append('+ ' + workzoneOptions.selection.length());
+ $('#dragDropCursor div').empty().append(workzoneOptions.selection.length() + ', ' + localeService.t('movedRecord'));
} else {
- $('#dragDropCursor div').empty().append(workzoneOptions.selection.length());
+ $('#dragDropCursor div').empty().append('+ ' + workzoneOptions.selection.length());
}
-
}
});
window.workzoneOptions = workzoneOptions;
@@ -1043,7 +1057,7 @@ const workzone = (services) => {
switch (action) {
case 'CHU2CHU' :
- if (!appCommons.utilsModule.is_ctrl_key(event)) act = 'MOV';
+ if (appCommons.utilsModule.is_ctrl_key(event)) act = 'MOV';
break;
case 'IMGT2REG':
case 'CHU2REG' :
@@ -1129,26 +1143,29 @@ const workzone = (services) => {
let publicationId = destKey.attr('data-publication-id');
let exposeName = $('#expose_list').val();
let assetsContainer = destKey.find('.expose_item_deployed');
- assetsContainer.empty().addClass('loading');
- $.ajax({
- type: 'POST',
- url: '/prod/expose/publication/add-assets',
- data: {
- publicationId: publicationId,
- exposeName: exposeName,
- lst: data.lst
- },
- dataType: 'json',
- success: function (data) {
- setTimeout(function(){
- getPublicationAssetsList(publicationId, exposeName, assetsContainer, 1);
- }
- , 6000);
+ if (publicationId !== undefined) {
+ assetsContainer.empty().addClass('loading');
- console.log(data.message);
- }
- });
+ $.ajax({
+ type: 'POST',
+ url: '/prod/expose/publication/add-assets',
+ data: {
+ publicationId: publicationId,
+ exposeName: exposeName,
+ lst: data.lst
+ },
+ dataType: 'json',
+ success: function (data) {
+ setTimeout(function(){
+ getPublicationAssetsList(publicationId, exposeName, assetsContainer, 1);
+ }
+ , 6000);
+
+ console.log(data.message);
+ }
+ });
+ }
}
}
diff --git a/config/configuration.sample.yml b/config/configuration.sample.yml
index 2ee204596b..21fef21576 100644
--- a/config/configuration.sample.yml
+++ b/config/configuration.sample.yml
@@ -323,14 +323,23 @@ geocoding-providers:
provincefields: Province
countryfields: Country, Pays
workers:
- queue:
- worker-queue:
- registry: alchemy_worker.queue_registry
- host: localhost
- port: 5672
- user: guest
- password: guest
- vhost: /
+ queue:
+ worker-queue:
+ registry: alchemy_worker.queue_registry
+ host: localhost
+ port: 5672
+ user: guest
+ password: guest
+ vhost: /
+ queues:
+ writeMetadatas: # this Q is "delayable" in case of record is locked
+ ttl_retry: 1500 # overwrite 1000 ms default delay
+ ttl_delayed: 10000 # overwrite 5000 ms default delay
+ subdefCreation: # this Q is "delayable" in case of record is locked
+ ttl_delayed: 10000 # overwrite 5000 ms default delay
+ pullAssets:
+ ttl_retry: 5000
+ max_retry : 5
externalservice:
ginger:
diff --git a/docker-compose.yml b/docker-compose.yml
index 605538354e..03bd619603 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -119,6 +119,7 @@ services:
- redis
- rabbitmq
- elasticsearch
+ - phraseanet
environment:
- PHRASEANET_PROJECT_NAME
- PHRASEANET_TRUSTED_PROXIES
@@ -135,7 +136,30 @@ services:
- LC_CTYPE=C.UTF-8
- LC_TIME=C.UTF-8
- LC_NAME=C.UTF-8
-
+ - PHRASEANET_EXPLODE_WORKER
+ - PHRASEANET_WORKER_assetsIngest
+ - PHRASEANET_WORKER_createRecord
+ - PHRASEANET_WORKER_deleteRecord
+ - PHRASEANET_WORKER_exportMail
+ - PHRASEANET_WORKER_exposeUpload
+ - PHRASEANET_WORKER_ftp
+ - PHRASEANET_WORKER_mainQueue
+ - PHRASEANET_WORKER_populateIndex
+ - PHRASEANET_WORKER_pullAssets
+ - PHRASEANET_WORKER_recordEdit
+ - PHRASEANET_WORKER_subdefCreation
+ - PHRASEANET_WORKER_subtitle
+ - PHRASEANET_WORKER_validationReminder
+ - PHRASEANET_WORKER_webhook
+ - PHRASEANET_WORKER_writeMetadatas
+ - IMAGEMAGICK_POLICY_VERSION
+ - IMAGEMAGICK_POLICY_WIDTH
+ - IMAGEMAGICK_POLICY_HEIGHT
+ - IMAGEMAGICK_POLICY_MAP
+ - IMAGEMAGICK_POLICY_MEMORY
+ - IMAGEMAGICK_POLICY_AREA
+ - IMAGEMAGICK_POLICY_DISK
+ - IMAGEMAGICK_POLICY_TEMPORARY_PATH
volumes:
- ${PHRASEANET_CONFIG_DIR}:/var/alchemy/Phraseanet/config:rw
- ${PHRASEANET_LOGS_DIR}:/var/alchemy/Phraseanet/logs:rw
diff --git a/docker/phraseanet/entrypoint.sh b/docker/phraseanet/entrypoint.sh
index 4fd1e76c79..929d89eabe 100755
--- a/docker/phraseanet/entrypoint.sh
+++ b/docker/phraseanet/entrypoint.sh
@@ -38,7 +38,7 @@ if [ -f "$FILE" ]; then
if [[ $PHRASEANET_SMTP_ENABLED && $PHRASEANET_SMTP_ENABLED = true ]]; then
bin/setup system:config set registry.email.smtp-enabled $PHRASEANET_SMTP_ENABLED
bin/setup system:config set registry.email.smtp-auth-enabled $PHRASEANET_SMTP_AUTH_ENABLED
- bin/setup system:config set registry.email.smtp-auth-secure-mode $PHRASEANET_SMTP_SECURE_MODE
+ bin/setup system:config set registry.email.smtp-secure-mode $PHRASEANET_SMTP_SECURE_MODE
bin/setup system:config set registry.email.smtp-host $PHRASEANET_SMTP_HOST
bin/setup system:config set registry.email.smtp-port $PHRASEANET_SMTP_PORT
bin/setup system:config set registry.email.smtp-user $PHRASEANET_SMTP_USER
@@ -49,7 +49,7 @@ if [ -f "$FILE" ]; then
if [[ -n ${PHRASEANET_ADMIN_ACCOUNT_ID} && $PHRASEANET_ADMIN_ACCOUNT_ID =~ ^[0-9]+$ ]]; then
bin/console user:password --user_id=$PHRASEANET_ADMIN_ACCOUNT_ID --password $PHRASEANET_ADMIN_ACCOUNT_PASSWORD -y
fi
-
+ echo `date +"%Y-%m-%d %H:%M:%S"` " - config/configuration.yml update by Phraseanet entrypoint.sh Finished !"
else
echo "$FILE doesn't exist, entering setup..."
@@ -62,6 +62,7 @@ else
datas
runuser app -c docker/phraseanet/auto-install.sh
+ echo `date +"%Y-%m-%d %H:%M:%S"` " - End of Phraseanet Installation"
fi
if [ ${XDEBUG_ENABLED} == "1" ]; then
@@ -70,7 +71,8 @@ if [ ${XDEBUG_ENABLED} == "1" ]; then
fi
./docker/phraseanet/plugins/console init
-#rm -Rf cache/
+rm -Rf cache/*
+chmod 600 config/configuration.yml
chown -R app:app \
cache \
@@ -84,6 +86,7 @@ if [ -d "plugins/" ];then
chown -R app:app plugins;
fi
-chown -R app:app datas &
+chown -R app:app datas && echo `date +"%Y-%m-%d %H:%M:%S"` " - Finished chown on datas by entreypoint" &
+echo `date +"%Y-%m-%d %H:%M:%S"` " - Finished runnning Phraseanet entrypoint.sh"
bash -e docker-php-entrypoint $@
diff --git a/docker/phraseanet/worker/entrypoint.sh b/docker/phraseanet/worker/entrypoint.sh
index 763a07d8ba..2fa3c03a4f 100755
--- a/docker/phraseanet/worker/entrypoint.sh
+++ b/docker/phraseanet/worker/entrypoint.sh
@@ -15,4 +15,47 @@ if [ ${XDEBUG_ENABLED} == "1" ]; then
docker-php-ext-enable xdebug
fi
+if [ -f /etc/ImageMagick-$IMAGEMAGICK_POLICY_VERSION/policy.xml ]; then
+ if [ ! -d $IMAGEMAGICK_POLICY_TEMPORARY_PATH ]; then
+ echo "$IMAGEMAGICK_POLICY_TEMPORARY_PATH does not exist lets create it"
+ mkdir -p $IMAGEMAGICK_POLICY_TEMPORARY_PATH
+ fi
+ sed -i "s/domain=\"resource\" name=\"memory\" value=\".*\"/domain=\"resource\" name=\"memory\" value=\"$IMAGEMAGICK_POLICY_MEMORY\"/g" /etc/ImageMagick-$IMAGEMAGICK_POLICY_VERSION/policy.xml
+ sed -i "s/domain=\"resource\" name=\"map\" value=\".*\"/domain=\"resource\" name=\"map\" value=\"$IMAGEMAGICK_POLICY_MAP\"/g" /etc/ImageMagick-$IMAGEMAGICK_POLICY_VERSION/policy.xml
+ sed -i "s/domain=\"resource\" name=\"width\" value=\".*\"/domain=\"resource\" name=\"width\" value=\"$IMAGEMAGICK_POLICY_WIDTH\"/g" /etc/ImageMagick-$IMAGEMAGICK_POLICY_VERSION/policy.xml
+ sed -i "s/domain=\"resource\" name=\"height\" value=\".*\"/domain=\"resource\" name=\"height\" value=\"$IMAGEMAGICK_POLICY_HEIGHT\"/g" /etc/ImageMagick-$IMAGEMAGICK_POLICY_VERSION/policy.xml
+ sed -i "s/domain=\"resource\" name=\"disk\" value=\".*\"/domain=\"resource\" name=\"disk\" value=\"$IMAGEMAGICK_POLICY_DISK\"/g" /etc/ImageMagick-$IMAGEMAGICK_POLICY_VERSION/policy.xml
+ sed -i "s/domain=\"resource\" name=\"area\" value=\".*\"/domain=\"resource\" name=\"area\" value=\"$IMAGEMAGICK_POLICY_AREA\"/g" /etc/ImageMagick-$IMAGEMAGICK_POLICY_VERSION/policy.xml
+ sed -i "s/.*domain=\"resource\" name=\"temporary-path\" value=\".*//g" /etc/ImageMagick-$IMAGEMAGICK_POLICY_VERSION/policy.xml
+fi
+
+rm -rf bin/run-worker.sh
+if [ ${PHRASEANET_EXPLODE_WORKER} == "1" ]; then
+ for i in `env | grep PHRASEANET_WORKER_ | cut -d'=' -f1`
+ do
+ queue_name="$(echo $i | cut -d'_' -f3)"
+ m=$i
+ command="bin/console worker:execute --queue-name=$queue_name -m ${!m} &"
+ echo $command >> bin/run-worker.sh
+ done
+
+ echo 'WORKER_NB_QUEUES=`env | grep PHRASEANET_WORKER_ | wc -l`
+ WORKER_LOOP_VALUE=20s
+ while true;
+ do
+ sleep $WORKER_LOOP_VALUE
+ nb_process=`ps faux | grep "worker:execute" | grep php | wc -l`
+ date_time_process=`date +"%Y-%m-%d %H:%M:%S"`
+ echo $date_time_process "-" $nb_process "running workers"
+ if [ $nb_process -lt $WORKER_NB_QUEUES ]
+ then
+ exit 1
+ break
+ fi
+ done ' >> bin/run-worker.sh
+else
+ command="bin/console worker:execute"
+ echo $command >> bin/run-worker.sh
+fi
+
runuser -u app -- $@
diff --git a/lib/Alchemy/Phrasea/Controller/Prod/BasketController.php b/lib/Alchemy/Phrasea/Controller/Prod/BasketController.php
index 6435d80b7d..483242e87c 100644
--- a/lib/Alchemy/Phrasea/Controller/Prod/BasketController.php
+++ b/lib/Alchemy/Phrasea/Controller/Prod/BasketController.php
@@ -13,6 +13,7 @@ use Alchemy\Phrasea\Controller\Controller;
use Alchemy\Phrasea\Controller\RecordsRequest;
use Alchemy\Phrasea\Model\Entities\Basket;
use Alchemy\Phrasea\Model\Entities\BasketElement;
+use Alchemy\Phrasea\Model\Entities\ValidationData;
use Alchemy\Phrasea\Model\Manipulator\BasketManipulator;
use Alchemy\Phrasea\Model\Repositories\BasketElementRepository;
use Doctrine\ORM\EntityManagerInterface;
@@ -251,8 +252,25 @@ class BasketController extends Controller
continue;
}
- $basket_element->getBasket()->removeElement($basket_element);
+ $oldBasket = $basket_element->getBasket();
+
+ $oldBasket->removeElement($basket_element);
$basket->addElement($basket_element);
+
+ // configure participant when moving from other type of basket to basket type feedback
+ if ($oldBasket->getValidation() == null && ($validationSession = $basket->getValidation()) !== null) {
+
+ $participants = $validationSession->getParticipants();
+
+ foreach ($participants as $participant) {
+ $validationData = new ValidationData();
+ $validationData->setParticipant($participant);
+ $validationData->setBasketElement($basket_element);
+
+ $this->getEntityManager()->persist($validationData);
+ }
+ }
+
$n++;
}
diff --git a/lib/Alchemy/Phrasea/Controller/Prod/LanguageController.php b/lib/Alchemy/Phrasea/Controller/Prod/LanguageController.php
index db213e6a63..928c7a7d85 100644
--- a/lib/Alchemy/Phrasea/Controller/Prod/LanguageController.php
+++ b/lib/Alchemy/Phrasea/Controller/Prod/LanguageController.php
@@ -59,9 +59,12 @@ class LanguageController
'feed_require_fields' => $translator->trans('Vous n\'avez pas rempli tous les champ requis'),
'feed_require_feed' => $translator->trans('Vous n\'avez pas selectionne de fil de publication'),
'removeTitle' => $translator->trans('panier::Supression d\'un element d\'un reportage'),
+ 'removeRecordFeedbackTitle' => $translator->trans('basket:feedback Delete item'),
'removeExposePublication' => $translator->trans('expose::Your are about to delete a publication from expose, please confirm your action !'),
'removeAssetPublication' => $translator->trans('expose::Your are about to delete an asset from a publication, please confirm your action !'),
'confirmRemoveReg' => $translator->trans('panier::Attention, vous etes sur le point de supprimer un element du reportage. Merci de confirmer votre action.'),
+ 'confirmRemoveFeedBack' => $translator->trans('basket:feedback Warning!You are about to delete one record from a feedback, please confirm your action'),
+ 'movedRecord' => $translator->trans('basket:: Items are being to moved !'),
'advsearch_title' => $translator->trans('phraseanet::recherche avancee'),
'bask_rename' => $translator->trans('panier:: renommer le panier'),
'reg_wrong_sbas' => $translator->trans('panier:: Un reportage ne peux recevoir que des elements provenants de la base ou il est enregistre'),
diff --git a/lib/Alchemy/Phrasea/Controller/Prod/PushController.php b/lib/Alchemy/Phrasea/Controller/Prod/PushController.php
index a4de6b17ad..648cf715d1 100644
--- a/lib/Alchemy/Phrasea/Controller/Prod/PushController.php
+++ b/lib/Alchemy/Phrasea/Controller/Prod/PushController.php
@@ -146,7 +146,7 @@ class PushController extends Controller
$this->getDataboxLogger($element->getDatabox())->log(
$element,
- Session_Logger::EVENT_VALIDATE,
+ Session_Logger::EVENT_PUSH,
$user_receiver->getId(),
''
);
@@ -386,7 +386,7 @@ class PushController extends Controller
$this->getDataboxLogger($basketElement->getRecord($this->app)->getDatabox())->log(
$basketElement->getRecord($this->app),
- Session_Logger::EVENT_PUSH,
+ Session_Logger::EVENT_VALIDATE,
$participantUser->getId(),
''
);
diff --git a/lib/Alchemy/Phrasea/Controller/Prod/RecordController.php b/lib/Alchemy/Phrasea/Controller/Prod/RecordController.php
index 1c1e6ee250..55f18cc959 100644
--- a/lib/Alchemy/Phrasea/Controller/Prod/RecordController.php
+++ b/lib/Alchemy/Phrasea/Controller/Prod/RecordController.php
@@ -103,6 +103,18 @@ class RecordController extends Controller
$recordTitle = htmlspecialchars($record->get_title());
}
+ $containerType = null;
+
+ if ($env === 'BASK') {
+ if ($record->get_container()->getValidation()) {
+ $containerType = 'feedback';
+ } elseif ($record->get_container()->getPusher()) {
+ $containerType = 'push';
+ } else {
+ $containerType = 'basket';
+ }
+ }
+
return $this->app->json([
"desc" => $this->render('prod/preview/caption.html.twig', [
'record' => $record,
@@ -131,6 +143,7 @@ class RecordController extends Controller
]),
"pos" => $record->getNumber(),
"title" => $recordTitle,
+ "containerType" => $containerType,
"databox_name" => $record->getDatabox()->get_dbname(),
"collection_name" => $record->getCollection()->get_name(),
"collection_logo" => $record->getCollection()->getLogo($record->getBaseId(), $this->app),
diff --git a/lib/Alchemy/Phrasea/Databox/Record/LegacyRecordRepository.php b/lib/Alchemy/Phrasea/Databox/Record/LegacyRecordRepository.php
index a6a0851100..8e554c58f8 100644
--- a/lib/Alchemy/Phrasea/Databox/Record/LegacyRecordRepository.php
+++ b/lib/Alchemy/Phrasea/Databox/Record/LegacyRecordRepository.php
@@ -319,7 +319,8 @@ class LegacyRecordRepository implements RecordRepository
. $userFilter
. " WHERE g.rid_parent IN ( :storyIds )\n"
. " ORDER BY g.rid_parent, g.ord ASC\n"
- . ") r\n"
+ . ") r \n"
+ . "ORDER BY r.rid_parent, r.ord ASC\n"
;
}
diff --git a/lib/Alchemy/Phrasea/WorkerManager/Command/WorkerExecuteCommand.php b/lib/Alchemy/Phrasea/WorkerManager/Command/WorkerExecuteCommand.php
index 8fde255710..b03e716fc0 100644
--- a/lib/Alchemy/Phrasea/WorkerManager/Command/WorkerExecuteCommand.php
+++ b/lib/Alchemy/Phrasea/WorkerManager/Command/WorkerExecuteCommand.php
@@ -6,6 +6,7 @@ use Alchemy\Phrasea\Command\Command;
use Alchemy\Phrasea\WorkerManager\Queue\AMQPConnection;
use Alchemy\Phrasea\WorkerManager\Queue\MessageHandler;
use Alchemy\Phrasea\WorkerManager\Worker\WorkerInvoker;
+use Doctrine\DBAL\Connection;
use PhpAmqpLib\Channel\AMQPChannel;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
@@ -45,7 +46,7 @@ class WorkerExecuteCommand extends Command
if ($channel == null) {
$output->writeln("Can't connect to rabbit, check configuration!");
- return;
+ return 1;
}
$serverConnection->declareExchange();
@@ -56,7 +57,7 @@ class WorkerExecuteCommand extends Command
if ($input->getOption('max-processes') != null && $maxProcesses == 0) {
$output->writeln('Invalid max-processes option.Need an integer');
- return;
+ return 1;
} elseif($maxProcesses) {
$workerInvoker->setMaxProcessPoolValue($maxProcesses);
}
@@ -69,8 +70,26 @@ class WorkerExecuteCommand extends Command
$messageHandler = $this->container['alchemy_worker.message.handler'];
$messageHandler->consume($serverConnection, $workerInvoker, $argQueueName, $maxProcesses);
+ /** @var Connection $dbConnection */
+ $dbConnection = $this->container['orm.em']->getConnection();
+
while (count($channel->callbacks)) {
$output->writeln("[*] Waiting for messages. To exit press CTRL+C");
+
+ // check connection for DB before given message to consumer
+ if($dbConnection->ping() === false){
+ $output->writeln("MySQL server is not available : retry to close and connect ....");
+
+ try {
+ $dbConnection->close();
+ $dbConnection->connect();
+ } catch (\Exception $e) {
+ // Mysql server can't be reconnected, so stop the worker
+ $serverConnection->connectionClose();
+
+ return 1;
+ }
+ }
$channel->wait();
}
diff --git a/lib/Alchemy/Phrasea/WorkerManager/Controller/AdminConfigurationController.php b/lib/Alchemy/Phrasea/WorkerManager/Controller/AdminConfigurationController.php
index df009c125c..5d2f6d9ecc 100644
--- a/lib/Alchemy/Phrasea/WorkerManager/Controller/AdminConfigurationController.php
+++ b/lib/Alchemy/Phrasea/WorkerManager/Controller/AdminConfigurationController.php
@@ -13,19 +13,22 @@ use Alchemy\Phrasea\WorkerManager\Form\WorkerConfigurationType;
use Alchemy\Phrasea\WorkerManager\Form\WorkerFtpType;
use Alchemy\Phrasea\WorkerManager\Form\WorkerPullAssetsType;
use Alchemy\Phrasea\WorkerManager\Form\WorkerSearchengineType;
+use Alchemy\Phrasea\WorkerManager\Form\WorkerValidationReminderType;
use Alchemy\Phrasea\WorkerManager\Queue\AMQPConnection;
use Alchemy\Phrasea\WorkerManager\Queue\MessagePublisher;
+use Doctrine\ORM\OptimisticLockException;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+use Symfony\Component\Form\Form;
use Symfony\Component\Form\FormInterface;
+use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
+
class AdminConfigurationController extends Controller
{
- public function indexAction(PhraseaApplication $app)
+ public function indexAction(PhraseaApplication $app, Request $request)
{
- /** @var AMQPConnection $serverConnection */
- $serverConnection = $this->app['alchemy_worker.amqp.connection'];
-
/** @var WorkerRunningJobRepository $repoWorker */
$repoWorker = $app['repo.worker-running-job'];
@@ -39,9 +42,10 @@ class AdminConfigurationController extends Controller
$workerRunningJob = $repoWorker->findByStatus($filterStatus);
return $this->render('admin/worker-manager/index.html.twig', [
- 'isConnected' => ($serverConnection->getChannel() != null) ? true : false,
+ 'isConnected' => $this->getAMQPConnection()->getChannel() != null,
'workerRunningJob' => $workerRunningJob,
- 'reload' => false
+ 'reload' => false,
+ '_fragment' => $request->get('_fragment') ?? 'worker-configuration',
]);
}
@@ -52,26 +56,54 @@ class AdminConfigurationController extends Controller
*/
public function configurationAction(PhraseaApplication $app, Request $request)
{
- $retryQueueConfig = $this->getRetryQueueConfiguration();
+ $AMQPConnection = $this->getAMQPConnection();
- $form = $app->form(new WorkerConfigurationType(), $retryQueueConfig);
+ $conf = ['queues' => $this->getConf()->get(['workers', 'queues'], [])];
+ // ttl's are saved in conf in ms, display in form as sec.
+ foreach($conf['queues'] as $qname => $settings) {
+ foreach ($settings as $k=>$v) {
+ if(in_array($k, [AMQPConnection::TTL_RETRY, AMQPConnection::TTL_DELAYED])) {
+ $conf['queues'][$qname][$k] /= 1000.0;
+ }
+ }
+ }
+ $form = $app->form(new WorkerConfigurationType($AMQPConnection), $conf);
$form->handleRequest($request);
if ($form->isValid()) {
- // save config in file
- $app['conf']->set(['workers', 'retry_queue'], $form->getData());
+ // save config
+ // too bad we must remove null entries from data to not save in conf
+ $_data = $form->getData();
+ $data = $conf['queues']; // we will save a patched conf (not only data) so custom settings will be preserved
+ foreach($_data['queues'] as $qname => $settings) {
+ $data[$qname] = [];
+ foreach ($settings as $k=>$v) {
+ if(!is_null($v)) { // ignore null values from form
+ if(in_array($k, [AMQPConnection::TTL_RETRY, AMQPConnection::TTL_DELAYED])) {
+ $v = (int)(1000 * (float)$v);
+ }
+ $data[$qname][$k] = $v;
+ }
+ }
+ }
+ ksort($data);
+ $app['conf']->set(['workers', 'queues'], $data);
+ /*
+ * todo : reinitialize q can't depend on form content :
+ * e.g. if a ttl_retry is blank in form, the value should go back to default, so the q should be reinit.
+ *
$queues = array_intersect_key(AMQPConnection::$defaultQueues, $retryQueueConfig);
$retryQueuesToReset = array_intersect_key(AMQPConnection::$defaultRetryQueues, array_flip($queues));
- /** @var AMQPConnection $serverConnection */
- $serverConnection = $this->app['alchemy_worker.amqp.connection'];
// change the queue TTL
- $serverConnection->reinitializeQueue($retryQueuesToReset);
- $serverConnection->reinitializeQueue(AMQPConnection::$defaultDelayedQueues);
+ $AMQPConnection->reinitializeQueue($retryQueuesToReset);
+ $AMQPConnection->reinitializeQueue(AMQPConnection::$defaultDelayedQueues);
+ */
- return $app->redirectPath('worker_admin');
+ // too bad : _fragment does not work with our old url generator... it will be passed as plain url parameter
+ return $app->redirectPath('worker_admin', ['_fragment'=>'worker-configuration']);
}
return $this->render('admin/worker-manager/worker_configuration.html.twig', [
@@ -84,7 +116,7 @@ class AdminConfigurationController extends Controller
/** @var WorkerRunningJobRepository $repoWorker */
$repoWorker = $app['repo.worker-running-job'];
- $reload = ($request->query->get('reload')) == 1 ? true : false ;
+ $reload = ($request->query->get('reload') == 1);
$workerRunningJob = [];
$filterStatus = [];
@@ -114,8 +146,8 @@ class AdminConfigurationController extends Controller
/**
* @param Request $request
* @param $workerId
- * @return \Symfony\Component\HttpFoundation\JsonResponse
- * @throws \Doctrine\ORM\OptimisticLockException
+ * @return JsonResponse
+ * @throws OptimisticLockException
*/
public function changeStatusAction(Request $request, $workerId)
{
@@ -140,13 +172,11 @@ class AdminConfigurationController extends Controller
public function queueMonitorAction(PhraseaApplication $app, Request $request)
{
- $reload = ($request->query->get('reload')) == 1 ? true : false ;
+ $reload = ($request->query->get('reload') == 1);
- /** @var AMQPConnection $serverConnection */
- $serverConnection = $app['alchemy_worker.amqp.connection'];
- $serverConnection->getChannel();
- $serverConnection->declareExchange();
- $queuesStatus = $serverConnection->getQueuesStatus();
+ $this->getAMQPConnection()->getChannel();
+ $this->getAMQPConnection()->declareExchange();
+ $queuesStatus = $this->getAMQPConnection()->getQueuesStatus();
return $this->render('admin/worker-manager/worker_queue_monitor.html.twig', [
'queuesStatus' => $queuesStatus,
@@ -162,10 +192,20 @@ class AdminConfigurationController extends Controller
return $this->app->json(['success' => false]);
}
- /** @var AMQPConnection $serverConnection */
- $serverConnection = $this->app['alchemy_worker.amqp.connection'];
+ $this->getAMQPConnection()->reinitializeQueue([$queueName]);
- $serverConnection->reinitializeQueue([$queueName]);
+ return $this->app->json(['success' => true]);
+ }
+
+ public function deleteQueueAction(PhraseaApplication $app, Request $request)
+ {
+ $queueName = $request->request->get('queueName');
+
+ if (empty($queueName)) {
+ return $this->app->json(['success' => false]);
+ }
+
+ $this->getAMQPConnection()->deleteQueue($queueName);
return $this->app->json(['success' => true]);
}
@@ -176,7 +216,8 @@ class AdminConfigurationController extends Controller
$repoWorker = $app['repo.worker-running-job'];
$repoWorker->truncateWorkerTable();
- return $app->redirectPath('worker_admin');
+ // too bad : _fragment does not work with our old url generator... it will be passed as plain url parameter
+ return $app->redirectPath('worker_admin', ['_fragment'=>'worker-info']);
}
public function deleteFinishedAction(PhraseaApplication $app)
@@ -185,7 +226,8 @@ class AdminConfigurationController extends Controller
$repoWorker = $app['repo.worker-running-job'];
$repoWorker->deleteFinishedWorks();
- return $app->redirectPath('worker_admin');
+ // too bad : _fragment does not work with our old url generator... it will be passed as plain url parameter
+ return $app->redirectPath('worker_admin', ['_fragment'=>'worker-info']);
}
public function searchengineAction(PhraseaApplication $app, Request $request)
@@ -201,7 +243,8 @@ class AdminConfigurationController extends Controller
$this->getDispatcher()->dispatch(WorkerEvents::POPULATE_INDEX, new PopulateIndexEvent($populateInfo));
- return $app->redirectPath('worker_admin');
+ // too bad : _fragment does not work with our old url generator... it will be passed as plain url parameter
+ return $app->redirectPath('worker_admin', ['_fragment'=>'worker-searchengine']);
}
return $this->render('admin/worker-manager/worker_searchengine.html.twig', [
@@ -211,14 +254,12 @@ class AdminConfigurationController extends Controller
public function subviewAction()
{
- return $this->render('admin/worker-manager/worker_subview.html.twig', [
- ]);
+ return $this->render('admin/worker-manager/worker_subview.html.twig', [ ]);
}
public function metadataAction()
{
- return $this->render('admin/worker-manager/worker_metadata.html.twig', [
- ]);
+ return $this->render('admin/worker-manager/worker_metadata.html.twig', [ ]);
}
public function ftpAction(PhraseaApplication $app, Request $request)
@@ -231,7 +272,8 @@ class AdminConfigurationController extends Controller
// save new ftp config
$app['conf']->set(['workers', 'ftp'], array_merge($ftpConfig, $form->getData()));
- return $app->redirectPath('worker_admin');
+ // too bad : _fragment does not work with our old url generator... it will be passed as plain url parameter
+ return $app->redirectPath('worker_admin', ['_fragment'=>'worker-ftp']);
}
return $this->render('admin/worker-manager/worker_ftp.html.twig', [
@@ -241,26 +283,60 @@ class AdminConfigurationController extends Controller
public function validationReminderAction(PhraseaApplication $app, Request $request)
{
- $interval = $app['conf']->get(['workers', 'validationReminder', 'interval'], 7200);
+ // nb : the "interval" for a loop-q is the ttl.
+ // so the setting is stored into the "queues" settings in conf.
+ // here only the "ttl_retry" can be set/changed in conf
+ $config = $this->getConf()->get(['workers', 'queues', MessagePublisher::VALIDATION_REMINDER_TYPE], []);
+ if(isset($config['ttl_retry'])) {
+ // all settings are in msec, but into the form we want large numbers in sec.
+ $config['ttl_retry'] /= 1000;
+ }
+ /** @var Form $form */
+ $form = $app->form(new WorkerValidationReminderType($this->getAMQPConnection()), $config);
- if ($request->getMethod() == 'POST') {
- $reminderInterval = (int)$request->request->get('worker_reminder_interval');
+ $form->handleRequest($request);
+ if ($form->isSubmitted() && $form->isValid()) {
+ $data = $form->getData();
+ switch($data['act']) {
+ case 'save' : // save the form content (settings)
+ unset($data['act']); // don't save this
+ // the interval was displayed in sec. in form, convert back to msec
+ if(isset($data['ttl_retry'])) {
+ $data['ttl_retry'] *= 1000;
+ }
+ $data = array_merge($config, $data);
+ $app['conf']->set(['workers', 'queues', MessagePublisher::VALIDATION_REMINDER_TYPE], $data);
+ $this->getAMQPConnection()->reinitializeQueue([MessagePublisher::VALIDATION_REMINDER_TYPE]);
+ break;
+ case 'start':
+ // reinitialize the validation reminder queues
+ $this->getAMQPConnection()->setQueue(MessagePublisher::VALIDATION_REMINDER_TYPE);
+ $this->getAMQPConnection()->reinitializeQueue([MessagePublisher::VALIDATION_REMINDER_TYPE]);
+ $this->getMessagePublisher()->initializeLoopQueue(MessagePublisher::VALIDATION_REMINDER_TYPE);
+ break;
+ case 'stop':
+ $this->getAMQPConnection()->reinitializeQueue([MessagePublisher::VALIDATION_REMINDER_TYPE]);
+ break;
+ }
- /** @var AMQPConnection $serverConnection */
- $serverConnection = $this->app['alchemy_worker.amqp.connection'];
- $serverConnection->setQueue(MessagePublisher::VALIDATION_REMINDER_QUEUE);
-
- // save the period interval in second
- $app['conf']->set(['workers', 'validationReminder', 'interval'], $reminderInterval);
- // reinitialize the validation reminder queues
- $serverConnection->reinitializeQueue([MessagePublisher::VALIDATION_REMINDER_QUEUE]);
- $this->app['alchemy_worker.message.publisher']->initializeLoopQueue(MessagePublisher::VALIDATION_REMINDER_TYPE);
-
- return $app->redirectPath('worker_admin');
+ // too bad : _fragment does not work with our old url generator... it will be passed as plain url parameter
+ return $app->redirectPath('worker_admin', ['_fragment'=>'worker-reminder']);
}
+ // guess if the q is "running" = check if there are pending message on Q or loop-Q
+ $running = false;
+ $qStatuses = $this->getAMQPConnection()->getQueuesStatus();
+ foreach([
+ MessagePublisher::VALIDATION_REMINDER_TYPE,
+ $this->getAMQPConnection()->getLoopQueueName(MessagePublisher::VALIDATION_REMINDER_TYPE)
+ ] as $qName) {
+ if(isset($qStatuses[$qName]) && $qStatuses[$qName]['messageCount'] > 0) {
+ $running = true;
+ }
+ }
return $this->render('admin/worker-manager/worker_validation_reminder.html.twig', [
- 'interval' => $interval
+ 'form' => $form->createView(),
+ 'running' => $running
]);
}
@@ -276,30 +352,74 @@ class AdminConfigurationController extends Controller
public function pullAssetsAction(PhraseaApplication $app, Request $request)
{
- $pullAssetsConfig = $this->getPullAssetsConfiguration();
- $form = $app->form(new WorkerPullAssetsType(), $pullAssetsConfig);
+ $config = $this->getConf()->get(['workers', 'pull_assets'], []);
+ // the "pullInterval" comes from the ttl_retry
+ $ttl_retry = $this->getConf()->get(['workers','queues', MessagePublisher::PULL_ASSETS_TYPE, 'ttl_retry'], null);
+ if(!is_null($ttl_retry)) {
+ $ttl_retry /= 1000; // form is in sec
+ }
+ $config['pullInterval'] = $ttl_retry;
+
+ $form = $app->form(new WorkerPullAssetsType(), $config);
$form->handleRequest($request);
- if ($form->isValid()) {
- /** @var AMQPConnection $serverConnection */
- $serverConnection = $this->app['alchemy_worker.amqp.connection'];
- $serverConnection->setQueue(MessagePublisher::PULL_QUEUE);
+ if ($form->isSubmitted() && $form->isValid()) {
- // save new pull config
- $app['conf']->set(['workers', 'pull_assets'], array_merge($pullAssetsConfig, $form->getData()));
+ $data = $form->getData();
+ switch($data['act']) {
+ case 'save' : // save the form content (settings) in 2 places
+ $ttl_retry = $data['pullInterval'];
+ unset($data['act'], $data['pullInterval'], $config['pullInterval']);
+ // save most data under workers/pull_assets
+ $app['conf']->set(['workers', 'pull_assets'], array_merge($config, $data));
+ // save ttl in the q settings
+ if(!is_null($ttl_retry)) {
+ $this->getConf()->set(['workers','queues', MessagePublisher::PULL_ASSETS_TYPE, 'ttl_retry'], 1000 * (int)$ttl_retry);
+ }
+ $this->getAMQPConnection()->reinitializeQueue([MessagePublisher::PULL_ASSETS_TYPE]);
+ break;
+ case 'start':
+ // reinitialize the validation reminder queues
+ $this->getAMQPConnection()->setQueue(MessagePublisher::PULL_ASSETS_TYPE);
+ $this->getAMQPConnection()->reinitializeQueue([MessagePublisher::PULL_ASSETS_TYPE]);
+ $this->getMessagePublisher()->initializeLoopQueue(MessagePublisher::PULL_ASSETS_TYPE);
+ break;
+ case 'stop':
+ $this->getAMQPConnection()->reinitializeQueue([MessagePublisher::PULL_ASSETS_TYPE]);
+ break;
+ }
- // reinitialize the pull queues
- $serverConnection->reinitializeQueue([MessagePublisher::PULL_QUEUE]);
- $this->app['alchemy_worker.message.publisher']->initializeLoopQueue(MessagePublisher::PULL_ASSETS_TYPE);
-
- return $app->redirectPath('worker_admin');
+ // too bad : _fragment does not work with our old url generator... it will be passed as plain url parameter
+ return $app->redirectPath('worker_admin', ['_fragment'=>'worker-pull-assets']);
}
+ // guess if the q is "running" = check if there are pending message on Q or loop-Q
+ $running = false;
+ $qStatuses = $this->getAMQPConnection()->getQueuesStatus();
+ foreach([
+ MessagePublisher::PULL_ASSETS_TYPE,
+ $this->getAMQPConnection()->getLoopQueueName(MessagePublisher::PULL_ASSETS_TYPE)
+ ] as $qName) {
+ if(isset($qStatuses[$qName]) && $qStatuses[$qName]['messageCount'] > 0) {
+ $running = true;
+ }
+ }
return $this->render('admin/worker-manager/worker_pull_assets.html.twig', [
- 'form' => $form->createView()
+ 'form' => $form->createView(),
+ 'running' => $running
]);
}
+
+
+ /**
+ * @return MessagePublisher
+ */
+ private function getMessagePublisher()
+ {
+ return $this->app['alchemy_worker.message.publisher'];
+ }
+
/**
* @return EventDispatcherInterface
*/
@@ -333,18 +453,25 @@ class AdminConfigurationController extends Controller
return $data;
}
- private function getPullAssetsConfiguration()
- {
- return $this->app['conf']->get(['workers', 'pull_assets'], []);
- }
-
private function getFtpConfiguration()
{
- return $this->app['conf']->get(['workers', 'ftp'], []);
+ return $this->getConf()->get(['workers', 'ftp'], []);
}
- private function getRetryQueueConfiguration()
+ /**
+ * @return AMQPConnection
+ */
+ private function getAMQPConnection()
{
- return $this->app['conf']->get(['workers', 'retry_queue'], []);
+ return $this->app['alchemy_worker.amqp.connection'];
}
+
+ /**
+ * @return UrlGeneratorInterface
+ */
+ private function getUrlGenerator()
+ {
+ return $this->app['url_generator'];
+ }
+
}
diff --git a/lib/Alchemy/Phrasea/WorkerManager/Event/AssetsCreationFailureEvent.php b/lib/Alchemy/Phrasea/WorkerManager/Event/AssetsCreationFailureEvent.php
index 2e26d250e3..50fd34290a 100644
--- a/lib/Alchemy/Phrasea/WorkerManager/Event/AssetsCreationFailureEvent.php
+++ b/lib/Alchemy/Phrasea/WorkerManager/Event/AssetsCreationFailureEvent.php
@@ -10,7 +10,7 @@ class AssetsCreationFailureEvent extends SfEvent
private $workerMessage;
private $count;
- public function __construct($payload, $workerMessage, $count = 2)
+ public function __construct($payload, $workerMessage, $count)
{
$this->payload = $payload;
$this->workerMessage = $workerMessage;
diff --git a/lib/Alchemy/Phrasea/WorkerManager/Event/AssetsCreationRecordFailureEvent.php b/lib/Alchemy/Phrasea/WorkerManager/Event/AssetsCreationRecordFailureEvent.php
index bccf447317..c8a12aff32 100644
--- a/lib/Alchemy/Phrasea/WorkerManager/Event/AssetsCreationRecordFailureEvent.php
+++ b/lib/Alchemy/Phrasea/WorkerManager/Event/AssetsCreationRecordFailureEvent.php
@@ -12,7 +12,7 @@ class AssetsCreationRecordFailureEvent extends SfEvent
private $count;
private $workerJobId;
- public function __construct($payload, $workerMessage = '', $count = 2, $workerJobId = 0)
+ public function __construct($payload, $workerMessage, $count, $workerJobId )
{
$this->payload = $payload;
$this->workerMessage = $workerMessage;
diff --git a/lib/Alchemy/Phrasea/WorkerManager/Event/ExportMailFailureEvent.php b/lib/Alchemy/Phrasea/WorkerManager/Event/ExportMailFailureEvent.php
index 30b03a011a..31b0f66e6d 100644
--- a/lib/Alchemy/Phrasea/WorkerManager/Event/ExportMailFailureEvent.php
+++ b/lib/Alchemy/Phrasea/WorkerManager/Event/ExportMailFailureEvent.php
@@ -13,7 +13,7 @@ class ExportMailFailureEvent extends SfEvent
private $workerMessage;
private $count;
- public function __construct($emitterUserId, $tokenValue, $destinationMails, $params, $workerMessage = '', $count = 2)
+ public function __construct($emitterUserId, $tokenValue, $destinationMails, $params, $workerMessage, $count)
{
$this->emitterUserId = $emitterUserId;
$this->tokenValue = $tokenValue;
diff --git a/lib/Alchemy/Phrasea/WorkerManager/Event/PopulateIndexFailureEvent.php b/lib/Alchemy/Phrasea/WorkerManager/Event/PopulateIndexFailureEvent.php
index 7f9305773a..832c9d2ead 100644
--- a/lib/Alchemy/Phrasea/WorkerManager/Event/PopulateIndexFailureEvent.php
+++ b/lib/Alchemy/Phrasea/WorkerManager/Event/PopulateIndexFailureEvent.php
@@ -14,7 +14,7 @@ class PopulateIndexFailureEvent extends SfEvent
private $count;
private $workerJobId;
- public function __construct($host, $port, $indexName, $databoxId, $workerMessage = '', $count = 2, $workerJobId = 0)
+ public function __construct($host, $port, $indexName, $databoxId, $workerMessage, $count, $workerJobId)
{
$this->host = $host;
$this->port = $port;
diff --git a/lib/Alchemy/Phrasea/WorkerManager/Event/SubdefinitionCreationFailureEvent.php b/lib/Alchemy/Phrasea/WorkerManager/Event/SubdefinitionCreationFailureEvent.php
index 16401d24c3..c1a12cf3f9 100644
--- a/lib/Alchemy/Phrasea/WorkerManager/Event/SubdefinitionCreationFailureEvent.php
+++ b/lib/Alchemy/Phrasea/WorkerManager/Event/SubdefinitionCreationFailureEvent.php
@@ -12,7 +12,7 @@ class SubdefinitionCreationFailureEvent extends RecordEvent
private $count;
private $workerJobId;
- public function __construct(RecordInterface $record, $subdefName, $workerMessage = '', $count = 2, $workerJobId = 0)
+ public function __construct(RecordInterface $record, $subdefName, $workerMessage, $count, $workerJobId)
{
parent::__construct($record);
diff --git a/lib/Alchemy/Phrasea/WorkerManager/Event/WebhookDeliverFailureEvent.php b/lib/Alchemy/Phrasea/WorkerManager/Event/WebhookDeliverFailureEvent.php
index f31790cad3..4bcc4050ed 100644
--- a/lib/Alchemy/Phrasea/WorkerManager/Event/WebhookDeliverFailureEvent.php
+++ b/lib/Alchemy/Phrasea/WorkerManager/Event/WebhookDeliverFailureEvent.php
@@ -11,7 +11,7 @@ class WebhookDeliverFailureEvent extends SfEvent
private $count;
private $deleveryId;
- public function __construct($webhookEventId, $workerMessage, $count = 2, $deleveryId = null)
+ public function __construct($webhookEventId, $workerMessage, $count, $deleveryId = null)
{
$this->webhookEventId = $webhookEventId;
$this->workerMessage = $workerMessage;
diff --git a/lib/Alchemy/Phrasea/WorkerManager/Form/QueueSettingsType.php b/lib/Alchemy/Phrasea/WorkerManager/Form/QueueSettingsType.php
new file mode 100644
index 0000000000..1271582c0a
--- /dev/null
+++ b/lib/Alchemy/Phrasea/WorkerManager/Form/QueueSettingsType.php
@@ -0,0 +1,68 @@
+AMQPConnection = $AMQPConnection;
+ $this->baseQueueName = $baseQueueName;
+ }
+
+ public function buildForm(FormBuilderInterface $builder, array $options)
+ {
+ parent::buildForm($builder, $options);
+
+ $builder->add('n_workers', HiddenType::class, [
+ 'label' => 'admin::workermanager:tab:workerconfig:n_workers',
+ 'required' => false,
+ 'attr' => [
+ 'placeholder' => 1
+ ]
+ ]);
+ if($this->AMQPConnection->hasRetryQueue($this->baseQueueName) || $this->AMQPConnection->hasLoopQueue($this->baseQueueName)) {
+ $builder
+ ->add('max_retry', IntegerType::class, [
+ 'label' => 'admin::workermanager:tab:workerconfig:max retry',
+ 'required' => false,
+ 'attr' => [
+ 'placeholder' => $this->AMQPConnection->getDefaultSetting($this->baseQueueName, AMQPConnection::MAX_RETRY),
+ //'class'=>'col'
+ ]
+ ])
+ ->add('ttl_retry', IntegerType::class, [
+ 'label' => 'admin::workermanager:tab:workerconfig:retry delay in seconds',
+ 'required' => false,
+ 'attr' => [
+ 'placeholder' => $this->AMQPConnection->getDefaultSetting($this->baseQueueName, AMQPConnection::TTL_RETRY) / 1000.0,
+ //'class'=>'col'
+ ]
+ ]);
+ }
+ if($this->AMQPConnection->hasDelayedQueue($this->baseQueueName)) {
+ $builder->add('ttl_delayed', IntegerType::class, [
+ 'label' => 'admin::workermanager:tab:workerconfig:delayed delay in seconds',
+ 'required' => false,
+ 'attr' => [
+ 'placeholder' => $this->AMQPConnection->getDefaultSetting($this->baseQueueName, AMQPConnection::TTL_DELAYED) / 1000.0,
+ //'class'=>'col'
+ ]
+ ]);
+ }
+ }
+
+ public function getName()
+ {
+ return 'queue_settings';
+ }
+}
diff --git a/lib/Alchemy/Phrasea/WorkerManager/Form/WorkerConfigurationType.php b/lib/Alchemy/Phrasea/WorkerManager/Form/WorkerConfigurationType.php
index 170cccd6fb..7682183ba3 100644
--- a/lib/Alchemy/Phrasea/WorkerManager/Form/WorkerConfigurationType.php
+++ b/lib/Alchemy/Phrasea/WorkerManager/Form/WorkerConfigurationType.php
@@ -2,48 +2,43 @@
namespace Alchemy\Phrasea\WorkerManager\Form;
-use Alchemy\Phrasea\WorkerManager\Queue\MessagePublisher;
+use Alchemy\Phrasea\WorkerManager\Queue\AMQPConnection;
use Symfony\Component\Form\AbstractType;
+use Symfony\Component\Form\Extension\Core\Type\FormType;
+use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormBuilderInterface;
class WorkerConfigurationType extends AbstractType
{
+ private $AMQPConnection;
+
+ public function __construct(AMQPConnection $AMQPConnection)
+ {
+ $this->AMQPConnection = $AMQPConnection;
+ }
+
public function buildForm(FormBuilderInterface $builder, array $options)
{
parent::buildForm($builder, $options);
- $builder
- ->add(MessagePublisher::ASSETS_INGEST_TYPE, 'text', [
- 'label' => 'admin::workermanager:tab:workerconfig: Ingest retry delay in ms'
- ])
- ->add(MessagePublisher::CREATE_RECORD_TYPE, 'text', [
- 'label' => 'admin::workermanager:tab:workerconfig: Create record retry delay in ms'
- ])
- ->add(MessagePublisher::SUBDEF_CREATION_TYPE, 'text', [
- 'label' => 'admin::workermanager:tab:workerconfig: Subdefinition retry delay in ms'
- ])
- ->add(MessagePublisher::WRITE_METADATAS_TYPE, 'text', [
- 'label' => 'admin::workermanager:tab:workerconfig: Metadatas retry delay in ms'
- ])
- ->add(MessagePublisher::WEBHOOK_TYPE, 'text', [
- 'label' => 'admin::workermanager:tab:workerconfig: Webhook retry delay in ms'
- ])
- ->add(MessagePublisher::EXPORT_MAIL_TYPE, 'text', [
- 'label' => 'admin::workermanager:tab:workerconfig: Export mail retry delay in ms'
- ])
- ->add(MessagePublisher::POPULATE_INDEX_TYPE, 'text', [
- 'label' => 'admin::workermanager:tab:workerconfig: Populate Index retry delay in ms'
- ])
- ->add(MessagePublisher::FTP_TYPE, 'text', [
- 'label' => 'admin::workermanager:tab:workerconfig: Ftp retry delay in ms (default 3 min)'
- ])
- ->add('delayedSubdef', 'text', [
- 'label' => 'admin::workermanager:tab:workerconfig: Subdef delay in ms'
- ])
- ->add('delayedWriteMeta', 'text', [
- 'label' => 'admin::workermanager:tab:workerconfig: Write meta delay in ms'
- ])
- ;
+ $g = $builder->create("queues", FormType::class, ['attr'=>['class'=>'form-row']]);
+
+ foreach($this->AMQPConnection->getBaseQueueNames() as $baseQueueName) {
+ if($this->AMQPConnection->hasRetryQueue($baseQueueName)
+ || $this->AMQPConnection->hasLoopQueue($baseQueueName)
+ || $this->AMQPConnection->hasDelayedQueue($baseQueueName)
+ ) {
+ $f = new QueueSettingsType($this->AMQPConnection, $baseQueueName);
+ $g->add($baseQueueName, $f, ['attr' => ['class' => 'norow'], 'block_name' => 'queue']);
+ }
+ }
+
+ $builder->add($g);
+
+ $builder->add("boutton::appliquer", SubmitType::class,
+ [
+ 'label' => "boutton::appliquer"
+ ]);
}
public function getName()
diff --git a/lib/Alchemy/Phrasea/WorkerManager/Form/WorkerFtpType.php b/lib/Alchemy/Phrasea/WorkerManager/Form/WorkerFtpType.php
index a0998a7494..e50d30307c 100644
--- a/lib/Alchemy/Phrasea/WorkerManager/Form/WorkerFtpType.php
+++ b/lib/Alchemy/Phrasea/WorkerManager/Form/WorkerFtpType.php
@@ -3,6 +3,7 @@
namespace Alchemy\Phrasea\WorkerManager\Form;
use Symfony\Component\Form\AbstractType;
+use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
class WorkerFtpType extends AbstractType
@@ -12,19 +13,19 @@ class WorkerFtpType extends AbstractType
parent::buildForm($builder, $options);
$builder
- ->add('proxy', 'text', [
+ ->add('proxy', TextType::class, [
'label' => 'admin::workermanager:tab:ftp: Proxy',
'required' => false
])
- ->add('proxyPort', 'text', [
+ ->add('proxyPort', TextType::class, [
'label' => 'admin::workermanager:tab:ftp: Proxy port',
'required' => false
])
- ->add('proxyUser', 'text', [
+ ->add('proxyUser', TextType::class, [
'label' => 'admin::workermanager:tab:ftp: Proxy user',
'required' => false
])
- ->add('proxyPassword', 'text', [
+ ->add('proxyPassword', TextType::class, [
'label' => 'admin::workermanager:tab:ftp: Proxy password',
'required' => false
])
diff --git a/lib/Alchemy/Phrasea/WorkerManager/Form/WorkerPullAssetsType.php b/lib/Alchemy/Phrasea/WorkerManager/Form/WorkerPullAssetsType.php
index 2054e24288..579a3d06b4 100644
--- a/lib/Alchemy/Phrasea/WorkerManager/Form/WorkerPullAssetsType.php
+++ b/lib/Alchemy/Phrasea/WorkerManager/Form/WorkerPullAssetsType.php
@@ -3,6 +3,9 @@
namespace Alchemy\Phrasea\WorkerManager\Form;
use Symfony\Component\Form\AbstractType;
+use Symfony\Component\Form\Extension\Core\Type\HiddenType;
+use Symfony\Component\Form\Extension\Core\Type\SubmitType;
+use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
class WorkerPullAssetsType extends AbstractType
@@ -11,20 +14,36 @@ class WorkerPullAssetsType extends AbstractType
{
parent::buildForm($builder, $options);
+ // because this form will have 3 submit buttons - to use the same route -, this "act" field
+ // will reflect the value of the clicked button (js)
+ // !!! tried: using symfony "getClickedButton()" does to NOT work (submit button values seems not sent in request ?)
$builder
- ->add('UploaderApiBaseUri', 'text', [
+ ->add('act', HiddenType::class, [
+ 'attr' => [
+ 'class' => 'act'
+ ]
+ ]);
+
+ $builder
+ ->add('UploaderApiBaseUri', TextType::class, [
'label' => 'admin::workermanager:tab:pullassets: Uploader api base uri'
])
- ->add('clientSecret', 'text', [
+ ->add('clientSecret', TextType::class, [
'label' => 'admin::workermanager:tab:pullassets: Client secret'
])
- ->add('clientId', 'text', [
+ ->add('clientId', TextType::class, [
'label' => 'admin::workermanager:tab:pullassets: Client ID'
])
- ->add('pullInterval', 'text', [
+ ->add('pullInterval', TextType::class, [
'label' => 'admin::workermanager:tab:pullassets: Fetching interval in second'
- ])
- ;
+ ]);
+
+ $builder
+ ->add("boutton::appliquer", SubmitType::class, [
+ 'label' => "boutton::appliquer",
+ 'attr' => ['value' => 'save']
+ ]);
+
}
public function getName()
diff --git a/lib/Alchemy/Phrasea/WorkerManager/Form/WorkerSearchengineType.php b/lib/Alchemy/Phrasea/WorkerManager/Form/WorkerSearchengineType.php
index 2f86bdda7a..66d1178bba 100644
--- a/lib/Alchemy/Phrasea/WorkerManager/Form/WorkerSearchengineType.php
+++ b/lib/Alchemy/Phrasea/WorkerManager/Form/WorkerSearchengineType.php
@@ -3,6 +3,8 @@
namespace Alchemy\Phrasea\WorkerManager\Form;
use Symfony\Component\Form\AbstractType;
+use Symfony\Component\Form\Extension\Core\Type\IntegerType;
+use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Validator\Constraints\NotBlank;
@@ -15,18 +17,18 @@ class WorkerSearchengineType extends AbstractType
parent::buildForm($builder, $options);
$builder
- ->add('host', 'text', [
+ ->add('host', TextType::class, [
'label' => 'admin::workermanager:tab:searchengine: Elasticsearch server host',
'constraints' => new NotBlank(),
])
- ->add('port', 'integer', [
+ ->add('port', IntegerType::class, [
'label' => 'admin::workermanager:tab:searchengine: Elasticsearch service port',
'constraints' => [
new Range(['min' => 1, 'max' => 65535]),
new NotBlank()
]
])
- ->add('indexName', 'text', [
+ ->add('indexName', TextType::class, [
'label' => 'admin::workermanager:tab:searchengine: Elasticsearch index name',
'constraints' => new NotBlank(),
'attr' =>['data-class'=>'inline']
diff --git a/lib/Alchemy/Phrasea/WorkerManager/Form/WorkerValidationReminderType.php b/lib/Alchemy/Phrasea/WorkerManager/Form/WorkerValidationReminderType.php
new file mode 100644
index 0000000000..0e6789db64
--- /dev/null
+++ b/lib/Alchemy/Phrasea/WorkerManager/Form/WorkerValidationReminderType.php
@@ -0,0 +1,68 @@
+AMQPConnection = $AMQPConnection;
+ }
+
+ public function buildForm(FormBuilderInterface $builder, array $options)
+ {
+ parent::buildForm($builder, $options);
+
+ // because this form will have 3 submit buttons - to use the same route -, this "act" field
+ // will reflect the value of the clicked button (js)
+ // !!! tried: using symfony "getClickedButton()" does to NOT work (submit button values seems not sent in request ?)
+ $builder
+ ->add('act', HiddenType::class, [
+ 'attr' => [
+ 'class' => 'act'
+ ]
+ ]);
+
+ // every ttl is in msec, we display this large one (loop q) in sec in form.
+ $defaultInterval = $this->AMQPConnection->getDefaultSetting(MessagePublisher::VALIDATION_REMINDER_TYPE, AMQPConnection::TTL_RETRY) / 1000;
+ $builder
+ ->add('ttl_retry', TextType::class, [
+ 'label' => 'admin::workermanager:tab:Reminder: Interval in second',
+ 'attr' => [
+ 'placeholder' => $defaultInterval
+ ]
+ ]);
+ $builder
+ ->add("boutton::appliquer", SubmitType::class, [
+ 'label' => "boutton::appliquer",
+ 'attr' => ['value' => 'save']
+ ]);
+/*
+ $builder
+ ->add("submit", ButtonType::class, [
+ 'label' => "start",
+// 'data' => 'truc',
+// 'empty_data' => 'machin',
+ 'attr'=>[
+ 'value' => 'start',
+ 'name' => 'zobi'
+ ]
+ ]);
+*/
+ }
+
+// public function getName()
+// {
+// return 'worker_pullAssets';
+// }
+}
diff --git a/lib/Alchemy/Phrasea/WorkerManager/Provider/ControllerServiceProvider.php b/lib/Alchemy/Phrasea/WorkerManager/Provider/ControllerServiceProvider.php
index a53aa5e91d..8d51a0368d 100644
--- a/lib/Alchemy/Phrasea/WorkerManager/Provider/ControllerServiceProvider.php
+++ b/lib/Alchemy/Phrasea/WorkerManager/Provider/ControllerServiceProvider.php
@@ -45,61 +45,81 @@ class ControllerServiceProvider implements ControllerProviderInterface, ServiceP
$firewall->requireRight(\ACL::TASKMANAGER);
});
+ /** @uses AdminConfigurationController::indexAction */
$controllers->match('/', 'controller.worker.admin.configuration:indexAction')
->method('GET')
->bind('worker_admin');
+ /** @uses AdminConfigurationController::configurationAction */
$controllers->match('/configuration', 'controller.worker.admin.configuration:configurationAction')
->method('GET|POST')
->bind('worker_admin_configuration');
+ /** @uses AdminConfigurationController::infoAction */
$controllers->match('/info', 'controller.worker.admin.configuration:infoAction')
->method('GET')
->bind('worker_admin_info');
+ /** @uses AdminConfigurationController::truncateTableAction */
$controllers->match('/truncate', 'controller.worker.admin.configuration:truncateTableAction')
->method('POST')
->bind('worker_admin_truncate');
+ /** @uses AdminConfigurationController::deleteFinishedAction */
$controllers->match('/delete-finished', 'controller.worker.admin.configuration:deleteFinishedAction')
->method('POST')
->bind('worker_admin_delete_finished');
+ /** @uses AdminConfigurationController::searchengineAction */
$controllers->match('/searchengine', 'controller.worker.admin.configuration:searchengineAction')
->method('GET|POST')
->bind('worker_admin_searchengine');
+ /** @uses AdminConfigurationController::subviewAction */
$controllers->match('/subview', 'controller.worker.admin.configuration:subviewAction')
->method('GET|POST')
->bind('worker_admin_subview');
+ /** @uses AdminConfigurationController::metadataAction */
$controllers->match('/metadata', 'controller.worker.admin.configuration:metadataAction')
->method('GET|POST')
->bind('worker_admin_metadata');
+ /** @uses AdminConfigurationController::ftpAction */
$controllers->match('/ftp', 'controller.worker.admin.configuration:ftpAction')
->method('GET|POST')
->bind('worker_admin_ftp');
+ /** @uses AdminConfigurationController::populateStatusAction */
$controllers->get('/populate-status', 'controller.worker.admin.configuration:populateStatusAction')
->bind('worker_admin_populate_status');
+ /** @uses AdminConfigurationController::pullAssetsAction */
$controllers->match('/pull-assets', 'controller.worker.admin.configuration:pullAssetsAction')
->method('GET|POST')
->bind('worker_admin_pullAssets');
+ /** @uses AdminConfigurationController::validationReminderAction */
$controllers->match('/validation-reminder', 'controller.worker.admin.configuration:validationReminderAction')
->method('GET|POST')
->bind('worker_admin_validationReminder');
+ /** @uses AdminConfigurationController::queueMonitorAction */
$controllers->match('/queue-monitor', 'controller.worker.admin.configuration:queueMonitorAction')
->method('GET')
->bind('worker_admin_queue_monitor');
+ /** @uses AdminConfigurationController::purgeQueueAction */
$controllers->match('/purge-queue', 'controller.worker.admin.configuration:purgeQueueAction')
->method('POST')
->bind('worker_admin_purge_queue');
+ /** @uses AdminConfigurationController::deleteQueueAction */
+ $controllers->match('/delete-queue', 'controller.worker.admin.configuration:deleteQueueAction')
+ ->method('POST')
+ ->bind('worker_admin_delete_queue');
+
+ /** @uses AdminConfigurationController::changeStatusAction */
$controllers->match('/{workerId}/change-status', 'controller.worker.admin.configuration:changeStatusAction')
->method('POST')
->assert('workerId', '\d+')
diff --git a/lib/Alchemy/Phrasea/WorkerManager/Queue/AMQPConnection.php b/lib/Alchemy/Phrasea/WorkerManager/Queue/AMQPConnection.php
index a56a6e9380..fc784f4095 100644
--- a/lib/Alchemy/Phrasea/WorkerManager/Queue/AMQPConnection.php
+++ b/lib/Alchemy/Phrasea/WorkerManager/Queue/AMQPConnection.php
@@ -3,6 +3,7 @@
namespace Alchemy\Phrasea\WorkerManager\Queue;
use Alchemy\Phrasea\Core\Configuration\PropertyAccess;
+use Exception;
use PhpAmqpLib\Channel\AMQPChannel;
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Wire\AMQPTable;
@@ -20,67 +21,109 @@ class AMQPConnection
private $hostConfig;
private $conf;
- public static $defaultQueues = [
- MessagePublisher::WRITE_METADATAS_TYPE => MessagePublisher::METADATAS_QUEUE,
- MessagePublisher::SUBDEF_CREATION_TYPE => MessagePublisher::SUBDEF_QUEUE,
- MessagePublisher::EXPORT_MAIL_TYPE => MessagePublisher::EXPORT_QUEUE,
- MessagePublisher::WEBHOOK_TYPE => MessagePublisher::WEBHOOK_QUEUE,
- MessagePublisher::ASSETS_INGEST_TYPE => MessagePublisher::ASSETS_INGEST_QUEUE,
- MessagePublisher::CREATE_RECORD_TYPE => MessagePublisher::CREATE_RECORD_QUEUE,
- MessagePublisher::PULL_ASSETS_TYPE => MessagePublisher::PULL_QUEUE,
- MessagePublisher::POPULATE_INDEX_TYPE => MessagePublisher::POPULATE_INDEX_QUEUE,
- MessagePublisher::DELETE_RECORD_TYPE => MessagePublisher::DELETE_RECORD_QUEUE,
- MessagePublisher::MAIN_QUEUE_TYPE => MessagePublisher::MAIN_QUEUE,
- MessagePublisher::SUBTITLE_TYPE => MessagePublisher::SUBTITLE_QUEUE,
- MessagePublisher::FTP_TYPE => MessagePublisher::FTP_QUEUE,
- MessagePublisher::VALIDATION_REMINDER_TYPE => MessagePublisher::VALIDATION_REMINDER_QUEUE,
- MessagePublisher::EXPOSE_UPLOAD_TYPE => MessagePublisher::EXPOSE_UPLOAD_QUEUE,
- MessagePublisher::RECORD_EDIT_TYPE => MessagePublisher::RECORD_EDIT_QUEUE
- ];
-
- // the corresponding worker queues and retry queues, loop queue
- public static $defaultRetryQueues = [
- MessagePublisher::METADATAS_QUEUE => MessagePublisher::RETRY_METADATAS_QUEUE,
- MessagePublisher::SUBDEF_QUEUE => MessagePublisher::RETRY_SUBDEF_QUEUE,
- MessagePublisher::EXPORT_QUEUE => MessagePublisher::RETRY_EXPORT_QUEUE,
- MessagePublisher::WEBHOOK_QUEUE => MessagePublisher::RETRY_WEBHOOK_QUEUE,
- MessagePublisher::ASSETS_INGEST_QUEUE => MessagePublisher::RETRY_ASSETS_INGEST_QUEUE,
- MessagePublisher::CREATE_RECORD_QUEUE => MessagePublisher::RETRY_CREATE_RECORD_QUEUE,
- MessagePublisher::POPULATE_INDEX_QUEUE => MessagePublisher::RETRY_POPULATE_INDEX_QUEUE,
- MessagePublisher::PULL_QUEUE => MessagePublisher::LOOP_PULL_QUEUE,
- MessagePublisher::FTP_QUEUE => MessagePublisher::RETRY_FTP_QUEUE,
- MessagePublisher::VALIDATION_REMINDER_QUEUE => MessagePublisher::LOOP_VALIDATION_REMINDER_QUEUE
- ];
-
- public static $defaultFailedQueues = [
- MessagePublisher::WRITE_METADATAS_TYPE => MessagePublisher::FAILED_METADATAS_QUEUE,
- MessagePublisher::SUBDEF_CREATION_TYPE => MessagePublisher::FAILED_SUBDEF_QUEUE,
- MessagePublisher::EXPORT_MAIL_TYPE => MessagePublisher::FAILED_EXPORT_QUEUE,
- MessagePublisher::WEBHOOK_TYPE => MessagePublisher::FAILED_WEBHOOK_QUEUE,
- MessagePublisher::ASSETS_INGEST_TYPE => MessagePublisher::FAILED_ASSETS_INGEST_QUEUE,
- MessagePublisher::CREATE_RECORD_TYPE => MessagePublisher::FAILED_CREATE_RECORD_QUEUE,
- MessagePublisher::POPULATE_INDEX_TYPE => MessagePublisher::FAILED_POPULATE_INDEX_QUEUE,
- MessagePublisher::FTP_TYPE => MessagePublisher::FAILED_FTP_QUEUE
- ];
-
- public static $defaultDelayedQueues = [
- MessagePublisher::METADATAS_QUEUE => MessagePublisher::DELAYED_METADATAS_QUEUE,
- MessagePublisher::SUBDEF_QUEUE => MessagePublisher::DELAYED_SUBDEF_QUEUE
- ];
-
- public static $defaultLoopTypes = [
- MessagePublisher::PULL_ASSETS_TYPE,
- MessagePublisher::VALIDATION_REMINDER_TYPE
- ];
-
// default message TTL in retry queue in millisecond
- const RETRY_DELAY = 10000;
-
- // default message TTL for some retry queue , 3 minute
- const RETRY_LARGE_DELAY = 180000;
+ const DEFAULT_RETRY_DELAY_VALUE = 10000;
// default message TTL in delayed queue in millisecond
- const DELAY = 5000;
+ const DEFAULT_DELAYED_DELAY_VALUE = 5000;
+
+ // max number of retry before a message goes in failed
+ const DEFAULT_MAX_RETRY_VALUE = 3;
+
+ const WITH_NOTHING = 0;
+ const WITH_RETRY = 1;
+ const WITH_DELAYED = 2;
+ const WITH_LOOP = 4;
+
+ const BASE_QUEUE = 'base_q';
+ const BASE_QUEUE_WITH_RETRY = 'base_q_with_retry';
+ const BASE_QUEUE_WITH_LOOP = 'base_q_with_loop';
+ const RETRY_QUEUE = 'retry_q';
+ const LOOP_QUEUE = 'loop_q';
+ const FAILED_QUEUE = 'failed_q';
+ const DELAYED_QUEUE = 'delayed_q';
+
+ // settings names
+ const MAX_RETRY = 'max_retry';
+ const TTL_RETRY = 'ttl_retry';
+ const TTL_DELAYED = 'ttl_delayed';
+
+ const MESSAGES = [
+ MessagePublisher::ASSETS_INGEST_TYPE => [
+ 'with' => self::WITH_RETRY,
+ self::MAX_RETRY => self::DEFAULT_MAX_RETRY_VALUE,
+ self::TTL_RETRY => self::DEFAULT_RETRY_DELAY_VALUE,
+ ],
+ MessagePublisher::CREATE_RECORD_TYPE => [
+ 'with' => self::WITH_RETRY,
+ self::MAX_RETRY => self::DEFAULT_MAX_RETRY_VALUE,
+ self::TTL_RETRY => self::DEFAULT_RETRY_DELAY_VALUE,
+ ],
+ MessagePublisher::DELETE_RECORD_TYPE => [
+ 'with' => self::WITH_NOTHING,
+ self::MAX_RETRY => self::DEFAULT_MAX_RETRY_VALUE,
+ ],
+ MessagePublisher::EXPORT_MAIL_TYPE => [
+ 'with' => self::WITH_RETRY,
+ self::MAX_RETRY => self::DEFAULT_MAX_RETRY_VALUE,
+ self::TTL_RETRY => self::DEFAULT_RETRY_DELAY_VALUE,
+ ],
+ MessagePublisher::EXPOSE_UPLOAD_TYPE => [
+ 'with' => self::WITH_NOTHING,
+ self::MAX_RETRY => self::DEFAULT_MAX_RETRY_VALUE,
+ ],
+ MessagePublisher::FTP_TYPE => [
+ 'with' => self::WITH_RETRY,
+ self::MAX_RETRY => self::DEFAULT_MAX_RETRY_VALUE,
+ self::TTL_RETRY => 180 * 1000,
+ ],
+ MessagePublisher::MAIN_QUEUE_TYPE => [
+ 'with' => self::WITH_NOTHING,
+ self::MAX_RETRY => self::DEFAULT_MAX_RETRY_VALUE,
+ ],
+ MessagePublisher::POPULATE_INDEX_TYPE => [
+ 'with' => self::WITH_RETRY,
+ self::MAX_RETRY => self::DEFAULT_MAX_RETRY_VALUE,
+ self::TTL_RETRY => self::DEFAULT_RETRY_DELAY_VALUE,
+ ],
+ MessagePublisher::PULL_ASSETS_TYPE => [
+ 'with' => self::WITH_LOOP,
+ self::MAX_RETRY => self::DEFAULT_MAX_RETRY_VALUE,
+ self::TTL_RETRY => self::DEFAULT_RETRY_DELAY_VALUE,
+ ],
+ MessagePublisher::RECORD_EDIT_TYPE => [
+ 'with' => self::WITH_NOTHING,
+ self::MAX_RETRY => self::DEFAULT_MAX_RETRY_VALUE,
+ ],
+ MessagePublisher::SUBDEF_CREATION_TYPE => [
+ 'with' => self::WITH_RETRY | self::WITH_DELAYED,
+ self::MAX_RETRY => self::DEFAULT_MAX_RETRY_VALUE,
+ self::TTL_RETRY => self::DEFAULT_RETRY_DELAY_VALUE,
+ self::TTL_DELAYED => self::DEFAULT_DELAYED_DELAY_VALUE
+ ],
+ MessagePublisher::SUBTITLE_TYPE => [
+ 'with' => self::WITH_NOTHING,
+ self::MAX_RETRY => self::DEFAULT_MAX_RETRY_VALUE,
+ ],
+ MessagePublisher::VALIDATION_REMINDER_TYPE => [
+ 'with' => self::WITH_LOOP,
+ self::MAX_RETRY => self::DEFAULT_MAX_RETRY_VALUE,
+ self::TTL_RETRY => 7200 * 1000,
+ ],
+ MessagePublisher::WEBHOOK_TYPE => [
+ 'with' => self::WITH_RETRY,
+ self::MAX_RETRY => self::DEFAULT_MAX_RETRY_VALUE,
+ self::TTL_RETRY => self::DEFAULT_RETRY_DELAY_VALUE,
+ ],
+ MessagePublisher::WRITE_METADATAS_TYPE => [
+ 'with' => self::WITH_RETRY | self::WITH_DELAYED,
+ self::MAX_RETRY => self::DEFAULT_MAX_RETRY_VALUE,
+ self::TTL_RETRY => self::DEFAULT_RETRY_DELAY_VALUE,
+ self::TTL_DELAYED => self::DEFAULT_DELAYED_DELAY_VALUE
+ ],
+ ];
+
+ private $queues = []; // filled during construct, from msg list, default values and conf
public function __construct(PropertyAccess $conf)
{
@@ -94,6 +137,165 @@ class AMQPConnection
$this->hostConfig = $conf->get(['workers', 'queue', 'worker-queue'], $defaultConfiguration);
$this->conf = $conf;
+
+ // fill list of type attributes
+ foreach (self::MESSAGES as $name => $attr) {
+ $settings = $attr;
+ unset($settings['with']);
+ $this->queues[$name] = [
+ 'Name' => $name,
+ 'QType' => self::BASE_QUEUE,
+ 'default_settings' => $settings, // to be displayed as placeholder
+ 'settings' => $settings, // settings belongs only to base_q
+ 'Exchange' => self::ALCHEMY_EXCHANGE,
+ ];
+
+ // a q with retry can fail (after n retry) or loop
+ if($attr['with'] & self::WITH_RETRY) {
+ $this->queues[$name]['QType'] = self::BASE_QUEUE_WITH_RETRY; // todo : avoid changing qtype ?
+
+ // declare the retry q, cross-link with base q
+ $retry_name = $name . '_retry';
+ $this->queues[$name]['RetryQ'] = $retry_name; // link baseq to retryq
+ $this->queues[$retry_name] = [
+ 'Name' => $retry_name,
+ 'QType' => self::RETRY_QUEUE,
+ 'Exchange' => self::RETRY_ALCHEMY_EXCHANGE,
+ 'BaseQ' => $name, // link retryq back to baseq
+ ];
+
+ // declare the failed q, cross-link with base q
+ $failed_name = $name . '_failed';
+ $this->queues[$name]['FailedQ'] = $failed_name; // link baseq to failedq
+ $this->queues[$failed_name] = [
+ 'Name' => $failed_name,
+ 'QType' => self::FAILED_QUEUE,
+ 'Exchange' => self::RETRY_ALCHEMY_EXCHANGE,
+ 'BaseQ' => $name, // link failedq back to baseq
+ ];
+ }
+ // a q can be "delayed" to solve "work in progress" lock on records
+ if($attr['with'] & self::WITH_DELAYED) {
+ // declare the delayed q, cross-link with base q
+ $delayed_name = $name . '_delayed';
+ $this->queues[$name]['DelayedQ'] = $delayed_name; // link baseq to delayedq
+ $this->queues[$delayed_name] = [
+ 'Name' => $delayed_name,
+ 'QType' => self::DELAYED_QUEUE,
+ 'Exchange' => self::RETRY_ALCHEMY_EXCHANGE,
+ 'BaseQ' => $name, // link delayedq back to baseq
+ ];
+ }
+ if($attr['with'] & self::WITH_LOOP) {
+ $this->queues[$name]['QType'] = self::BASE_QUEUE_WITH_LOOP; // todo : avoid changing qtype ?
+
+ // declare the loop q, cross-link with base q
+ $loop_name = $name . '_loop';
+ $this->queues[$name]['LoopQ'] = $loop_name; // link baseq to loopq
+ $this->queues[$loop_name] = [
+ 'Name' => $loop_name,
+ 'QType' => self::LOOP_QUEUE,
+ 'Exchange' => self::RETRY_ALCHEMY_EXCHANGE,
+ 'BaseQ' => $name, // link loopq back to baseq
+ ];
+ }
+ }
+ // inject conf values
+ foreach($conf->get(['workers', 'queues'], []) as $name => $settings) {
+ if(!isset($this->queues[$name])) {
+ throw new Exception(sprintf('undefined queue "%s" in conf', $name));
+ }
+ $this->queues[$name]['settings'] = array_merge($this->queues[$name]['settings'], $settings);
+ }
+ }
+
+ public function getBaseQueueNames()
+ {
+ $keys = array_keys(self::MESSAGES);
+ asort($keys);
+ return $keys;
+ }
+
+ public function isBaseQueue(string $queueName)
+ {
+ return array_key_exists($queueName, self::MESSAGES);
+ }
+
+ public function getBaseQueueName(string $baseQueueName)
+ {
+ $q = $this->getQueue($baseQueueName);
+ return $q['Name'];
+ }
+
+ public function hasRetryQueue(string $baseQueueName)
+ {
+ $q = $this->getQueue($baseQueueName);
+ return array_key_exists('RetryQ', $q);
+ }
+
+ public function getRetryQueueName(string $baseQueueName)
+ {
+ $q = $this->getQueue($baseQueueName, 'RetryQ');
+ return $q['Name'];
+ }
+
+ public function getSetting(string $baseQueueName, string $settingName)
+ {
+ $q = $this->getQueue($baseQueueName);
+ return $q['settings'][$settingName];
+ }
+
+ public function getDefaultSetting(string $baseQueueName, string $settingName)
+ {
+ $q = $this->getQueue($baseQueueName);
+ return $q['default_settings'][$settingName];
+ }
+
+ public function hasDelayedQueue(string $baseQueueName)
+ {
+ $q = $this->getQueue($baseQueueName);
+ return array_key_exists('DelayedQ', $q);
+ }
+
+ public function getDelayedQueueName(string $baseQueueName)
+ {
+ $q = $this->getQueue($baseQueueName, 'DelayedQ');
+ return $q['Name'];
+ }
+
+ public function getFailedQueueName(string $baseQueueName)
+ {
+ $q = $this->getQueue($baseQueueName, 'FailedQ');
+ return $q['Name'];
+ }
+
+ public function hasLoopQueue(string $baseQueueName)
+ {
+ $q = $this->getQueue($baseQueueName);
+ return array_key_exists('LoopQ', $q);
+ }
+
+ public function getLoopQueueName(string $baseQueueName)
+ {
+ $q = $this->getQueue($baseQueueName, 'LoopQ');
+ return $q['Name'];
+ }
+
+ public function getExchange(string $queueName)
+ {
+ $q = $this->getQueue($queueName);
+ return $q['Exchange'];
+ }
+
+ private function getQueue(string $queueName, string $subQueueKey = null)
+ {
+ if(!array_key_exists($queueName, $this->queues)) {
+ throw new Exception(sprintf('undefined queue "%s"', $queueName));
+ }
+ if($subQueueKey && !array_key_exists($subQueueKey, $this->queues[$queueName])) {
+ throw new Exception(sprintf('base queue "%s" has no "%s"', $queueName, $subQueueKey));
+ }
+ return $subQueueKey ? $this->queues[$this->queues[$queueName][$subQueueKey]] : $this->queues[$queueName];
}
public function getConnection()
@@ -108,8 +310,9 @@ class AMQPConnection
$this->hostConfig['vhost']
);
- } catch (\Exception $e) {
-
+ }
+ catch (Exception $e) {
+ // no-op
}
}
@@ -127,7 +330,8 @@ class AMQPConnection
}
return null;
- } else {
+ }
+ else {
return $this->channel;
}
}
@@ -156,107 +360,192 @@ class AMQPConnection
$this->declareExchange();
}
- if (isset(self::$defaultRetryQueues[$queueName])) {
- $this->channel->queue_declare($queueName, false, true, false, false, false, new AMQPTable([
- 'x-dead-letter-exchange' => self::RETRY_ALCHEMY_EXCHANGE, // the exchange to which republish a 'dead' message
- 'x-dead-letter-routing-key' => self::$defaultRetryQueues[$queueName] // the routing key to apply to this 'dead' message
- ]));
-
- $this->channel->queue_bind($queueName, self::ALCHEMY_EXCHANGE, $queueName);
-
- // declare also the corresponding retry queue
- // use this to delay the delivery of a message to the alchemy-exchange
- $this->channel->queue_declare(self::$defaultRetryQueues[$queueName], false, true, false, false, false, new AMQPTable([
- 'x-dead-letter-exchange' => AMQPConnection::ALCHEMY_EXCHANGE,
- 'x-dead-letter-routing-key' => $queueName,
- 'x-message-ttl' => $this->getTtlRetryPerRouting($queueName)
- ]));
-
- $this->channel->queue_bind(self::$defaultRetryQueues[$queueName], AMQPConnection::RETRY_ALCHEMY_EXCHANGE, self::$defaultRetryQueues[$queueName]);
-
- } elseif (in_array($queueName, self::$defaultRetryQueues)) {
- // if it's a retry queue
- $routing = array_search($queueName, AMQPConnection::$defaultRetryQueues);
- $this->channel->queue_declare($queueName, false, true, false, false, false, new AMQPTable([
- 'x-dead-letter-exchange' => AMQPConnection::ALCHEMY_EXCHANGE,
- 'x-dead-letter-routing-key' => $routing,
- 'x-message-ttl' => $this->getTtlRetryPerRouting($routing)
- ]));
-
- $this->channel->queue_bind($queueName, AMQPConnection::RETRY_ALCHEMY_EXCHANGE, $queueName);
- } elseif (in_array($queueName, self::$defaultFailedQueues)) {
- // if it's a failed queue
- $this->channel->queue_declare($queueName, false, true, false, false, false);
-
- $this->channel->queue_bind($queueName, AMQPConnection::RETRY_ALCHEMY_EXCHANGE, $queueName);
- } elseif (in_array($queueName, self::$defaultDelayedQueues)) {
- // if it's a delayed queue
- $routing = array_search($queueName, AMQPConnection::$defaultDelayedQueues);
- $this->channel->queue_declare($queueName, false, true, false, false, false, new AMQPTable([
- 'x-dead-letter-exchange' => AMQPConnection::ALCHEMY_EXCHANGE,
- 'x-dead-letter-routing-key' => $routing,
- 'x-message-ttl' => $this->getTtlDelayedPerRouting($routing)
- ]));
-
- $this->channel->queue_bind($queueName, AMQPConnection::RETRY_ALCHEMY_EXCHANGE, $queueName);
- } else {
- $this->channel->queue_declare($queueName, false, true, false, false, false);
-
- $this->channel->queue_bind($queueName, AMQPConnection::ALCHEMY_EXCHANGE, $queueName);
+ $queue = $this->queues[$queueName];
+ switch($queue['QType']) {
+ case self::BASE_QUEUE_WITH_RETRY:
+ $this->queue_declare_and_bind($queueName, self::ALCHEMY_EXCHANGE, [
+ 'x-dead-letter-exchange' => self::RETRY_ALCHEMY_EXCHANGE, // the exchange to which republish a 'dead' message
+ 'x-dead-letter-routing-key' => $queue['RetryQ'] // the routing key to apply to this 'dead' message
+ ]);
+ $this->setQueue($queue['RetryQ']);
+ break;
+ case self::BASE_QUEUE_WITH_LOOP:
+ $this->queue_declare_and_bind($queueName, self::ALCHEMY_EXCHANGE, [
+ 'x-dead-letter-exchange' => self::RETRY_ALCHEMY_EXCHANGE, // the exchange to which republish a 'dead' message
+ 'x-dead-letter-routing-key' => $queue['LoopQ'] // the routing key to apply to this 'dead' message
+ ]);
+ $this->setQueue($queue['LoopQ']);
+ break;
+ case self::LOOP_QUEUE:
+ case self::RETRY_QUEUE:
+ $this->queue_declare_and_bind($queueName, self::RETRY_ALCHEMY_EXCHANGE, [
+ 'x-dead-letter-exchange' => self::ALCHEMY_EXCHANGE,
+ 'x-dead-letter-routing-key' => $queue['BaseQ'],
+ 'x-message-ttl' => (int)$this->queues[$queue['BaseQ']]['settings'][self::TTL_RETRY]
+ ]);
+ break;
+ case self::DELAYED_QUEUE:
+ $this->queue_declare_and_bind($queueName, self::RETRY_ALCHEMY_EXCHANGE, [
+ 'x-dead-letter-exchange' => self::ALCHEMY_EXCHANGE,
+ 'x-dead-letter-routing-key' => $queue['BaseQ'],
+ 'x-message-ttl' => (int)$this->queues[$queue['BaseQ']]['settings'][self::TTL_DELAYED]
+ ]);
+ break;
+ case self::FAILED_QUEUE:
+ $this->queue_declare_and_bind($queueName, self::RETRY_ALCHEMY_EXCHANGE);
+ break;
+ case self::BASE_QUEUE:
+ $this->queue_declare_and_bind($queueName, self::ALCHEMY_EXCHANGE);
+ break;
+ default:
+ throw new Exception(sprintf('undefined q type "%s', $queueName));
+ break;
}
return $this->channel;
}
- public function reinitializeQueue(array $queuNames)
+ private function queue_declare_and_bind(string $name, string $exchange, array $arguments = null)
+ {
+ try {
+ $this->channel->queue_declare(
+ $name,
+ false, true, false, false, false,
+ $arguments ? new AMQPTable($arguments) : null
+ );
+ $this->channel->queue_bind($name, $exchange, $name);
+ }
+ catch (Exception $e) {
+ // the q exists and arguments don't match, fallback.
+ // Happens when we try to get the number of messages (getQueueStatus)
+ // after the settings (e.g. ttl) was changed and the q was not yet re-created
+ $this->getConnection();
+ if (isset($this->connection)) {
+ $this->channel = $this->connection->channel();
+ }
+ $this->channel->queue_declare($name,true);
+ }
+ }
+
+ /**
+ * purge some queues, delete related retry-q
+ * nb: called by admin/purgeQueuAction, so a q may be __any kind__ - not only base-types !
+ *
+ * @param array $queueNames
+ * @throws Exception
+ */
+ public function reinitializeQueue(array $queueNames)
{
if (!isset($this->channel)) {
$this->getChannel();
$this->declareExchange();
}
- foreach ($queuNames as $queuName) {
- if (in_array($queuName, self::$defaultQueues)) {
- $this->channel->queue_purge($queuName);
- } else {
- $this->channel->queue_delete($queuName);
+
+ foreach ($queueNames as $queueName) {
+ // re-inject conf values (some may have changed)
+ $settings = $this->conf->get(['workers', 'queues', $queueName], []);
+ if(array_key_exists($queueName, $this->queues)) {
+ $this->queues[$queueName]['settings'] = array_merge($this->queues[$queueName]['settings'], $settings);
}
- if (isset(self::$defaultRetryQueues[$queuName])) {
- $this->channel->queue_delete(self::$defaultRetryQueues[$queuName]);
+ if(array_key_exists($queueName, self::MESSAGES)) {
+ // base-q
+ $this->purgeQueue($queueName);
+
+ if($this->hasRetryQueue($queueName)) {
+ $this->deleteQueue($this->getRetryQueueName($queueName));
+ }
+ if($this->hasLoopQueue($queueName)) {
+ $this->deleteQueue($this->getLoopQueueName($queueName));
+ }
+ }
+ else {
+ // retry, delayed, loop, ... q
+ $this->deleteQueue($queueName);
}
- $this->setQueue($queuName);
+ $this->setQueue($queueName);
+ }
+ }
+
+ /**
+ * delete a queue, fails silently if the q does not exists
+ *
+ * @param $queueName
+ */
+ public function deleteQueue($queueName)
+ {
+ if (!isset($this->channel)) {
+ $this->getChannel();
+ $this->declareExchange();
+ }
+ try {
+ $this->channel->queue_delete($queueName);
+ }
+ catch(Exception $e) {
+ // no-op
+ }
+ }
+
+ /**
+ * purge a queue, fails silently if the q does not exists
+ *
+ * @param $queueName
+ */
+ public function purgeQueue($queueName)
+ {
+ if (!isset($this->channel)) {
+ $this->getChannel();
+ $this->declareExchange();
+ }
+ try {
+ $this->channel->queue_purge($queueName);
+ }
+ catch(Exception $e) {
+ // no-op
}
}
/**
* Get queueName, messageCount, consumerCount of queues
* @return array
+ * @throws Exception
*/
public function getQueuesStatus()
{
- $queuesList = array_merge(
- array_values(self::$defaultQueues),
- array_values(self::$defaultDelayedQueues),
- array_values(self::$defaultRetryQueues),
- array_values(self::$defaultFailedQueues)
- );
-
$this->getChannel();
$queuesStatus = [];
- foreach ($queuesList as $queue) {
- $this->setQueue($queue);
- list($queueName, $messageCount, $consumerCount) = $this->channel->queue_declare($queue, true);
+ foreach($this->queues as $name => $queue) {
- $status['queueName'] = $queueName;
- $status['messageCount'] = $messageCount;
- $status['consumerCount'] = $consumerCount;
+ $this->setQueue($name); // todo : BASE_QUEUE_WITH_RETRY will set both BASE and RETRY Q, so we should skip one of 2
- $queuesStatus[] = $status;
- unset($status);
+ $this->getConnection();
+ if (isset($this->connection)) {
+ $this->channel = $this->connection->channel();
+ }
+ try {
+ list($queueName, $messageCount, $consumerCount) = $this->channel->queue_declare($name, true);
+ $queuesStatus[$queueName] = [
+ 'queueName' => $queueName,
+ 'exists' => true,
+ 'messageCount' => $messageCount,
+ 'consumerCount' => $consumerCount
+ ];
+ }
+ catch (Exception $e) {
+ // should not happen since "setQueue()" was called
+ $queuesStatus[$name] = [
+ 'queueName' => $name,
+ 'exists' => false,
+ 'messageCount' => -1,
+ 'consumerCount' => -1
+ ];
+ }
}
+ ksort($queuesStatus);
+
return $queuesStatus;
}
@@ -265,58 +554,4 @@ class AMQPConnection
$this->channel->close();
$this->connection->close();
}
-
- /**
- * @param $routing
- * @return int
- */
- private function getTtlRetryPerRouting($routing)
- {
- $config = $this->conf->get(['workers']);
-
- if ($routing == MessagePublisher::PULL_QUEUE &&
- isset($config['pull_assets']) &&
- isset($config['pull_assets']['pullInterval']) ) {
- // convert in milli second
- return (int)($config['pull_assets']['pullInterval']) * 1000;
- } elseif ($routing == MessagePublisher::VALIDATION_REMINDER_QUEUE) {
-
- if (isset($config['validationReminder']) &&
- isset($config['validationReminder']['interval'])) {
-
- // convert in milli second
- return (int)($config['validationReminder']['interval']) * 1000;
- }
-
- // default value to 2 hour if not set
- return (int) 7200 * 1000;
-
- } elseif (isset($config['retry_queue']) &&
- isset($config['retry_queue'][array_search($routing, AMQPConnection::$defaultQueues)])) {
-
- return (int)($config['retry_queue'][array_search($routing, AMQPConnection::$defaultQueues)]);
- }
-
- if ($routing == MessagePublisher::FTP_QUEUE) {
- return self::RETRY_LARGE_DELAY;
- } else {
- return self::RETRY_DELAY;
- }
- }
-
- private function getTtlDelayedPerRouting($routing)
- {
- $delayed = [
- MessagePublisher::METADATAS_QUEUE => 'delayedWriteMeta',
- MessagePublisher::SUBDEF_QUEUE => 'delayedSubdef'
- ];
-
- $config = $this->conf->get(['workers']);
-
- if (isset($config['retry_queue']) && isset($config['retry_queue'][$delayed[$routing]])) {
- return (int)$config['retry_queue'][$delayed[$routing]];
- }
-
- return self::DELAY;
- }
}
diff --git a/lib/Alchemy/Phrasea/WorkerManager/Queue/MessageHandler.php b/lib/Alchemy/Phrasea/WorkerManager/Queue/MessageHandler.php
index 55ee1914b4..bd62a20e42 100644
--- a/lib/Alchemy/Phrasea/WorkerManager/Queue/MessageHandler.php
+++ b/lib/Alchemy/Phrasea/WorkerManager/Queue/MessageHandler.php
@@ -4,6 +4,7 @@ namespace Alchemy\Phrasea\WorkerManager\Queue;
use Alchemy\Phrasea\WorkerManager\Worker\ProcessPool;
use Alchemy\Phrasea\WorkerManager\Worker\WorkerInvoker;
+use Exception;
use PhpAmqpLib\Channel\AMQPChannel;
use PhpAmqpLib\Message\AMQPMessage;
use PhpAmqpLib\Wire\AMQPTable;
@@ -11,8 +12,6 @@ use Ramsey\Uuid\Uuid;
class MessageHandler
{
- const MAX_OF_TRY = 3;
-
private $messagePublisher;
public function __construct(MessagePublisher $messagePublisher)
@@ -20,27 +19,37 @@ class MessageHandler
$this->messagePublisher = $messagePublisher;
}
- public function consume(AMQPConnection $serverConnection, WorkerInvoker $workerInvoker, $argQueueName, $maxProcesses)
+ /**
+ * called by WorkerExecuteCommand cli
+ *
+ * @param AMQPConnection $AMQPConnection
+ * @param WorkerInvoker $workerInvoker
+ * @param array|null $argQueueNames
+ * @param $maxProcesses
+ */
+ public function consume(AMQPConnection $AMQPConnection, WorkerInvoker $workerInvoker, $argQueueNames, $maxProcesses)
{
- $publisher = $this->messagePublisher;
- $channel = $serverConnection->getChannel();
+ $channel = $AMQPConnection->getChannel();
if ($channel == null) {
+ // todo : if there is no channel, can we push ?
$this->messagePublisher->pushLog("Can't connect to rabbit, check configuration!", "error");
return ;
}
- $serverConnection->declareExchange();
+ $AMQPConnection->declareExchange();
// define consume callbacks
- $callback = function (AMQPMessage $message) use ($channel, $workerInvoker, $publisher) {
+ $publisher = $this->messagePublisher;
+ $callback = function (AMQPMessage $message) use ($AMQPConnection, $channel, $workerInvoker, $publisher) {
$data = json_decode($message->getBody(), true);
$count = 0;
+ $headers = null;
if ($message->has('application_headers')) {
/** @var AMQPTable $headers */
$headers = $message->get('application_headers');
@@ -49,9 +58,10 @@ class MessageHandler
if (isset($headerData['x-death'])) {
$xDeathHeader = $headerData['x-death'];
+ // todo : if there are more than 1 xdeath ? what is $count ?
foreach ($xDeathHeader as $xdeath) {
$queue = $xdeath['queue'];
- if (!in_array($queue, AMQPConnection::$defaultQueues)) {
+ if (!$AMQPConnection->isBaseQueue($queue)) {
continue;
}
@@ -61,51 +71,45 @@ class MessageHandler
}
}
- // if message is yet executed 3 times, save the unprocessed message in the corresponding failed queues
- if ($count > self::MAX_OF_TRY && !in_array($data['message_type'], AMQPConnection::$defaultLoopTypes)) {
- $this->messagePublisher->publishFailedMessage($data['payload'], $headers, AMQPConnection::$defaultFailedQueues[$data['message_type']]);
+ $msgType = $data['message_type'];
- $logMessage = sprintf("Rabbit message executed 3 times, it's to be saved in %s , payload >>> %s",
- AMQPConnection::$defaultFailedQueues[$data['message_type']],
+ if($count > $AMQPConnection->getSetting($msgType, AMQPConnection::MAX_RETRY) && !$AMQPConnection->hasLoopQueue($msgType)) {
+ $publisher->publishFailedMessage($data['payload'], $headers, $data['message_type']);
+
+ $logMessage = sprintf("Rabbit message executed %s times, it's to be saved in %s , payload >>> %s",
+ $count,
+ $msgType,
json_encode($data['payload'])
);
- $this->messagePublisher->pushLog($logMessage);
+ $publisher->pushLog($logMessage);
$channel->basic_ack($message->delivery_info['delivery_tag']);
- } else {
+ }
+ else {
try {
- $workerInvoker->invokeWorker($data['message_type'], json_encode($data['payload']));
+ $workerInvoker->invokeWorker($msgType, json_encode($data['payload']));
- if (in_array($data['message_type'], AMQPConnection::$defaultLoopTypes)) {
+ if ($AMQPConnection->hasLoopQueue($msgType)) {
// make a loop for the loop type
$channel->basic_nack($message->delivery_info['delivery_tag']);
} else {
$channel->basic_ack($message->delivery_info['delivery_tag']);
}
- $oldPayload = $data['payload'];
- $message = $data['message_type'].' to be consumed! >> Payload ::'. json_encode($oldPayload);
-
- $publisher->pushLog($message);
- } catch (\Exception $e) {
+ $publisher->pushLog(
+ sprintf('"%s" to be consumed! >> Payload :: %s', $msgType, json_encode($data['payload']))
+ );
+ }
+ catch (Exception $e) {
$channel->basic_nack($message->delivery_info['delivery_tag']);
}
}
};
- $prefetchCount = ProcessPool::MAX_PROCESSES;
-
- if ($maxProcesses) {
- $prefetchCount = $maxProcesses;
- }
-
- foreach (AMQPConnection::$defaultQueues as $queueName) {
- if ($argQueueName ) {
- if (in_array($queueName, $argQueueName)) {
- $this->runConsumer($queueName, $serverConnection, $channel, $prefetchCount, $callback);
- }
- } else {
- $this->runConsumer($queueName, $serverConnection, $channel, $prefetchCount, $callback);
+ $prefetchCount = $maxProcesses ? $maxProcesses : ProcessPool::MAX_PROCESSES;
+ foreach($AMQPConnection->getBaseQueueNames() as $queueName) {
+ if (!$argQueueNames || in_array($queueName, $argQueueNames)) {
+ $this->runConsumer($queueName, $AMQPConnection, $channel, $prefetchCount, $callback);
}
}
}
@@ -114,9 +118,10 @@ class MessageHandler
{
$serverConnection->setQueue($queueName);
+ // todo : remove this if !!! move code to a generic place
// initialize validation reminder when starting consumer
- if ($queueName == MessagePublisher::VALIDATION_REMINDER_QUEUE) {
- $serverConnection->reinitializeQueue([MessagePublisher::VALIDATION_REMINDER_QUEUE]);
+ if ($queueName == MessagePublisher::VALIDATION_REMINDER_TYPE) {
+ $serverConnection->reinitializeQueue([MessagePublisher::VALIDATION_REMINDER_TYPE]);
$this->messagePublisher->initializeLoopQueue(MessagePublisher::VALIDATION_REMINDER_TYPE);
}
diff --git a/lib/Alchemy/Phrasea/WorkerManager/Queue/MessagePublisher.php b/lib/Alchemy/Phrasea/WorkerManager/Queue/MessagePublisher.php
index 7da797f630..d58a5a7711 100644
--- a/lib/Alchemy/Phrasea/WorkerManager/Queue/MessagePublisher.php
+++ b/lib/Alchemy/Phrasea/WorkerManager/Queue/MessagePublisher.php
@@ -2,6 +2,8 @@
namespace Alchemy\Phrasea\WorkerManager\Queue;
+use DateTime;
+use DateTimeZone;
use Monolog\Logger;
use PhpAmqpLib\Message\AMQPMessage;
use PhpAmqpLib\Wire\AMQPTable;
@@ -28,107 +30,96 @@ class MessagePublisher
const MAIN_QUEUE_TYPE = 'mainQueue';
- const MAIN_QUEUE = 'main-queue';
- const SUBTITLE_QUEUE = 'subtitle-queue';
- // ** ** \\
-
- // worker queue to be consumed, when no ack , it is requeued to the retry queue
- const ASSETS_INGEST_QUEUE = 'ingest-queue';
- const CREATE_RECORD_QUEUE = 'createrecord-queue';
- const DELETE_RECORD_QUEUE = 'deleterecord-queue';
- const EXPORT_QUEUE = 'export-queue';
- const EXPOSE_UPLOAD_QUEUE = 'exposeupload-queue';
- const FTP_QUEUE = 'ftp-queue';
- const METADATAS_QUEUE = 'metadatas-queue';
- const POPULATE_INDEX_QUEUE = 'populateindex-queue';
- const PULL_QUEUE = 'pull-queue';
- const RECORD_EDIT_QUEUE = 'recordedit-queue';
- const SUBDEF_QUEUE = 'subdef-queue';
- const VALIDATION_REMINDER_QUEUE = 'validationReminder-queue';
- const WEBHOOK_QUEUE = 'webhook-queue';
-
-
- // retry queue
- // we can use these retry queue with TTL, so when message expires it is requeued to the corresponding worker queue
- const RETRY_ASSETS_INGEST_QUEUE = 'retry-ingest-queue';
- const RETRY_CREATE_RECORD_QUEUE = 'retry-createrecord-queue';
- const RETRY_EXPORT_QUEUE = 'retry-export-queue';
- const RETRY_FTP_QUEUE = 'retry-ftp-queue';
- const RETRY_METADATAS_QUEUE = 'retry-metadatas-queue';
- const RETRY_POPULATE_INDEX_QUEUE = 'retry-populateindex-queue';
- const RETRY_SUBDEF_QUEUE = 'retry-subdef-queue';
- const RETRY_WEBHOOK_QUEUE = 'retry-webhook-queue';
-
- // use those queue to make a loop on a consumer
- const LOOP_PULL_QUEUE = 'loop-pull-queue';
- const LOOP_VALIDATION_REMINDER_QUEUE = 'loop-validationReminder-queue';
-
-
- // all failed queue, if message is treated over 3 times it goes to the failed queue
- const FAILED_ASSETS_INGEST_QUEUE = 'failed-ingest-queue';
- const FAILED_CREATE_RECORD_QUEUE = 'failed-createrecord-queue';
- const FAILED_EXPORT_QUEUE = 'failed-export-queue';
- const FAILED_FTP_QUEUE = 'failed-ftp-queue';
- const FAILED_METADATAS_QUEUE = 'failed-metadatas-queue';
- const FAILED_POPULATE_INDEX_QUEUE = 'failed-populateindex-queue';
- const FAILED_SUBDEF_QUEUE = 'failed-subdef-queue';
- const FAILED_WEBHOOK_QUEUE = 'failed-webhook-queue';
-
-
- // delayed queue when record is locked
- const DELAYED_SUBDEF_QUEUE = 'delayed-subdef-queue';
- const DELAYED_METADATAS_QUEUE = 'delayed-metadatas-queue';
-
const NEW_RECORD_MESSAGE = 'newrecord';
- /** @var AMQPConnection $serverConnection */
- private $serverConnection;
+ /** @var AMQPConnection $AMQPConnection */
+ private $AMQPConnection;
/** @var Logger */
private $logger;
- public function __construct(AMQPConnection $serverConnection, LoggerInterface $logger)
+ public function __construct(AMQPConnection $AMQPConnection, LoggerInterface $logger)
{
- $this->serverConnection = $serverConnection;
- $this->logger = $logger;
+ $this->AMQPConnection = $AMQPConnection;
+ $this->logger = $logger;
}
- public function publishMessage(array $payload, $queueName, $retryCount = null, $workerMessage = '')
+ public function publishMessage(array $payload, $queueName)
{
- // add published timestamp to all message payload
- $payload['payload']['published'] = time();
- $msg = new AMQPMessage(json_encode($payload));
- $routing = array_search($queueName, AMQPConnection::$defaultRetryQueues);
+ $this->AMQPConnection->getBaseQueueName($queueName); // just to throw an exception if q is undefined
- if (count($retryCount) && $routing != false) {
+ $this->_publishMessage($payload, $queueName);
+ }
+
+ public function publishRetryMessage(array $payload, string $baseQueueName, $retryCount, $workerMessage)
+ {
+ $retryQ = $this->AMQPConnection->getRetryQueueName($baseQueueName);
+
+ $headers = null;
+ if(!is_null($retryCount)) {
// add a message header information
$headers = new AMQPTable([
'x-death' => [
[
'count' => $retryCount,
'exchange' => AMQPConnection::ALCHEMY_EXCHANGE,
- 'queue' => $routing,
- 'routing-keys' => $routing,
+ 'queue' => $baseQueueName,
+ 'routing-keys' => $baseQueueName,
'reason' => 'rejected', // rejected is sended like nack
- 'time' => new \DateTime('now', new \DateTimeZone('UTC'))
+ 'time' => new DateTime('now', new DateTimeZone('UTC'))
]
],
'worker-message' => $workerMessage
]);
+ }
+ $this->_publishMessage($payload, $retryQ, $headers);
+ }
+ public function publishDelayedMessage(array $payload, string $baseQueueName)
+ {
+ $delayedQ = $this->AMQPConnection->getDelayedQueueName($baseQueueName);
+
+ $this->_publishMessage($payload, $delayedQ);
+ }
+
+ public function publishFailedMessage(array $payload, AMQPTable $headers, $baseQueueName)
+ {
+ $FailedQ = $this->AMQPConnection->getFailedQueueName($baseQueueName);
+
+ $msg = new AMQPMessage(json_encode($payload));
+ $msg->set('application_headers', $headers);
+
+ $channel = $this->AMQPConnection->setQueue($FailedQ);
+ if ($channel == null) {
+ $this->pushLog("Can't connect to rabbit, check configuration!", "error");
+
+ return ;
+ }
+
+ $channel->basic_publish($msg, AMQPConnection::RETRY_ALCHEMY_EXCHANGE, $FailedQ);
+
+ $this->_publishMessage($payload, $FailedQ, $headers);
+ }
+
+ private function _publishMessage(array $payload, $queueName, $headers = null)
+ {
+ // add published timestamp to all message payload
+ $payload['payload']['published'] = time();
+ $msg = new AMQPMessage(json_encode($payload));
+
+ if (!is_null($headers)) {
+ // add a message header information
$msg->set('application_headers', $headers);
}
- $channel = $this->serverConnection->setQueue($queueName);
-
- if ($channel == null) {
+ if (is_null( ($channel = $this->AMQPConnection->setQueue($queueName)) )) {
$this->pushLog("Can't connect to rabbit, check configuration!", "error");
return true;
}
- $exchange = in_array($queueName, AMQPConnection::$defaultQueues) ? AMQPConnection::ALCHEMY_EXCHANGE : AMQPConnection::RETRY_ALCHEMY_EXCHANGE;
+ $exchange = $this->AMQPConnection->getExchange($queueName); // in_array($queueName, AMQPConnection::$defaultQueues) ? AMQPConnection::ALCHEMY_EXCHANGE : AMQPConnection::RETRY_ALCHEMY_EXCHANGE;
$channel->basic_publish($msg, $exchange, $queueName);
return true;
@@ -139,16 +130,16 @@ class MessagePublisher
$payload = [
'message_type' => $type,
'payload' => [
- 'initTimestamp' => new \DateTime('now', new \DateTimeZone('UTC'))
+ 'initTimestamp' => new DateTime('now', new DateTimeZone('UTC'))
]
];
- $this->publishMessage($payload, AMQPConnection::$defaultQueues[$type]);
+ $this->publishMessage($payload, $type);
}
public function connectionClose()
{
- $this->serverConnection->connectionClose();
+ $this->AMQPConnection->connectionClose();
}
/**
@@ -163,18 +154,4 @@ class MessagePublisher
call_user_func(array($this->logger, $method), $message, $context);
}
- public function publishFailedMessage(array $payload, AMQPTable $headers, $queueName)
- {
- $msg = new AMQPMessage(json_encode($payload));
- $msg->set('application_headers', $headers);
-
- $channel = $this->serverConnection->setQueue($queueName);
- if ($channel == null) {
- $this->pushLog("Can't connect to rabbit, check configuration!", "error");
-
- return ;
- }
-
- $channel->basic_publish($msg, AMQPConnection::RETRY_ALCHEMY_EXCHANGE, $queueName);
- }
}
diff --git a/lib/Alchemy/Phrasea/WorkerManager/Queue/WebhookPublisher.php b/lib/Alchemy/Phrasea/WorkerManager/Queue/WebhookPublisher.php
index a1bdcc888a..f58ec84c75 100644
--- a/lib/Alchemy/Phrasea/WorkerManager/Queue/WebhookPublisher.php
+++ b/lib/Alchemy/Phrasea/WorkerManager/Queue/WebhookPublisher.php
@@ -24,6 +24,6 @@ class WebhookPublisher implements WebhookPublisherInterface
]
];
- $this->messagePublisher->publishMessage($payload, MessagePublisher::WEBHOOK_QUEUE);
+ $this->messagePublisher->publishMessage($payload, MessagePublisher::WEBHOOK_TYPE);
}
}
diff --git a/lib/Alchemy/Phrasea/WorkerManager/Subscriber/AssetsIngestSubscriber.php b/lib/Alchemy/Phrasea/WorkerManager/Subscriber/AssetsIngestSubscriber.php
index 07c37aa5fc..e6a211c564 100644
--- a/lib/Alchemy/Phrasea/WorkerManager/Subscriber/AssetsIngestSubscriber.php
+++ b/lib/Alchemy/Phrasea/WorkerManager/Subscriber/AssetsIngestSubscriber.php
@@ -33,7 +33,7 @@ class AssetsIngestSubscriber implements EventSubscriberInterface
'payload' => array_merge($event->getData(), ['type' => WorkerRunningJob::TYPE_PUSH])
];
- $this->messagePublisher->publishMessage($payload, MessagePublisher::ASSETS_INGEST_QUEUE);
+ $this->messagePublisher->publishMessage($payload, MessagePublisher::ASSETS_INGEST_TYPE);
}
public function onAssetsCreationFailure(AssetsCreationFailureEvent $event)
@@ -43,9 +43,9 @@ class AssetsIngestSubscriber implements EventSubscriberInterface
'payload' => $event->getPayload()
];
- $this->messagePublisher->publishMessage(
+ $this->messagePublisher->publishRetryMessage(
$payload,
- MessagePublisher::RETRY_ASSETS_INGEST_QUEUE,
+ MessagePublisher::ASSETS_INGEST_TYPE,
$event->getCount(),
$event->getWorkerMessage()
);
@@ -84,9 +84,9 @@ class AssetsIngestSubscriber implements EventSubscriberInterface
}
}
- $this->messagePublisher->publishMessage(
+ $this->messagePublisher->publishRetryMessage(
$payload,
- MessagePublisher::RETRY_CREATE_RECORD_QUEUE,
+ MessagePublisher::CREATE_RECORD_TYPE, // todo
$event->getCount(),
$event->getWorkerMessage()
);
diff --git a/lib/Alchemy/Phrasea/WorkerManager/Subscriber/ExportSubscriber.php b/lib/Alchemy/Phrasea/WorkerManager/Subscriber/ExportSubscriber.php
index 0bd7edfb9d..bbfde318bd 100644
--- a/lib/Alchemy/Phrasea/WorkerManager/Subscriber/ExportSubscriber.php
+++ b/lib/Alchemy/Phrasea/WorkerManager/Subscriber/ExportSubscriber.php
@@ -32,7 +32,7 @@ class ExportSubscriber implements EventSubscriberInterface
]
];
- $this->messagePublisher->publishMessage($payload, MessagePublisher::EXPORT_QUEUE);
+ $this->messagePublisher->publishMessage($payload, MessagePublisher::EXPORT_MAIL_TYPE);
}
public function onExportMailFailure(ExportMailFailureEvent $event)
@@ -47,9 +47,9 @@ class ExportSubscriber implements EventSubscriberInterface
]
];
- $this->messagePublisher->publishMessage(
+ $this->messagePublisher->publishRetryMessage(
$payload,
- MessagePublisher::RETRY_EXPORT_QUEUE,
+ MessagePublisher::EXPORT_MAIL_TYPE,
$event->getCount(),
$event->getWorkerMessage()
);
@@ -66,7 +66,7 @@ class ExportSubscriber implements EventSubscriberInterface
$this->messagePublisher->publishMessage(
$payload,
- MessagePublisher::FTP_QUEUE
+ MessagePublisher::FTP_TYPE
);
}
diff --git a/lib/Alchemy/Phrasea/WorkerManager/Subscriber/ExposeSubscriber.php b/lib/Alchemy/Phrasea/WorkerManager/Subscriber/ExposeSubscriber.php
index f4fed4d6be..44acd302ae 100644
--- a/lib/Alchemy/Phrasea/WorkerManager/Subscriber/ExposeSubscriber.php
+++ b/lib/Alchemy/Phrasea/WorkerManager/Subscriber/ExposeSubscriber.php
@@ -36,7 +36,7 @@ class ExposeSubscriber implements EventSubscriberInterface
]
];
- $this->messagePublisher->publishMessage($payload, MessagePublisher::EXPOSE_UPLOAD_QUEUE);
+ $this->messagePublisher->publishMessage($payload, MessagePublisher::EXPOSE_UPLOAD_TYPE);
}
}
diff --git a/lib/Alchemy/Phrasea/WorkerManager/Subscriber/RecordSubscriber.php b/lib/Alchemy/Phrasea/WorkerManager/Subscriber/RecordSubscriber.php
index 5d57699fa1..5de0ac80a9 100644
--- a/lib/Alchemy/Phrasea/WorkerManager/Subscriber/RecordSubscriber.php
+++ b/lib/Alchemy/Phrasea/WorkerManager/Subscriber/RecordSubscriber.php
@@ -5,7 +5,6 @@ namespace Alchemy\Phrasea\WorkerManager\Subscriber;
use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Core\Event\Record\DeletedEvent;
use Alchemy\Phrasea\Core\Event\Record\DeleteEvent;
-use Alchemy\Phrasea\Core\Event\Record\MetadataChangedEvent;
use Alchemy\Phrasea\Core\Event\Record\RecordEvent;
use Alchemy\Phrasea\Core\Event\Record\RecordEvents;
use Alchemy\Phrasea\Core\Event\Record\SubdefinitionCreateEvent;
@@ -22,6 +21,8 @@ use Alchemy\Phrasea\WorkerManager\Queue\MessagePublisher;
use Alchemy\Phrasea\WorkerManager\Worker\CreateRecordWorker;
use Alchemy\Phrasea\WorkerManager\Worker\Factory\WorkerFactoryInterface;
use Alchemy\Phrasea\WorkerManager\Worker\Resolver\TypeBasedWorkerResolver;
+use databox;
+use Exception;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class RecordSubscriber implements EventSubscriberInterface
@@ -67,7 +68,7 @@ class RecordSubscriber implements EventSubscriberInterface
]
];
- $this->messagePublisher->publishMessage($payload, MessagePublisher::SUBDEF_QUEUE);
+ $this->messagePublisher->publishMessage($payload, MessagePublisher::SUBDEF_CREATION_TYPE);
}
}
}
@@ -87,7 +88,7 @@ class RecordSubscriber implements EventSubscriberInterface
]
];
- $this->messagePublisher->publishMessage($payload, MessagePublisher::DELETE_RECORD_QUEUE);
+ $this->messagePublisher->publishMessage($payload, MessagePublisher::DELETE_RECORD_TYPE);
}
public function onSubdefinitionCreationFailure(SubdefinitionCreationFailureEvent $event)
@@ -123,14 +124,14 @@ class RecordSubscriber implements EventSubscriberInterface
$em->persist($workerRunningJob);
$em->flush();
$em->commit();
- } catch (\Exception $e) {
+ } catch (Exception $e) {
$em->rollback();
}
}
- $this->messagePublisher->publishMessage(
+ $this->messagePublisher->publishRetryMessage(
$payload,
- MessagePublisher::RETRY_SUBDEF_QUEUE,
+ MessagePublisher::SUBDEF_CREATION_TYPE,
$event->getCount(),
$event->getWorkerMessage()
);
@@ -170,18 +171,19 @@ class RecordSubscriber implements EventSubscriberInterface
];
if ($subdef->is_physically_present()) {
- $this->messagePublisher->publishMessage($payload, MessagePublisher::METADATAS_QUEUE);
- } else {
- $logMessage = sprintf("Subdef %s is not physically present! to be passed in the %s ! payload >>> %s",
+ $this->messagePublisher->publishMessage($payload, MessagePublisher::WRITE_METADATAS_TYPE);
+ }
+ else {
+ $logMessage = sprintf('Subdef "%s" is not physically present! to be passed in the retry q of "%s" ! payload >>> %s',
$subdef->get_name(),
- MessagePublisher::RETRY_METADATAS_QUEUE,
+ MessagePublisher::WRITE_METADATAS_TYPE,
json_encode($payload)
);
$this->messagePublisher->pushLog($logMessage);
- $this->messagePublisher->publishMessage(
+ $this->messagePublisher->publishRetryMessage(
$payload,
- MessagePublisher::RETRY_METADATAS_QUEUE,
+ MessagePublisher::WRITE_METADATAS_TYPE,
2,
'Subdef is not physically present!'
);
@@ -215,10 +217,10 @@ class RecordSubscriber implements EventSubscriberInterface
]
];
- $logMessage = sprintf("Subdef %s write meta failed, error : %s ! to be passed in the %s ! payload >>> %s",
+ $logMessage = sprintf('Subdef "%s" write meta failed, error : "%s" ! to be passed in the retry q of "%s" ! payload >>> %s',
$event->getSubdefName(),
$event->getWorkerMessage(),
- MessagePublisher::RETRY_METADATAS_QUEUE,
+ MessagePublisher::WRITE_METADATAS_TYPE,
json_encode($payload)
);
$this->messagePublisher->pushLog($logMessage);
@@ -243,14 +245,14 @@ class RecordSubscriber implements EventSubscriberInterface
$em->persist($workerRunningJob);
$em->flush();
$em->commit();
- } catch (\Exception $e) {
+ } catch (Exception $e) {
$em->rollback();
}
}
- $this->messagePublisher->publishMessage(
+ $this->messagePublisher->publishRetryMessage(
$payload,
- MessagePublisher::RETRY_METADATAS_QUEUE,
+ MessagePublisher::WRITE_METADATAS_TYPE,
$event->getCount(),
$event->getWorkerMessage()
);
@@ -276,7 +278,7 @@ class RecordSubscriber implements EventSubscriberInterface
]
];
- $this->messagePublisher->publishMessage($payload, MessagePublisher::METADATAS_QUEUE);
+ $this->messagePublisher->publishMessage($payload, MessagePublisher::WRITE_METADATAS_TYPE);
}
}
@@ -294,19 +296,27 @@ class RecordSubscriber implements EventSubscriberInterface
]
];
- $this->messagePublisher->publishMessage($payload, MessagePublisher::RECORD_EDIT_QUEUE);
+ $this->messagePublisher->publishMessage($payload, MessagePublisher::RECORD_EDIT_TYPE);
}
public static function getSubscribedEvents()
{
return [
+ /** @uses onRecordCreated */
RecordEvents::CREATED => 'onRecordCreated',
+ /** @uses onSubdefinitionCreate */
RecordEvents::SUBDEFINITION_CREATE => 'onSubdefinitionCreate',
+ /** @uses onDelete */
RecordEvents::DELETE => 'onDelete',
+ /** @uses onSubdefinitionCreationFailure */
WorkerEvents::SUBDEFINITION_CREATION_FAILURE => 'onSubdefinitionCreationFailure',
+ /** @uses onRecordsWriteMeta */
WorkerEvents::RECORDS_WRITE_META => 'onRecordsWriteMeta',
+ /** @uses onStoryCreateCover */
WorkerEvents::STORY_CREATE_COVER => 'onStoryCreateCover',
+ /** @uses onSubdefinitionWritemeta */
WorkerEvents::SUBDEFINITION_WRITE_META => 'onSubdefinitionWritemeta',
+ /** @uses onRecordEditInWorker */
WorkerEvents::RECORD_EDIT_IN_WORKER => 'onRecordEditInWorker'
];
}
@@ -322,12 +332,12 @@ class RecordSubscriber implements EventSubscriberInterface
}
/**
- * @param \databox $databox
+ * @param databox $databox
* @param string $subdefType
* @param string $subdefName
* @return bool
*/
- private function isSubdefMetadataUpdateRequired(\databox $databox, $subdefType, $subdefName)
+ private function isSubdefMetadataUpdateRequired(databox $databox, $subdefType, $subdefName)
{
if ($databox->get_subdef_structure()->hasSubdef($subdefType, $subdefName)) {
return $databox->get_subdef_structure()->get_subdef($subdefType, $subdefName)->isMetadataUpdateRequired();
diff --git a/lib/Alchemy/Phrasea/WorkerManager/Subscriber/SearchengineSubscriber.php b/lib/Alchemy/Phrasea/WorkerManager/Subscriber/SearchengineSubscriber.php
index b5bd748f2c..d6e92163ef 100644
--- a/lib/Alchemy/Phrasea/WorkerManager/Subscriber/SearchengineSubscriber.php
+++ b/lib/Alchemy/Phrasea/WorkerManager/Subscriber/SearchengineSubscriber.php
@@ -40,7 +40,7 @@ class SearchengineSubscriber implements EventSubscriberInterface
]
];
- $this->messagePublisher->publishMessage($payload, MessagePublisher::POPULATE_INDEX_QUEUE);
+ $this->messagePublisher->publishMessage($payload, MessagePublisher::POPULATE_INDEX_TYPE);
}
}
@@ -83,9 +83,9 @@ class SearchengineSubscriber implements EventSubscriberInterface
}
}
- $this->messagePublisher->publishMessage(
+ $this->messagePublisher->publishRetryMessage(
$payload,
- MessagePublisher::RETRY_POPULATE_INDEX_QUEUE,
+ MessagePublisher::POPULATE_INDEX_TYPE,
$event->getCount(),
$event->getWorkerMessage()
);
diff --git a/lib/Alchemy/Phrasea/WorkerManager/Subscriber/SubtitleSubscriber.php b/lib/Alchemy/Phrasea/WorkerManager/Subscriber/SubtitleSubscriber.php
index e67958165c..aab98ccebb 100644
--- a/lib/Alchemy/Phrasea/WorkerManager/Subscriber/SubtitleSubscriber.php
+++ b/lib/Alchemy/Phrasea/WorkerManager/Subscriber/SubtitleSubscriber.php
@@ -65,7 +65,7 @@ class SubtitleSubscriber implements EventSubscriberInterface
'payload' => $data
];
- $this->messagePublisher->publishMessage($payload, MessagePublisher::MAIN_QUEUE);
+ $this->messagePublisher->publishMessage($payload, MessagePublisher::MAIN_QUEUE_TYPE);
} catch (\Exception $e) {
$em->rollback();
}
diff --git a/lib/Alchemy/Phrasea/WorkerManager/Subscriber/WebhookSubscriber.php b/lib/Alchemy/Phrasea/WorkerManager/Subscriber/WebhookSubscriber.php
index eb45da3a37..414a3c5ac0 100644
--- a/lib/Alchemy/Phrasea/WorkerManager/Subscriber/WebhookSubscriber.php
+++ b/lib/Alchemy/Phrasea/WorkerManager/Subscriber/WebhookSubscriber.php
@@ -29,9 +29,9 @@ class WebhookSubscriber implements EventSubscriberInterface
]
];
- $this->messagePublisher->publishMessage(
+ $this->messagePublisher->publishRetryMessage(
$payload,
- MessagePublisher::RETRY_WEBHOOK_QUEUE,
+ MessagePublisher::WEBHOOK_TYPE,
$event->getCount(),
$event->getWorkerMessage()
);
diff --git a/lib/Alchemy/Phrasea/WorkerManager/Worker/AssetsIngestWorker.php b/lib/Alchemy/Phrasea/WorkerManager/Worker/AssetsIngestWorker.php
index 4a46d8461c..e688a70ebe 100644
--- a/lib/Alchemy/Phrasea/WorkerManager/Worker/AssetsIngestWorker.php
+++ b/lib/Alchemy/Phrasea/WorkerManager/Worker/AssetsIngestWorker.php
@@ -2,8 +2,8 @@
namespace Alchemy\Phrasea\WorkerManager\Worker;
-use Alchemy\Phrasea\Application\Helper\EntityManagerAware;
use Alchemy\Phrasea\Application as PhraseaApplication;
+use Alchemy\Phrasea\Application\Helper\EntityManagerAware;
use Alchemy\Phrasea\Model\Entities\StoryWZ;
use Alchemy\Phrasea\Model\Entities\WorkerRunningJob;
use Alchemy\Phrasea\Model\Repositories\UserRepository;
@@ -80,7 +80,7 @@ class AssetsIngestWorker implements WorkerInterface
'commit_id' => $payload['commit_id']
];
- $this->messagePublisher->publishMessage($createRecordMessage, MessagePublisher::CREATE_RECORD_QUEUE);
+ $this->messagePublisher->publishMessage($createRecordMessage, MessagePublisher::CREATE_RECORD_TYPE);
/** @var WorkerRunningJob $workerRunningJob */
$workerRunningJob = $this->repoWorkerJob->findOneBy([
diff --git a/lib/Alchemy/Phrasea/WorkerManager/Worker/FtpWorker.php b/lib/Alchemy/Phrasea/WorkerManager/Worker/FtpWorker.php
index 3814e026ec..e849eadd1d 100644
--- a/lib/Alchemy/Phrasea/WorkerManager/Worker/FtpWorker.php
+++ b/lib/Alchemy/Phrasea/WorkerManager/Worker/FtpWorker.php
@@ -5,7 +5,6 @@ namespace Alchemy\Phrasea\WorkerManager\Worker;
use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Application\Helper\NotifierAware;
use Alchemy\Phrasea\Core\LazyLocator;
-use Alchemy\Phrasea\Exception\InvalidArgumentException;
use Alchemy\Phrasea\Model\Entities\FtpExport;
use Alchemy\Phrasea\Model\Entities\FtpExportElement;
use Alchemy\Phrasea\Model\Entities\WorkerRunningJob;
@@ -371,9 +370,9 @@ class FtpWorker implements WorkerInterface
'payload' => $payload
];
- $this->app['alchemy_worker.message.publisher']->publishMessage(
+ $this->getMessagePublisher()->publishRetryMessage(
$fullPayload,
- MessagePublisher::RETRY_FTP_QUEUE,
+ MessagePublisher::FTP_TYPE,
$count,
$workerMessage
);
@@ -503,4 +502,13 @@ class FtpWorker implements WorkerInterface
{
return $this->app['repo.ftp-exports'];
}
+
+ /**
+ * @return MessagePublisher
+ */
+ private function getMessagePublisher()
+ {
+ return $this->app['alchemy_worker.message.publisher'];
+ }
+
}
diff --git a/lib/Alchemy/Phrasea/WorkerManager/Worker/MainQueueWorker.php b/lib/Alchemy/Phrasea/WorkerManager/Worker/MainQueueWorker.php
index 82471f2b88..3448758cc7 100644
--- a/lib/Alchemy/Phrasea/WorkerManager/Worker/MainQueueWorker.php
+++ b/lib/Alchemy/Phrasea/WorkerManager/Worker/MainQueueWorker.php
@@ -29,7 +29,7 @@ class MainQueueWorker implements WorkerInterface
switch ($payload['type']) {
case MessagePublisher::SUBTITLE_TYPE:
- $queue = MessagePublisher::SUBTITLE_QUEUE;
+ $queue = MessagePublisher::SUBTITLE_TYPE;
$messageType = $payload['type'];
unset($payload['type']);
diff --git a/lib/Alchemy/Phrasea/WorkerManager/Worker/PullAssetsWorker.php b/lib/Alchemy/Phrasea/WorkerManager/Worker/PullAssetsWorker.php
index fe83f5845c..9334c2e86c 100644
--- a/lib/Alchemy/Phrasea/WorkerManager/Worker/PullAssetsWorker.php
+++ b/lib/Alchemy/Phrasea/WorkerManager/Worker/PullAssetsWorker.php
@@ -82,7 +82,7 @@ class PullAssetsWorker implements WorkerInterface
]
];
- $this->messagePublisher->publishMessage($payload, MessagePublisher::ASSETS_INGEST_QUEUE);
+ $this->messagePublisher->publishMessage($payload, MessagePublisher::ASSETS_INGEST_TYPE);
}
}
diff --git a/lib/Alchemy/Phrasea/WorkerManager/Worker/SubdefCreationWorker.php b/lib/Alchemy/Phrasea/WorkerManager/Worker/SubdefCreationWorker.php
index 6de0cb6228..12dc1cfcd9 100644
--- a/lib/Alchemy/Phrasea/WorkerManager/Worker/SubdefCreationWorker.php
+++ b/lib/Alchemy/Phrasea/WorkerManager/Worker/SubdefCreationWorker.php
@@ -75,7 +75,7 @@ class SubdefCreationWorker implements WorkerInterface
if (!$canCreateSubdef) {
// the file is in used to write meta
- $this->messagePublisher->publishMessage($message, MessagePublisher::DELAYED_SUBDEF_QUEUE);
+ $this->messagePublisher->publishDelayedMessage($message, MessagePublisher::SUBDEF_CREATION_TYPE);
return ;
}
@@ -178,7 +178,10 @@ class SubdefCreationWorker implements WorkerInterface
// checking ended
// order to write meta for the subdef if needed
- $this->dispatcher->dispatch(WorkerEvents::SUBDEFINITION_WRITE_META, new SubdefinitionWritemetaEvent($record, $payload['subdefName']));
+ $this->dispatcher->dispatch(WorkerEvents::SUBDEFINITION_WRITE_META, new SubdefinitionWritemetaEvent(
+ $record,
+ $payload['subdefName'])
+ );
$this->subdefGenerator->setLogger($oldLogger);
diff --git a/lib/Alchemy/Phrasea/WorkerManager/Worker/WebhookWorker.php b/lib/Alchemy/Phrasea/WorkerManager/Worker/WebhookWorker.php
index d88d5f3332..c02a7a4cae 100644
--- a/lib/Alchemy/Phrasea/WorkerManager/Worker/WebhookWorker.php
+++ b/lib/Alchemy/Phrasea/WorkerManager/Worker/WebhookWorker.php
@@ -170,7 +170,11 @@ class WebhookWorker implements WorkerInterface
$this->messagePublisher->pushLog($workerMessage);
// count = 0 mean do not retry because no api application defined
- $this->dispatch(WorkerEvents::WEBHOOK_DELIVER_FAILURE, new WebhookDeliverFailureEvent($webhookevent->getId(), $workerMessage, 0));
+ $this->dispatch(WorkerEvents::WEBHOOK_DELIVER_FAILURE, new WebhookDeliverFailureEvent(
+ $webhookevent->getId(),
+ $workerMessage,
+ 0)
+ );
return;
}
@@ -235,7 +239,7 @@ class WebhookWorker implements WorkerInterface
$this->messagePublisher->publishFailedMessage(
$payload,
new AMQPTable(['worker-message' => $e->getMessage()]),
- MessagePublisher::FAILED_WEBHOOK_QUEUE
+ MessagePublisher::WEBHOOK_TYPE
);
}
}
diff --git a/lib/Alchemy/Phrasea/WorkerManager/Worker/WriteMetadatasWorker.php b/lib/Alchemy/Phrasea/WorkerManager/Worker/WriteMetadatasWorker.php
index e181fe8f7c..dac5ae527c 100644
--- a/lib/Alchemy/Phrasea/WorkerManager/Worker/WriteMetadatasWorker.php
+++ b/lib/Alchemy/Phrasea/WorkerManager/Worker/WriteMetadatasWorker.php
@@ -12,6 +12,8 @@ use Alchemy\Phrasea\Model\Repositories\WorkerRunningJobRepository;
use Alchemy\Phrasea\WorkerManager\Event\SubdefinitionWritemetaEvent;
use Alchemy\Phrasea\WorkerManager\Event\WorkerEvents;
use Alchemy\Phrasea\WorkerManager\Queue\MessagePublisher;
+use DateTime;
+use Exception;
use Monolog\Logger;
use PHPExiftool\Driver\Metadata\Metadata;
use PHPExiftool\Driver\Metadata\MetadataBag;
@@ -21,6 +23,7 @@ use PHPExiftool\Driver\Value\Multi;
use PHPExiftool\Exception\TagUnknown;
use PHPExiftool\Writer;
use Psr\Log\LoggerInterface;
+use record_adapter;
class WriteMetadatasWorker implements WorkerInterface
{
@@ -73,7 +76,7 @@ class WriteMetadatasWorker implements WorkerInterface
if (!$canWriteMeta) {
// the file is in used to generate subdef
- $this->messagePublisher->publishMessage($message, MessagePublisher::DELAYED_METADATAS_QUEUE);
+ $this->messagePublisher->publishDelayedMessage($message, MessagePublisher::WRITE_METADATAS_TYPE);
return ;
}
@@ -113,7 +116,7 @@ class WriteMetadatasWorker implements WorkerInterface
$em->beginTransaction();
try {
- $date = new \DateTime();
+ $date = new DateTime();
$workerRunningJob = new WorkerRunningJob();
$workerRunningJob
->setDataboxId($databoxId)
@@ -129,14 +132,17 @@ class WriteMetadatasWorker implements WorkerInterface
$em->flush();
$em->commit();
- } catch (\Exception $e) {
+ } catch (Exception $e) {
$em->rollback();
+ $this->logger->error("Error persisting WorkerRunningJob !");
+
+ return ;
}
}
try {
$subdef = $record->get_subdef($payload['subdefName']);
- } catch (\Exception $e) {
+ } catch (Exception $e) {
$workerMessage = "Exception catched when try to get subdef " .$payload['subdefName']. " from DB for the recordID: " .$recordId;
$this->logger->error($workerMessage);
@@ -221,7 +227,7 @@ class WriteMetadatasWorker implements WorkerInterface
try {
$value = self::fixDate($value); // will return NULL if the date is not valid
}
- catch (\Exception $e) {
+ catch (Exception $e) {
$value = null; // do NOT write back to iptc
}
}
@@ -230,7 +236,7 @@ class WriteMetadatasWorker implements WorkerInterface
$value = new Mono($value);
}
}
- } catch(\Exception $e) {
+ } catch(Exception $e) {
// the field is not set in the record, erase it
if ($fieldStructure->is_multi()) {
$value = new Multi(array(''));
@@ -260,8 +266,8 @@ class WriteMetadatasWorker implements WorkerInterface
$this->writer->write($subdef->getRealPath(), $metadata);
$this->messagePublisher->pushLog(sprintf('meta written for sbasid=%1$d - recordid=%2$d (%3$s)', $databox->get_sbas_id(), $recordId, $subdef->get_name() ));
- } catch (\Exception $e) {
- $workerMessage = sprintf('meta NOT written for sbasid=%1$d - recordid=%2$d (%3$s) because "%s"', $databox->get_sbas_id(), $recordId, $subdef->get_name() , $e->getMessage());
+ } catch (Exception $e) {
+ $workerMessage = sprintf('meta NOT written for sbasid=%1$d - recordid=%2$d (%3$s) because "%4$s"', $databox->get_sbas_id(), $recordId, $subdef->get_name() , $e->getMessage());
$this->logger->error($workerMessage);
$count = isset($payload['count']) ? $payload['count'] + 1 : 2 ;
@@ -297,11 +303,11 @@ class WriteMetadatasWorker implements WorkerInterface
$em->beginTransaction();
try {
$workerRunningJob->setStatus(WorkerRunningJob::FINISHED);
- $workerRunningJob->setFinished(new \DateTime('now'));
+ $workerRunningJob->setFinished(new DateTime('now'));
$em->persist($workerRunningJob);
$em->flush();
$em->commit();
- } catch (\Exception $e) {
+ } catch (Exception $e) {
$em->rollback();
}
@@ -314,7 +320,7 @@ class WriteMetadatasWorker implements WorkerInterface
return str_replace("\0", "", $value);
}
- private function updateJeton(\record_adapter $record)
+ private function updateJeton(record_adapter $record)
{
$connection = $record->getDatabox()->get_connection();
@@ -344,16 +350,16 @@ class WriteMetadatasWorker implements WorkerInterface
$a = explode(';', preg_replace('/\D+/', ';', trim($value)));
switch (count($a)) {
case 3: // yyyy;mm;dd
- $date = new \DateTime($a[0] . '-' . $a[1] . '-' . $a[2]);
+ $date = new DateTime($a[0] . '-' . $a[1] . '-' . $a[2]);
$date = $date->format('Y-m-d H:i:s');
break;
case 6: // yyyy;mm;dd;hh;mm;ss
- $date = new \DateTime($a[0] . '-' . $a[1] . '-' . $a[2] . ' ' . $a[3] . ':' . $a[4] . ':' . $a[5]);
+ $date = new DateTime($a[0] . '-' . $a[1] . '-' . $a[2] . ' ' . $a[3] . ':' . $a[4] . ':' . $a[5]);
$date = $date->format('Y-m-d H:i:s');
break;
}
}
- catch (\Exception $e) {
+ catch (Exception $e) {
$date = null;
}
diff --git a/lib/classes/patch/413_PHRAS_3282.php b/lib/classes/patch/413_PHRAS_3282.php
new file mode 100644
index 0000000000..6ebfab3780
--- /dev/null
+++ b/lib/classes/patch/413_PHRAS_3282.php
@@ -0,0 +1,119 @@
+ MessagePublisher::ASSETS_INGEST_TYPE,
+ 'createRecord' => MessagePublisher::CREATE_RECORD_TYPE,
+ 'deleteRecord' => MessagePublisher::DELETE_RECORD_TYPE,
+ 'exportMail' => MessagePublisher::EXPORT_MAIL_TYPE,
+ 'exposeUpload' => MessagePublisher::EXPOSE_UPLOAD_TYPE,
+ 'ftp' => MessagePublisher::FTP_TYPE,
+ 'populateIndex' => MessagePublisher::POPULATE_INDEX_TYPE,
+ 'pullAssets' => MessagePublisher::PULL_ASSETS_TYPE,
+ 'recordEdit' => MessagePublisher::RECORD_EDIT_TYPE,
+ 'subdefCreation' => MessagePublisher::SUBDEF_CREATION_TYPE,
+ 'validationReminder' => MessagePublisher::VALIDATION_REMINDER_TYPE,
+ 'writeMetadatas' => MessagePublisher::WRITE_METADATAS_TYPE,
+ 'webhook' => MessagePublisher::WEBHOOK_TYPE,
+ ];
+ const OLDQ2NEWQ_ttl_delayed = [
+ 'delayedSubdef' => MessagePublisher::SUBDEF_CREATION_TYPE,
+ 'delayedWriteMeta' => MessagePublisher::WRITE_METADATAS_TYPE,
+ ];
+ /** @var string */
+ private $release = '4.1.3';
+ /** @var array */
+ private $concern = [base::APPLICATION_BOX, base::DATA_BOX];
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_release()
+ {
+ return $this->release;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDoctrineMigrations()
+ {
+ return [];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function require_all_upgrades()
+ {
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function concern()
+ {
+ return $this->concern;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function apply(base $base, Application $app)
+ {
+ if ($base->get_base_type() === base::DATA_BOX) {
+ $this->patch_databox($base, $app);
+ }
+ elseif ($base->get_base_type() === base::APPLICATION_BOX) {
+ $this->patch_appbox($base, $app);
+ }
+
+ return true;
+ }
+
+ private function patch_databox(base $databox, Application $app)
+ {
+ }
+
+ private function patch_appbox(base $databox, Application $app)
+ {
+ /** @var PropertyAccess $conf */
+ $conf = $app['conf'];
+
+ // --------------------------------------------
+ // PHRAS-3282_refacto-some-code-on-workers_MASTER
+ // patch workers settings
+ // --------------------------------------------
+
+ foreach(self::OLDQ2NEWQ_ttl_retry as $old=>$new) {
+ if(($v = $conf->get(['workers', 'retry_queue', $old], null)) !== null) {
+ $conf->set(['workers', 'queues', $new, 'ttl_retry'], $v);
+ }
+ }
+
+ foreach(self::OLDQ2NEWQ_ttl_delayed as $old=>$new) {
+ if(($v = $conf->get(['workers', 'retry_queue', $old], null)) !== null) {
+ $conf->set(['workers', 'queues', $new, 'ttl_delayed'], $v);
+ }
+ }
+
+ if(($v = $conf->get(['workers', 'pull_assets', 'pullInterval'], null)) !== null) {
+ $conf->set(['workers', 'queues', MessagePublisher::PULL_ASSETS_TYPE, 'ttl_retry'], $v * 1000);
+ }
+
+ if(($v = $conf->get(['workers', 'validationReminder', 'interval'], null)) !== null) {
+ $conf->set(['workers', 'queues', MessagePublisher::VALIDATION_REMINDER_TYPE, 'ttl_retry'], $v * 1000);
+ }
+
+ $conf->remove(['workers', 'retry_queue']);
+ $conf->remove(['workers', 'pull_assets']);
+ $conf->remove(['workers', 'validationReminder']);
+ }
+}
diff --git a/lib/classes/record/preview.php b/lib/classes/record/preview.php
index dd0ae0fe43..63666f5d7b 100644
--- a/lib/classes/record/preview.php
+++ b/lib/classes/record/preview.php
@@ -270,8 +270,7 @@ class record_preview extends record_adapter
$this->title .= parent::get_title($options);
break;
case "BASK":
- $this->title .= $this->name . ' - ' . parent::get_title($options)
- . ' (' . $this->getNumber() . '/' . $this->total . ') ';
+ $this->title .= $this->name . ' (' . $this->getNumber() . '/' . $this->total . ') - ' . parent::get_title($options);
break;
case "REG":
$title = parent::get_title($options);
diff --git a/resources/locales/messages.de.xlf b/resources/locales/messages.de.xlf
index fda2f460e5..f643e8be78 100644
--- a/resources/locales/messages.de.xlf
+++ b/resources/locales/messages.de.xlf
@@ -1,6 +1,6 @@
-
+
The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message.
@@ -133,7 +133,7 @@
%d fields have been updated
%d Felder wurden aktualisiert
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
%docs_not_orderable% documents ne peuvent pas etre commandes
@@ -248,12 +248,12 @@
%quantity% records added
%quantity% Datensätze hinzugefügt
Controller/Prod/StoryController.php
- Controller/Prod/BasketController.php
+ Controller/Prod/BasketController.php
%quantity% records moved
%quantity% Datensätze bewegt
- Controller/Prod/BasketController.php
+ Controller/Prod/BasketController.php
%quantity% selected files
@@ -395,6 +395,11 @@
*Phraseanet Navigator* ist eine Smartphone Anwendung, die dem Benutzer ermöglicht, sich auf diese Instanz zu verbinden.
Form/Configuration/APIClientsFormType.php
+
+ 1
+ 1
+ WorkerManager/Form/QueueSettingsType.php
+
1 record
1 Datensatz
@@ -612,7 +617,7 @@
Accuse de reception
Empfangsbestätigung
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
prod/templates/push.html.twig
@@ -695,7 +700,7 @@
Add a position
Ort hinzufügen
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Add an admin
@@ -705,17 +710,17 @@
Add an end point
Fügen Sie einen Endpunkt hinzu
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Add an entry point
Fügen Sie einen Einstiegspunkt hinzu
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Add new range
Fügen Sie ein neues Kapitel hinzu
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Add this url
@@ -962,7 +967,7 @@
Controller/Prod/StoryController.php
Controller/Prod/ToolsController.php
Controller/Prod/LazaretController.php
- Controller/Prod/BasketController.php
+ Controller/Prod/BasketController.php
Controller/Admin/CollectionController.php
Controller/Admin/CollectionController.php
Controller/Admin/CollectionController.php
@@ -1017,7 +1022,7 @@
An error occured, please retry
Ein Fehler ist aufgetreten, bitte versuchen Sie nochmal
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
An error occured, please retry or contact an admin if problem persist
@@ -1034,7 +1039,7 @@
An error occurred
Ein Fehler ist aufgetreten
Order/Controller/ProdOrderController.php
- Controller/Prod/BasketController.php
+ Controller/Prod/BasketController.php
Controller/Api/V1Controller.php
Controller/Api/V1Controller.php
Controller/Admin/CollectionController.php
@@ -1045,7 +1050,7 @@
An error occurred reading this file
Ein Fehler ist beim Lesen dieser Datei aufgetreten
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
An unexpected error occurred during authentication process, please contact an admin
@@ -1158,8 +1163,8 @@
Archive
Archivieren
- prod/WorkZone/Macros.html.twig
- prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
Are you sure you want delete users rights ?
@@ -1174,7 +1179,7 @@
Are you sure you want to delete this list ?
Wollen Sie diese Liste sicher löschen?
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
prod/templates/push.html.twig
@@ -1190,13 +1195,13 @@
Attention
Vorsicht
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
web/admin/index.html.twig
Attention !
Achtung !
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Attention, certain documents ont des sous-definitions substituees
@@ -1206,7 +1211,7 @@
Attention, en supprimant ce preregalge, vous ne pourrez plus modifier ou supprimer de publications prealablement effectues avec celui-ci
Achtung: Wenn Sie diese Voreinstellung löschen, können Sie Veröffentlichungen die mit diesen Voreinstellungen ausgeführt wurden weder verändern noch löschen
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Aucun
@@ -1221,7 +1226,7 @@
Aucun document selectionne
kein ausgewähltes Dokument
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Aucun statut editable
@@ -1262,7 +1267,7 @@
Aucune publication effectuee, verifiez vos parametres
keine Veröffentlichung ausgeführt, überprüfen Sie Ihre Parameter
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Audio
@@ -1461,27 +1466,27 @@
Basket created
Sammelkorb wurde erstellt
- Controller/Prod/BasketController.php
+ Controller/Prod/BasketController.php
Basket has been archived
Sammelkorb wurde archiviert
- Controller/Prod/BasketController.php
+ Controller/Prod/BasketController.php
Basket has been deleted
Sammelkorb wurde gelöscht
- Controller/Prod/BasketController.php
+ Controller/Prod/BasketController.php
Basket has been unarchived
Sammelkorb wurde nicht mehr archiviert
- Controller/Prod/BasketController.php
+ Controller/Prod/BasketController.php
Basket has been updated
Sammelkorb wurde aktualisiert
- Controller/Prod/BasketController.php
+ Controller/Prod/BasketController.php
Basket is not found
@@ -1491,7 +1496,7 @@
Basket updated
Sammelkorb wurde aktualisiert
- Controller/Prod/BasketController.php
+ Controller/Prod/BasketController.php
Binary data
@@ -1572,7 +1577,7 @@
Cancel
Abbrechen
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
actions/Property/type.html.twig
actions/Property/index.html.twig
prod/actions/delete_records_confirm_form.html.twig
@@ -1700,7 +1705,7 @@
Certaines publications n'ont pu etre effectuees, verifiez vos parametres
einige Veröffentlichung wurden nicht ausgeführt, überprüfen Sie Ihre Parameter
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Certains champs sont obligatoires, veuillez les remplir
@@ -1720,7 +1725,7 @@
Change play speed
Wiedergabegeschwindigkeit ändern
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Changes for rotation will be applied only on
@@ -2122,7 +2127,7 @@
Ctrl
Strg
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Cumulative total
@@ -2396,7 +2401,7 @@
Delete current
Aktuelles löschen
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Delete records
@@ -2451,7 +2456,7 @@
Des difficultes ont ete rencontres a la connection au serveur distant
Probleme sind bei der Verbindung mit dem entfernten Server aufgetreten
- WorkerManager/Worker/FtpWorker.php
+ WorkerManager/Worker/FtpWorker.php
TaskManager/Job/FtpJob.php
@@ -2631,7 +2636,7 @@
Drag and drop the pin to move position
Ziehen Sie das Pin-Symbol und legen Sie es ab, um den Standort zu verschieben
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Droits
@@ -2697,7 +2702,7 @@
Edit position
Standort bearbeiten
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Editer
@@ -2972,7 +2977,7 @@
End Range
Kapitel beenden
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
End session activity
@@ -3023,7 +3028,7 @@
Erreur : soit les parametres sont incorrects, soit le serveur distant ne repond pas
Falsche Parameter oder entfernter Server antwortet nicht
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Erreur YouTube a rencontré une erreur lors du traitement de la requête.
@@ -3162,9 +3167,9 @@
Einstellungen von ausführbaren Programme
Form/Configuration/MainConfigurationFormType.php
-
+
Expiration date successfully updated!
- Ablaufdatum erfolgreich aktualisiert!
+ Ablaufdatum erfolgreich aktualisiert!
Controller/Prod/PushController.php
@@ -3172,12 +3177,12 @@
Exportieren
Controller/Prod/DoDownloadController.php
Controller/Prod/DoDownloadController.php
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Export ranges
Kapitel exportieren
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Export saved in the waiting queue
@@ -3212,7 +3217,7 @@
Feedback
Feedback
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
web/prod/toolbar.html.twig
prod/WorkZone/Story.html.twig
prod/WorkZone/Macros.html.twig
@@ -3365,7 +3370,7 @@
Force sending of the document ?
Senden von dem Dokument zwingen?
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Forcer l'envoi du document
@@ -3499,22 +3504,22 @@
Go 1 frame backward
Gehen Sie ein Einzelbild zurück
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Go 1 frame forward
Gehen Sie ein Einzelbild vorwärts
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Go to end point
Gehen Sie zum Endpunkt
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Go to start point
Gehen Sie zum Startpunkt
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Good
@@ -3685,9 +3690,9 @@
Wenn Sie vorhaben, grossen Dateien zu speichern, bitte vergewissern Sie, dass sie in diese Verzeichnisse einpassen werden.
web/setup/step2.html.twig
-
+
Il ne vous reste plus que %timeLeft% pour terminer votre validation
- Es bleibt Ihr gleich %timeLeft%, um Ihr Feedback zu beenden
+ Es bleibt Ihr gleich %timeLeft%, um Ihr Feedback zu beenden
Notification/Mail/MailInfoValidationReminder.php
@@ -3876,7 +3881,7 @@
Keyboard shortcuts
Tastenkombinationen
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Keywords used for indexing purposes by search engines robots
@@ -3897,22 +3902,22 @@
L'utilisateur approuve ce document
Benutzer genehmigt dieses Dokument
- prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
L'utilisateur desapprouve ce document
Benutzer lehnt dieses Dokument ab
- prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
L'utilisateur n'a pas encore donne son avis sur ce document
Benutzer hat seine Meinung noch nicht gegeben
- prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
La connection vers le serveur distant est OK
Verbindung mit dem entfernten Server ist OK
- WorkerManager/Worker/FtpWorker.php
+ WorkerManager/Worker/FtpWorker.php
TaskManager/Job/FtpJob.php
@@ -4076,7 +4081,7 @@
Les parametres sont corrects, le serveur distant est operationnel
die Parameter sind korrekt, entfernter Server ist betriebsfähig
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Les paramétres oauth de votre application.
@@ -4101,8 +4106,8 @@
Lightbox
Lightbox
- prod/WorkZone/Macros.html.twig
- prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
Limite temporelle
@@ -4143,7 +4148,7 @@
List name can not be empty
Name der Liste muss nicht leer sein
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
List name is required
@@ -4172,9 +4177,9 @@
Live Suche
admin/fields/templates.html.twig
-
+
Load More
- Mehr laden
+ Mehr laden
prod/WorkZone/ExposePublicationAssets.html.twig
@@ -4321,7 +4326,7 @@
Message
Nachricht
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
prod/templates/push.html.twig
@@ -4425,7 +4430,7 @@
Move
Verschieben
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Move %countable% records to the chosen collection in the list.
@@ -4435,7 +4440,7 @@
Move down range
Kapitel herunterziehen
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Move one record to the chosen collection in the list.
@@ -4445,7 +4450,7 @@
Move up range
Kapitel aufrücken
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Moves records
@@ -4476,7 +4481,7 @@
Name
Name
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
actions/Download/prepare.html.twig
Bridge/Dailymotion/playlist_createcontainer.html.twig
prod/templates/push.html.twig
@@ -4490,12 +4495,12 @@
Navigate to end point
Navigieren Sie zum Endpunkt
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Navigate to entry point
Navigieren Sie zum Startpunkt
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Ne pas autoriser
@@ -4511,7 +4516,7 @@
New list name ?
Neuer Name der Liste?
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
prod/templates/push.html.twig
@@ -4557,7 +4562,7 @@
No active basket
Kein aktiver Sammekorb
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
No application for registration has been recorded
@@ -4639,7 +4644,7 @@
No users selected
Kein Benutzer ausgewählt
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Nom
@@ -4804,12 +4809,12 @@
One frame backward
Ein Einzelbild zurück
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
One frame forward
Ein Einzelbild vorwärts
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
One of these conditions
@@ -4963,11 +4968,11 @@
Pause
Pause
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
-
+
Percent of the time left before the end of the validation to send a reminder email
- Verbleibende Zeit Prozentsatz vor Ende des Feedbacks, um eine Erinnerungsmail zu senden
+ Verbleibende Zeit Prozentsatz vor Ende des Feedbacks, um eine Erinnerungsmail zu senden
Form/Configuration/ActionsFormType.php
@@ -5029,7 +5034,7 @@
Play
Play
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Playlist
@@ -5091,7 +5096,7 @@
Please provide a name for this selection.
Bitte benennen Sie diese Kollektion
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Please provide a valid IP address.
@@ -5131,7 +5136,7 @@
Please select one record
Bitte wählen Sie einen Datensatz aus
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Please wait while your files are being gathered for the download, this operation may take a few minutes.
@@ -5202,7 +5207,7 @@
Print
Drucken
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Problemes de connexion ?
@@ -5263,7 +5268,7 @@
Push
Push
eventsmanager/notify/push.php
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
prod/WorkZone/Macros.html.twig
@@ -5425,9 +5430,9 @@
tab/shift-tab : Feld ändern
web/prod/index.html.twig
-
+
Rappel : Il vous reste %timeLeft% pour valider %title% de %user%
- Es bleibt Ihr %timeLeft%, um %title% von %user% zu bestätigen
+ Es bleibt Ihr %timeLeft%, um %title% von %user% zu bestätigen
eventsmanager/notify/validationreminder.php
@@ -5451,12 +5456,12 @@
Re-ordonner
wieder ordnen
prod/Story/Reorder.html.twig
- prod/WorkZone/Macros.html.twig
- prod/WorkZone/Macros.html.twig
- prod/WorkZone/Macros.html.twig
- prod/WorkZone/Macros.html.twig
- prod/WorkZone/Macros.html.twig
- prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
prod/Baskets/Reorder.html.twig
@@ -5573,7 +5578,7 @@
Record removed from basket
Datensatz wurde aus dem Sammelkorb gelöscht
- Controller/Prod/BasketController.php
+ Controller/Prod/BasketController.php
Record removed from story
@@ -5660,7 +5665,7 @@
Remove current Range
Aktuelles Kapitel entfernen
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Remove from basket
@@ -5934,7 +5939,7 @@
Save as VTT
Kapitel speichern
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Save the list
@@ -6063,7 +6068,7 @@
Send
Senden
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
web/login/forgot-password.html.twig
prod/actions/Push.html.twig
prod/actions/Push.html.twig
@@ -6161,7 +6166,7 @@
Share
Verteilen
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Share my list
@@ -6176,7 +6181,7 @@
Shift
Umschalt
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Short description
@@ -6235,7 +6240,7 @@
Some files are being downloaded
Einige Dateien werden heruntergeladen
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Some of them are required, like the indexer, Exiftool or ImageMagick components, some others are optionnal, like FFmpeg which is used to preview video files.
@@ -6288,7 +6293,7 @@
Space bar
Space-Taste
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Stamp logo
@@ -6298,13 +6303,15 @@
Start
Start
+ admin/worker-manager/worker_validation_reminder.html.twig
+ admin/worker-manager/worker_pull_assets.html.twig
admin/task-manager/templates.html.twig
admin/task-manager/templates.html.twig
Start Range
Kapitel starten
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Start by creating one by using the "add" button on the left !
@@ -6347,6 +6354,8 @@
Stop
prod/upload/lazaret.html.twig
prod/upload/lazaret.html.twig
+ admin/worker-manager/worker_validation_reminder.html.twig
+ admin/worker-manager/worker_pull_assets.html.twig
admin/task-manager/templates.html.twig
admin/task-manager/templates.html.twig
@@ -6414,7 +6423,7 @@
Submit
Einreichen
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Substitute
@@ -6482,7 +6491,7 @@
Suppr
Entf
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Suppression de %n_element% photos
@@ -6719,7 +6728,7 @@
The requested basket does not exist
Der erforderte Sammelkorb existiert nicht
- Controller/Prod/BasketController.php
+ Controller/Prod/BasketController.php
The task status
@@ -6795,7 +6804,7 @@
This feature is not supported by your browser
Diese Funktion wird nicht von Ihrem Webbrowser unterhalten
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
This feed is public
@@ -6816,7 +6825,7 @@
This file is too big
Datei ist zu gross
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
web/admin/index.html.twig
@@ -6837,7 +6846,7 @@
This user does not participate to the validation but is only viewer.
Dieser Benutzer darf nicht teilnehmen, nur ansehen.
- prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
This user has no rights
@@ -6867,7 +6876,7 @@
Time for feedback (days)
Zeit für Feedback (Tage)
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
prod/templates/push.html.twig
@@ -6890,7 +6899,7 @@
Toggle loop
Wiederholung aktivieren
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Token
@@ -6905,7 +6914,7 @@
Tool box
Werkzeuge
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Total
@@ -6931,13 +6940,13 @@
Transfert Annule
Übertragung abgebrochen
- WorkerManager/Worker/FtpWorker.php
+ WorkerManager/Worker/FtpWorker.php
TaskManager/Job/FtpJob.php
Transfert OK
Übertragung OK
- WorkerManager/Worker/FtpWorker.php
+ WorkerManager/Worker/FtpWorker.php
TaskManager/Job/FtpJob.php
@@ -7261,7 +7270,7 @@
User can download HD
Benutzer darf HD herunterladen
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
prod/templates/push.html.twig
prod/templates/push.html.twig
prod/templates/push.html.twig
@@ -7272,14 +7281,14 @@
User can see others choices
Benutzer darf die andere Auswahlen sehen
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
prod/templates/push.html.twig
prod/templates/push.html.twig
User contribute to the feedback
Benutzer darf Feedback geben
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
prod/templates/push.html.twig
prod/templates/push.html.twig
@@ -7463,7 +7472,7 @@
Vous avez envoye une demande de validation de document sur ce panier
Sie haben eine Bewertung von Dokumenten angefordert
- prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
Vous avez recu des documents
@@ -7567,7 +7576,7 @@
Vous ne pouvez pas selectionner plus de 800 enregistrements
Sie können nicht mehr als 800 Datensätze auswählen
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Vous ne pouvez uploader des elements sur Dailymotion qu'un par un
@@ -7763,7 +7772,7 @@
You can choose only one record
Sie dürfen nur einen Datensatz auswählen
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
You can download the documentation here
@@ -7794,7 +7803,7 @@
You do not have access to this basket
Sie haben keinen Zugriff auf diesen Sammelkorb
- Controller/Prod/BasketController.php
+ Controller/Prod/BasketController.php
You do not have enough rights to access quarantine
@@ -8082,8 +8091,8 @@
action : supprimer
Löschen
web/prod/toolbar.html.twig
- prod/WorkZone/Macros.html.twig
- prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
action:: nouveau panier
@@ -8109,37 +8118,28 @@
action::Valider
Bestätigen
- prod/WorkZone/Macros.html.twig
- prod/WorkZone/Macros.html.twig
- prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
action::detacher
entfernen
- prod/WorkZone/Macros.html.twig
- prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
action::editer
Bearbeiten
- prod/WorkZone/Macros.html.twig
- prod/WorkZone/Macros.html.twig
-
-
- action::exporter
- Exportieren
- prod/WorkZone/Macros.html.twig
- prod/WorkZone/Macros.html.twig
- prod/WorkZone/Macros.html.twig
- prod/WorkZone/Macros.html.twig
- prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
action::renommer
umbenennen
- prod/WorkZone/Macros.html.twig
- prod/WorkZone/Macros.html.twig
- prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
actual status
@@ -8151,9 +8151,9 @@
Kollektion wurde nicht erstellt: sie müssen einen Namen eingeben
admin/collection/create.html.twig
-
+
admin:: Phraseanet service setting (beta)
- Phraseanet-Service Einstellungen (beta)
+ Phraseanet-Service Einstellungen (beta)
web/admin/tree.html.twig
@@ -9118,26 +9118,16 @@
admin::workermanager: Rabbit config error
Konfigurationsfehler des Nachrichten Managers
- admin/worker-manager/index.html.twig
+ admin/worker-manager/index.html.twig
-
+
admin::workermanager:tab:Reminder: Interval in second
- Zeitintervall für das Feedback Erinnerung (in Sekunden)
- admin/worker-manager/worker_validation_reminder.html.twig
+ Zeitintervall für das Feedback Erinnerung (in Sekunden)
+ WorkerManager/Form/WorkerValidationReminderType.php
-
- admin::workermanager:tab:Reminder: Start
- Erinnerung Prozess starten
- admin/worker-manager/worker_validation_reminder.html.twig
-
-
- admin::workermanager:tab:Reminder: Stop
- Erinnerung Prozess stoppen
- admin/worker-manager/worker_validation_reminder.html.twig
-
-
+
admin::workermanager:tab:Reminder: description
- Eine Erinnerungsmail senden, wenn Feedback nicht abgeschlossen ist
+ Eine Erinnerungsmail senden, wenn Feedback nicht abgeschlossen ist
admin/worker-manager/worker_validation_reminder.html.twig
@@ -9145,34 +9135,34 @@
Allgemeine Einstellungen
admin/worker-manager/index.html.twig
-
+
admin::workermanager:tab:ftp: Proxy
- Proxy FTP
- WorkerManager/Form/WorkerFtpType.php
+ Proxy FTP
+ WorkerManager/Form/WorkerFtpType.php
-
+
admin::workermanager:tab:ftp: Proxy password
- Proxy Passwort
- WorkerManager/Form/WorkerFtpType.php
+ Proxy Passwort
+ WorkerManager/Form/WorkerFtpType.php
-
+
admin::workermanager:tab:ftp: Proxy port
- Proxy-Port
- WorkerManager/Form/WorkerFtpType.php
+ Proxy-Port
+ WorkerManager/Form/WorkerFtpType.php
-
+
admin::workermanager:tab:ftp: Proxy user
- admin::workermanager:tab:ftp: Proxy user
- WorkerManager/Form/WorkerFtpType.php
+ Proxy Benutzer
+ WorkerManager/Form/WorkerFtpType.php
-
+
admin::workermanager:tab:ftp: description
- Export FTP worker
+ FTP worker Export
admin/worker-manager/worker_ftp.html.twig
-
+
admin::workermanager:tab:ftp: title
- FTP
+ FTP
admin/worker-manager/index.html.twig
@@ -9188,32 +9178,22 @@
admin::workermanager:tab:pullassets: Client ID
Client ID
- WorkerManager/Form/WorkerPullAssetsType.php
+ WorkerManager/Form/WorkerPullAssetsType.php
admin::workermanager:tab:pullassets: Client secret
Client secret
- WorkerManager/Form/WorkerPullAssetsType.php
+ WorkerManager/Form/WorkerPullAssetsType.php
admin::workermanager:tab:pullassets: Fetching interval in second
Abrufintervall in Sekunden
- WorkerManager/Form/WorkerPullAssetsType.php
-
-
- admin::workermanager:tab:pullassets: Initialize pull assets
- Starten
- admin/worker-manager/worker_pull_assets.html.twig
-
-
- admin::workermanager:tab:pullassets: Stop pull assets
- Wiederherstellung der Medien beenden
- admin/worker-manager/worker_pull_assets.html.twig
+ WorkerManager/Form/WorkerPullAssetsType.php
admin::workermanager:tab:pullassets: Uploader api base uri
Uploader API base URI, zum Beispiel: https://api-uploader.phrasea.io
- WorkerManager/Form/WorkerPullAssetsType.php
+ WorkerManager/Form/WorkerPullAssetsType.php
admin::workermanager:tab:pullassets: description
@@ -9230,15 +9210,20 @@
Worker Anzahl
admin/worker-manager/worker_queue_monitor.html.twig
+
+ admin::workermanager:tab:queueMonitor: Delete Queue
+ Warteschlange löschen
+ admin/worker-manager/worker_queue_monitor.html.twig
+
admin::workermanager:tab:queueMonitor: Message count
Nachrichten Anzahl
admin/worker-manager/worker_queue_monitor.html.twig
-
+
admin::workermanager:tab:queueMonitor: Purge Queue
- Warteschlange löschen
- admin/worker-manager/worker_queue_monitor.html.twig
+ Warteschlange reinigen
+ admin/worker-manager/worker_queue_monitor.html.twig
admin::workermanager:tab:queueMonitor: Refresh list
@@ -9255,9 +9240,9 @@
Warteschlange
admin/worker-manager/index.html.twig
-
+
admin::workermanager:tab:reminder: title
- Feedback Erinnerung
+ Feedback Erinnerung
admin/worker-manager/index.html.twig
@@ -9268,17 +9253,17 @@
admin::workermanager:tab:searchengine: Elasticsearch index name
Elasticsearch Index Name
- WorkerManager/Form/WorkerSearchengineType.php
+ WorkerManager/Form/WorkerSearchengineType.php
admin::workermanager:tab:searchengine: Elasticsearch server host
Elasticsearch Server Host (ohne http oder https)
- WorkerManager/Form/WorkerSearchengineType.php
+ WorkerManager/Form/WorkerSearchengineType.php
admin::workermanager:tab:searchengine: Elasticsearch service port
Elasticsearch Service Port
- WorkerManager/Form/WorkerSearchengineType.php
+ WorkerManager/Form/WorkerSearchengineType.php
admin::workermanager:tab:searchengine: Populate
@@ -9310,85 +9295,35 @@
Auflösung
admin/worker-manager/index.html.twig
-
- admin::workermanager:tab:workerconfig: Config Worker queue delayed
- Verzögerungswarteschlange Konfiguration
- admin/worker-manager/worker_configuration.html.twig
-
-
- admin::workermanager:tab:workerconfig: Create record retry delay in ms
- Datensatzerstellung, in ms (Standardwert: 30 sek.)
- WorkerManager/Form/WorkerConfigurationType.php
-
-
- admin::workermanager:tab:workerconfig: Export mail retry delay in ms
- Mail Export, in ms (Standardwert: 30 sek.)
- WorkerManager/Form/WorkerConfigurationType.php
-
-
- admin::workermanager:tab:workerconfig: Ftp retry delay in ms (default 3 min)
- admin::workermanager:tab:workerconfig: Ftp retry delay in ms (default 3 min)
- WorkerManager/Form/WorkerConfigurationType.php
-
-
- admin::workermanager:tab:workerconfig: Ingest retry delay in ms
- Upload, in ms (Standardwert: 30 sek.)
- WorkerManager/Form/WorkerConfigurationType.php
-
-
- admin::workermanager:tab:workerconfig: Metadatas retry delay in ms
- Metadaten Schreiben, in ms (Standardwert: 30 sek.)
- WorkerManager/Form/WorkerConfigurationType.php
-
-
- admin::workermanager:tab:workerconfig: Populate Index retry delay in ms
- Indexierung, in ms (Standardwert: 30 sek.)
- WorkerManager/Form/WorkerConfigurationType.php
-
-
- admin::workermanager:tab:workerconfig: Set up the delay between two attempts per queue! (if not set, default 10000 millisecond)
- Wiederholungsinterval zwischen zwei Versuche, wenn Job einen Fehler erzeugt
- admin/worker-manager/worker_configuration.html.twig
-
-
- admin::workermanager:tab:workerconfig: Subdef delay in ms
- Auflösung Herstellung, in ms (Standardwert: 20 sek.)
- WorkerManager/Form/WorkerConfigurationType.php
-
-
- admin::workermanager:tab:workerconfig: Subdefinition retry delay in ms
- Auflösung Herstellung, in ms (Standardwert: 30 sek.)
- WorkerManager/Form/WorkerConfigurationType.php
-
-
- admin::workermanager:tab:workerconfig: Webhook retry delay in ms
- Webhook, in ms (Standardwert: 30 sek.)
- WorkerManager/Form/WorkerConfigurationType.php
-
-
- admin::workermanager:tab:workerconfig: Write meta delay in ms
- Metadaten Schreiben, in ms (Standardwert: 20 sek.)
- WorkerManager/Form/WorkerConfigurationType.php
-
-
- admin::workermanager:tab:workerconfig: if not set ,default 5000 millisecond
- Zeitintervall, wenn Datei von einem anderen Prozess gesperrt wird
- admin/worker-manager/worker_configuration.html.twig
-
admin::workermanager:tab:workerconfig: title
Workers allgemeine Einstellungen
- admin/worker-manager/worker_configuration.html.twig
+ admin/worker-manager/worker_configuration.html.twig
-
+
admin::workermanager:tab:workerconfig: warning
- Es ist erforderlich, Meldungswarteschlangen zu zerstören, für die Einbeziehung von neuen Zeitintervallen
- admin/worker-manager/worker_configuration.html.twig
+ Es ist erforderlich, Meldungswarteschlangen zu zerstören, für die Einbeziehung von neuen Zeitintervallen. Diese Aktion kann im Warteschlange Tab durchgeführt werden.
+ admin/worker-manager/worker_configuration.html.twig
-
- admin::workermanager:tab:workerconfig:Apply in queue
- Anwenden
- admin/worker-manager/worker_configuration.html.twig
+
+ admin::workermanager:tab:workerconfig:delayed delay in seconds
+ Zeitintervall zwischen Versuche fur verzögerte Nachrichte (Sek.)
+ WorkerManager/Form/QueueSettingsType.php
+
+
+ admin::workermanager:tab:workerconfig:max retry
+ Maximale Anzahl von Versuchen
+ WorkerManager/Form/QueueSettingsType.php
+
+
+ admin::workermanager:tab:workerconfig:n_workers
+ n_workers
+ WorkerManager/Form/QueueSettingsType.php
+
+
+ admin::workermanager:tab:workerconfig:retry delay in seconds
+ Zeitintervall für neue Versuch (Sek.)
+ WorkerManager/Form/QueueSettingsType.php
admin::workermanager:tab:workerinfo: Display error work
@@ -9465,11 +9400,6 @@
Beendet
admin/worker-manager/worker_info.html.twig
-
- admin::workermanager:tab:workerinfo: payload
- Payload
- admin/worker-manager/worker_info.html.twig
-
admin::workermanager:tab:workerinfo: published
Erstellt
@@ -9500,146 +9430,146 @@
Auftrag auf
admin/worker-manager/worker_info.html.twig
-
+
admin:expose Retrieve configuration error
- Unmöglich, die Expose Einstellungen wiederzuherstellen
+ Unmöglich, die Expose Einstellungen wiederzuherstellen
admin/phraseanet-service/index.html.twig
admin/phraseanet-service/index.html.twig
-
+
admin:phrasea-service-setting:tab-title:: Page title
- Phraseanet-Service Einstellungen
+ Phraseanet-Service Einstellungen
admin/phraseanet-service/index.html.twig
-
+
admin:phrasea-service-setting:tab:: Auth
- Auth Service
+ Auth Service
admin/phraseanet-service/index.html.twig
-
+
admin:phrasea-service-setting:tab:: Expose
- Expose Service
+ Expose Service
admin/phraseanet-service/index.html.twig
-
+
admin:phrasea-service-setting:tab:: Notify
- Notify Service
+ Notify Service
admin/phraseanet-service/index.html.twig
-
+
admin:phrasea-service-setting:tab:: Report
- Report Service
+ Report Service
admin/phraseanet-service/index.html.twig
-
+
admin:phrasea-service-setting:tab:: Uploader
- Uploader Service
+ Uploader Service
admin/phraseanet-service/index.html.twig
-
+
admin:phrasea-service-setting:tab:expose:: Activate this expose
- Diese Expose Aktivieren
+ Diese Expose Aktivieren
PhraseanetService/Form/PSExposeConnectionType.php
-
+
admin:phrasea-service-setting:tab:expose:: Add mapping
- Ein Phraseanet Mapping für die Medien und seine Beschreibung hinzufügen
+ Ein Phraseanet Mapping für die Medien und seine Beschreibung hinzufügen
admin/phraseanet-service/expose.html.twig
-
+
admin:phrasea-service-setting:tab:expose:: Add user
- Benutzer hinzufügen
+ Benutzer hinzufügen
admin/phraseanet-service/expose.html.twig
-
+
admin:phrasea-service-setting:tab:expose:: Auth Base Uri
- Auth Base Uri
+ Auth Base Uri
PhraseanetService/Form/PSExposeConnectionType.php
-
+
admin:phrasea-service-setting:tab:expose:: Auth Client ID
- Auth Client ID
+ Auth Client ID
PhraseanetService/Form/PSExposeConnectionType.php
-
+
admin:phrasea-service-setting:tab:expose:: Auth Client secret
- Auth Client secret
+ Auth Client secret
PhraseanetService/Form/PSExposeConnectionType.php
-
+
admin:phrasea-service-setting:tab:expose:: Connection Kind
- Methode der Verbindung
+ Methode der Verbindung
PhraseanetService/Form/PSExposeConnectionType.php
-
+
admin:phrasea-service-setting:tab:expose:: Delete
- Diese Expose löschen
+ Diese Expose löschen
admin/phraseanet-service/expose.html.twig
-
+
admin:phrasea-service-setting:tab:expose:: Expose Base Uri api
- Expose Base Uri api
+ Expose Base Uri API
PhraseanetService/Form/PSExposeConnectionType.php
-
+
admin:phrasea-service-setting:tab:expose:: Expose Client ID
- Expose Client ID
+ Expose Client ID
PhraseanetService/Form/PSExposeConnectionType.php
-
+
admin:phrasea-service-setting:tab:expose:: Expose Client secret
- Expose Client secret
+ Expose Client secret
PhraseanetService/Form/PSExposeConnectionType.php
-
+
admin:phrasea-service-setting:tab:expose:: Expose Front base uri
- Expose Front base uri
+ Expose Front base URI
PhraseanetService/Form/PSExposeConnectionType.php
-
+
admin:phrasea-service-setting:tab:expose:: Expose setting
- Einstellungen für Expose Service
+ Einstellungen für Expose Service
admin/phraseanet-service/expose.html.twig
-
+
admin:phrasea-service-setting:tab:expose:: Name
- Expose Name
+ Expose Name
PhraseanetService/Form/PSExposeConnectionType.php
-
+
admin:phrasea-service-setting:tab:expose:: New expose interconnection name
- Expose unbennant
+ Expose unbennant
admin/phraseanet-service/expose.html.twig
-
+
admin:phrasea-service-setting:tab:expose:: Save
- Speichern
+ Speichern
admin/phraseanet-service/expose.html.twig
-
+
admin:phrasea-service-setting:tab:expose:: activate Phraseanet-service expose
- Expose Service in Prod aktivieren
+ Expose Service in Prod aktivieren
PhraseanetService/Form/PSExposeConfigurationType.php
-
+
admin:phrasea-service-setting:tab:expose:: add Mapping
- Ein Phraseanet Mapping für die Medien und die Beschreibungsfelder hinzufügen
+ Ein Phraseanet Mapping für die Medien und die Beschreibungsfelder hinzufügen
admin/phraseanet-service/expose.html.twig
-
+
admin:phrasea-service-setting:tab:expose:: add user
- Benutzer hinzufügen
+ Benutzer hinzufügen
admin/phraseanet-service/expose.html.twig
-
+
admin:phrasea-service-setting:tab:expose:: connection test
- Verbindungstest mit Expose (nicht implementiert)
+ Verbindungstest mit Expose (nicht implementiert)
admin/phraseanet-service/expose.html.twig
admin:worker Retrieve configuration error
Worker Abruf Konfigurationsfehler
- admin/worker-manager/index.html.twig
+ admin/worker-manager/index.html.twig
alert
@@ -9709,6 +9639,11 @@
Jetzt die Datenbank neu indexieren (Dieser Vorgang kann bei vielen Datensätzen / ab 10.000/ Stunden dauern)
admin/databox/databox.html.twig
+
+ basket:: Items are being to moved !
+ Elemente im Korb wurden verschoben !
+ Controller/Prod/LanguageController.php
+
basket:action:delete record form basket
Datensatz vom Sammelkorb entfernen
@@ -9721,6 +9656,16 @@
prod/WorkZone/Story.html.twig
prod/WorkZone/Basket.html.twig
+
+ basket:feedback Delete item
+ Datensatz entfernen
+ Controller/Prod/LanguageController.php
+
+
+ basket:feedback Warning!You are about to delete one record from a feedback, please confirm your action
+ Warnung! Sie sind im Begriff, einen Datensatz von einem Feedback zu löschen. Sie werden alle Abstimmungen verlieren. Bitte bestätigen Sie diese Aktion.
+ Controller/Prod/LanguageController.php
+
be notified when a document is placed in quarantine
Benachrichtigungen bekommen, wenn ein Dokument unter Quarantäne gestellt wird
@@ -9782,6 +9727,9 @@
boutton::appliquer
Anwenden
+ WorkerManager/Form/WorkerConfigurationType.php
+ WorkerManager/Form/WorkerValidationReminderType.php
+ WorkerManager/Form/WorkerPullAssetsType.php
web/admin/users.html.twig
@@ -10115,12 +10063,12 @@
cgus :: Attention, si vous refuser les CGUs de cette base, vous n'y aures plus acces
Achtung: Wenn Sie die ANB ablehnen können Sie sich nicht in die Datenbank einloggen
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
cgus :: Vous devez vous reauthentifier pour que vos parametres soient pris en compte.
Änderungen werden erst bei der nächsten Anmeldung wirksam
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
cgus :: accepter
@@ -10177,9 +10125,9 @@
web/admin/subdefs.html.twig
web/admin/subdefs.html.twig
-
+
client_credentials
- client_credentials
+ client_credentials
PhraseanetService/Form/PSExposeConnectionType.php
@@ -10285,7 +10233,7 @@
delete
Löschen
- prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
descendant
@@ -10317,7 +10265,7 @@
web/account/account.html.twig
web/account/account.html.twig
web/account/account.html.twig
- prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
edit: chosiir limage du regroupement
@@ -10327,22 +10275,22 @@
edit:: Ajouter %s au champ courrant
%s zum ausgewählten Dokument hinzufügen
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
edit:: Ajouter %s au champ courrant pour les records selectionnes
%s an allen ausgewählte Dokumente hinzufügen
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
edit:: Supprimer %s du champ courrant
%s von ausgewähltem Dokument löschen
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
edit:: Supprimer %s du champ dans les records selectionnes
%s von allen ausgewählten Dokumente löschen
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
edit::Certains champs doivent etre remplis pour valider cet editing
@@ -10352,7 +10300,7 @@
edit::certains documents possedent des champs requis non remplis. Merci de les remplir pour valider votre editing
Bei einigen Dokumenten wurden erforderliche Felder nicht ausgefüllt. Bitte füllen Sie diese vor der Bestätigung aus.
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
edit::preset:: titre
@@ -10448,16 +10396,16 @@
E-Mail Adressen durch Kommas getrennt
web/common/dialog_export.html.twig
-
+
expose::Your are about to delete a publication from expose, please confirm your action !
- Löschen der Veröffentlichung bestätigen
- Controller/Prod/LanguageController.php
-
-
- expose::Your are about to delete an asset from a publication, please confirm your action !
- Löschen der Medien in der Veröffentlichung bestätigen
+ Sie sind im Begriff, eine Veröffentlichung von Expose zu löschen. Bitte bestätigen Sie diese Aktion.
Controller/Prod/LanguageController.php
+
+ expose::Your are about to delete an asset from a publication, please confirm your action !
+ Sie sind im Begriff, einen Datensatz von einer Veröffentlichung zu löschen. Bitte bestätigen Sie diese Aktion !
+ Controller/Prod/LanguageController.php
+
failed to send mail
Email Senden ist fehlgeschlagen
@@ -10676,7 +10624,7 @@
invite:: Redirection vers la zone d'authentification, cliquez sur OK pour continuer ou annulez
Umleitung auf die Anmelde-Seite. Mit OK kommen Sie zur Anmeldeseite und mit klick auf Abbrechen können Sieauf dieser Seite fortfahren
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
janvier
@@ -10968,7 +10916,7 @@
or
Oder
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
order-manager::mail: your-order-of
@@ -11235,8 +11183,8 @@
panier:: Un reportage ne peux recevoir que des elements provenants de la base ou il est enregistre
Ein Bericht darf nur Elemente enthalten die aus der selben Datenbank kommen
- Controller/Prod/LanguageController.php
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
panier:: description
@@ -11251,32 +11199,32 @@
panier:: ordre Validation ascendante
gut bewertet
- prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
panier:: ordre Validation descendante
weniger gut bewertet
- prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
panier:: ordre du panier
Sammelkorb Reihenfolge
- prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
panier:: renommer le panier
umbenennen
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
panier:: vous ne pouvez pas supprimer un panier public
Sie können keinen leeren öffentlichen Sammelkorb löschen
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
panier::Attention, vous etes sur le point de supprimer un element du reportage. Merci de confirmer votre action.
Achtung : Sie sind dabei ein Element des Berichtes zu löschen. Bitte bestätigen Sie Ihre Handlung.
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
panier::Supression d'un element d'un reportage
@@ -11286,7 +11234,7 @@
paniers:: panier recu de %pusher%
Sammelkorb von %pusher% bekommen
- prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
paniers::Vous etes sur le point de supprimer ce panier. Cette action est irreversible. Souhaitez-vous continuer ?
@@ -11309,9 +11257,9 @@
pro Monat
web/admin/editusers_quotas.html.twig
-
+
password
- Passwort
+ Passwort
PhraseanetService/Form/PSExposeConnectionType.php
@@ -11337,7 +11285,7 @@
phraseanet:: Erreur
Fehler
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
phraseanet:: Modele de donnees
@@ -11651,7 +11599,7 @@
phraseanet::recherche avancee
Erweiterte Suche
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
phraseanet::status bit
@@ -11988,14 +11936,14 @@
Suchen Sie den Inhalt der Felder
web/prod/index.html.twig
-
+
prod::basketTab:basket
- Sammelkorb
+ Sammelkorb
web/prod/index.html.twig
-
+
prod::basketTab:expose
- Expose
+ Expose
web/prod/index.html.twig
@@ -12365,354 +12313,354 @@ Vorsicht: die aktuelle Werte werden durch die neue Werte überschrieben
prod:edit: chapters
Kapitel Bearbeitung
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
prod:edit: no overlaps for chapters
Keine Überschneidung für die Kapitel
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
prod:edit: only a media of type video can be edited
Nur eine Video kann bearbeitet werden
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
prod:edit: suggested_values
Vorgeschlagene Werte
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
prod:edit: video-editor
Video Tools
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
-
+
prod:expose:Add publication
- Eine Veröffentlichung hinzufügen
- prod/WorkZone/Macros.html.twig
- prod/WorkZone/Macros.html.twig
+ Eine Veröffentlichung hinzufügen
+ prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
-
+
prod:expose:Refresh
- Aktualisieren
- prod/WorkZone/Macros.html.twig
+ Aktualisieren
+ prod/WorkZone/Macros.html.twig
-
+
prod:expose:connection:Auth connexion
- Auth Verbindung
+ Auth Verbindung
prod/WorkZone/ExposeOauthLogin.html.twig
-
+
prod:expose:connection:Password
- Passwort
+ Passwort
prod/WorkZone/ExposeOauthLogin.html.twig
-
+
prod:expose:connection:Sign in
- Anmelden
+ Anmelden
prod/WorkZone/ExposeOauthLogin.html.twig
-
+
prod:expose:connection:Username
- Benutzername
+ Benutzername
prod/WorkZone/ExposeOauthLogin.html.twig
-
+
prod:expose:publication:Access rules
- Veröffentlichung Zugriffsregelungen
+ Veröffentlichung Zugriffsregelungen
prod/WorkZone/ExposeEdit.html.twig
prod/WorkZone/ExposeNew.html.twig
-
+
prod:expose:publication:Advanced setting
- Erweiterte Einstellung
+ Erweiterte Einstellung
prod/WorkZone/ExposeEdit.html.twig
prod/WorkZone/ExposeNew.html.twig
-
+
prod:expose:publication:Available (leave blank for permanet publication)
- Verfügbar (Datum leer lassen für dauerhafte Veröffentlichungen)
+ Verfügbar (Datum leer lassen für dauerhafte Veröffentlichungen)
prod/WorkZone/ExposeEdit.html.twig
prod/WorkZone/ExposeNew.html.twig
-
+
prod:expose:publication:Cancel
- Abbrechen
+ Abbrechen
prod/WorkZone/ExposeEdit.html.twig
prod/WorkZone/ExposeNew.html.twig
-
+
prod:expose:publication:Create publication
- Veröffentlichung erstellen
+ Veröffentlichung erstellen
prod/WorkZone/ExposeNew.html.twig
-
+
prod:expose:publication:Dark
- Dunkler Modus
+ Dunkler Modus
prod/WorkZone/ExposeEdit.html.twig
prod/WorkZone/ExposeNew.html.twig
-
+
prod:expose:publication:Delete
- Veröffentlichung löschen
+ Veröffentlichung löschen
prod/WorkZone/ExposePublicationAssets.html.twig
-
+
prod:expose:publication:Download
- Download Layout
+ Download Layout
prod/WorkZone/ExposeEdit.html.twig
prod/WorkZone/ExposeNew.html.twig
-
+
prod:expose:publication:Editing
- Bearbeitung
+ Bearbeitung
prod/WorkZone/ExposeEdit.html.twig
-
+
prod:expose:publication:Enabled
- Aktiviert
+ Aktiviert
prod/WorkZone/ExposeEdit.html.twig
prod/WorkZone/ExposeNew.html.twig
-
+
prod:expose:publication:From
- Von
+ Von
prod/WorkZone/ExposeEdit.html.twig
prod/WorkZone/ExposeNew.html.twig
-
+
prod:expose:publication:Gallery
- Gallery Layout
+ Gallery Layout
prod/WorkZone/ExposeEdit.html.twig
prod/WorkZone/ExposeNew.html.twig
-
+
prod:expose:publication:Layout
- Layout
+ Layout
prod/WorkZone/ExposeEdit.html.twig
prod/WorkZone/ExposeNew.html.twig
-
+
prod:expose:publication:Light
- Licht Modus
+ Licht Modus
prod/WorkZone/ExposeEdit.html.twig
prod/WorkZone/ExposeNew.html.twig
-
+
prod:expose:publication:Mapbox
- Map Layout
+ Map Layout
prod/WorkZone/ExposeEdit.html.twig
prod/WorkZone/ExposeNew.html.twig
-
+
prod:expose:publication:Name
- Veröffentlichung Name
+ Veröffentlichung Name
prod/WorkZone/ExposeEdit.html.twig
prod/WorkZone/ExposeNew.html.twig
-
+
prod:expose:publication:Open access
- Freier Zugang
+ Freier Zugang
prod/WorkZone/ExposeEdit.html.twig
prod/WorkZone/ExposeNew.html.twig
-
+
prod:expose:publication:Parent Publication
- Übergeordnete Veröffentlichung
+ Übergeordnete Veröffentlichung
prod/WorkZone/ExposeEdit.html.twig
prod/WorkZone/ExposeNew.html.twig
prod/WorkZone/ExposePublicationAssets.html.twig
-
+
prod:expose:publication:Password
- Passwort
+ Passwort
prod/WorkZone/ExposeEdit.html.twig
prod/WorkZone/ExposeNew.html.twig
-
+
prod:expose:publication:Permission
- Rechte
+ Rechte
prod/WorkZone/ExposeEdit.html.twig
prod/WorkZone/ExposeEdit.html.twig
-
+
prod:expose:publication:Profile
- Veröffentlichung Profil
+ Veröffentlichung Profil
prod/WorkZone/ExposeEdit.html.twig
prod/WorkZone/ExposeNew.html.twig
-
+
prod:expose:publication:Publicly listing
- Öffentlich auflisten (Veröffentlichung auf der Liste der Expose Zielseite)
+ Öffentlich auflisten (Veröffentlichung auf der Liste der Expose Zielseite)
prod/WorkZone/ExposeEdit.html.twig
prod/WorkZone/ExposeNew.html.twig
-
+
prod:expose:publication:Refresh Publication
- Assets aktualiseren
+ Assets aktualiseren
prod/WorkZone/ExposePublicationAssets.html.twig
-
+
prod:expose:publication:Select Layout
- Layout auswählen
+ Layout auswählen
prod/WorkZone/ExposeEdit.html.twig
prod/WorkZone/ExposeNew.html.twig
-
+
prod:expose:publication:Select Profile
- Profil auswählen
+ Profil auswählen
prod/WorkZone/ExposeEdit.html.twig
prod/WorkZone/ExposeNew.html.twig
-
+
prod:expose:publication:Select Theme
- Modus auswählen
+ Modus auswählen
prod/WorkZone/ExposeEdit.html.twig
prod/WorkZone/ExposeNew.html.twig
-
+
prod:expose:publication:Select a parent publication
- Eine übgeordnete Veröffentlichung auswählen
+ Eine übgeordnete Veröffentlichung auswählen
prod/WorkZone/ExposeEdit.html.twig
prod/WorkZone/ExposeNew.html.twig
-
+
prod:expose:publication:Slug
- Slug
+ Slug
prod/WorkZone/ExposeEdit.html.twig
prod/WorkZone/ExposeNew.html.twig
-
+
prod:expose:publication:Theme
- Modus
+ Modus
prod/WorkZone/ExposeEdit.html.twig
prod/WorkZone/ExposeNew.html.twig
-
+
prod:expose:publication:To
- Zu
+ Zu
prod/WorkZone/ExposeEdit.html.twig
prod/WorkZone/ExposeNew.html.twig
-
+
prod:expose:publication:Update Publication
- Veröffentlichung Einstellung ändern
+ Veröffentlichung Einstellung ändern
prod/WorkZone/ExposeEdit.html.twig
-
+
prod:expose:publication:Users
- Benutzer
+ Benutzer
prod/WorkZone/ExposeEdit.html.twig
prod/WorkZone/ExposeNew.html.twig
-
+
prod:expose:publication:permission:Group Name
- Gruppenname
+ Gruppenname
prod/WorkZone/ExposePermission.html.twig
-
+
prod:expose:publication:permission:User Name
- Benutzername
+ Benutzername
prod/WorkZone/ExposePermission.html.twig
-
+
prod:expose:publication:permission:list:Delete
- prod:expose:publication:permission:list:Delete
+ Löschen
prod/WorkZone/ExposePermission.html.twig
prod/WorkZone/ExposePermission.html.twig
-
+
prod:expose:publication:permission:list:Edit
- prod:expose:publication:permission:list:Edit
+ Bearbeiten
prod/WorkZone/ExposePermission.html.twig
prod/WorkZone/ExposePermission.html.twig
-
+
prod:expose:publication:permission:list:Group
- Gruppe
+ Gruppe
prod/WorkZone/ExposePermission.html.twig
-
+
prod:expose:publication:permission:list:Remove Group
- Gruppe entfernen
+ Gruppe entfernen
prod/WorkZone/ExposePermission.html.twig
-
+
prod:expose:publication:permission:list:Remove User
- Benutzer entfernen
+ Benutzer entfernen
prod/WorkZone/ExposePermission.html.twig
-
+
prod:expose:publication:permission:list:User
- Benutzer
+ Benutzer
prod/WorkZone/ExposePermission.html.twig
-
+
prod:expose:publication:permission:list:View
- Ansehen
+ Ansehen
prod/WorkZone/ExposePermission.html.twig
prod/WorkZone/ExposePermission.html.twig
-
+
prod:expose:select expose
- Expose auswählen
- prod/WorkZone/Macros.html.twig
+ Expose auswählen
+ prod/WorkZone/Macros.html.twig
-
+
prod:mapbox Change position
- Lokalisierung verändern
- Controller/Prod/LanguageController.php
+ Lokalisierung verändern
+ Controller/Prod/LanguageController.php
-
+
prod:mapboxgl: description info : right click to add position
- Rechtsklick, um die Position von ausgewählte Datensatz (¨e) zu verändern oder Rechtsklick auf die Positionssymbol, um die Position eines Datensatzes zu verändern
- Controller/Prod/LanguageController.php
+ Rechtsklick, um die Position von ausgewählte Datensatz (¨e) zu verändern oder Rechtsklick auf die Positionssymbol, um die Position eines Datensatzes zu verändern
+ Controller/Prod/LanguageController.php
prod:mapboxgl: description notice
Machen Sie einen Rechtsklick, um einen Suchbereich zu hinzufügen. Klicken Sie auf den Bereich zu entfernen. Benutzen Sie den Griff, um die Grösse zu ändern oder den Bereich zu verschieben. Es ist auch möglich, mehrere Suchbereiche auszuwählen.
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
-
+
prod:mapboxgl: title info
- Hilfe
- Controller/Prod/LanguageController.php
+ Hilfe
+ Controller/Prod/LanguageController.php
prod:mapboxgl: title map dialog
Lokalisierung Suche
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
prod:mapboxgl: title notice
Suchbereiche Funktionen
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
-
+
prod:mapboxjs: description info : right click to add position
- Rechtsklick, um die Position von ausgewählte Datensatz (¨e) zu verändern oder Rechtsklick auf die Positionssymbol, um die Position eines Datensatzes zu verändern
- Controller/Prod/LanguageController.php
+ Rechtsklick, um die Position von ausgewählte Datensatz (¨e) zu verändern oder Rechtsklick auf die Positionssymbol, um die Position eines Datensatzes zu verändern
+ Controller/Prod/LanguageController.php
-
+
prod:mapboxjs: description notice
- prod:mapboxjs: description notice
- Controller/Prod/LanguageController.php
+ Beschreibung
+ Controller/Prod/LanguageController.php
-
+
prod:mapboxjs: title info
- Hilfe
- Controller/Prod/LanguageController.php
+ Hilfe
+ Controller/Prod/LanguageController.php
-
+
prod:mapboxjs: title notice
- prod:mapboxjs: title notice
- Controller/Prod/LanguageController.php
+ Titel
+ Controller/Prod/LanguageController.php
prod:push: create new user
Neuer Benutzer
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
prod:push: delete selection
@@ -12812,12 +12760,12 @@ Vorsicht: die aktuelle Werte werden durch die neue Werte überschrieben
prod:videoeditor:subtitletab:message:: error
Fehler beim speichern des Untertitels
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
prod:videoeditor:subtitletab:message:: success
Erfolg
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
prod:workzone:basket:creation-date
@@ -12830,10 +12778,10 @@ Vorsicht: die aktuelle Werte werden durch die neue Werte überschrieben
Feedback Schlusstermin aktualisiert
prod/WorkZone/Basket.html.twig
-
+
prod:workzone:expose:modal:: title
- Veröffentlichung Einstellungen
- Controller/Prod/LanguageController.php
+ Veröffentlichung Einstellungen
+ Controller/Prod/LanguageController.php
prod:workzone:facetstab:search_and_facets_sort_options
@@ -13447,9 +13395,9 @@ Vorsicht: die aktuelle Werte werden durch die neue Werte überschrieben
Verbindungen
module/report/connexion.php
-
+
report::Demande de validation vers %n_user% utilisateurs depuis lapplication box
- Feedback zu %n_user% Benutzer
+ Feedback zu %n_user% Benutzer
prod/preview/short_history.html.twig
@@ -13497,9 +13445,9 @@ Vorsicht: die aktuelle Werte werden durch die neue Werte überschrieben
Veröffentlichung von %dest%
prod/preview/short_history.html.twig
-
+
report::Push vers %n_user% utilisateurs depuis lapplication box
- Push zu %n_user% Benutzer
+ Push zu %n_user% Benutzer
prod/preview/short_history.html.twig
@@ -13829,19 +13777,19 @@ Vorsicht: die aktuelle Werte werden durch die neue Werte überschrieben
task::ftp:Certains documents n'ont pas pu etre tranferes
Einige Dokumente konnten nicht übertragen werden
- WorkerManager/Worker/FtpWorker.php
+ WorkerManager/Worker/FtpWorker.php
TaskManager/Job/FtpJob.php
task::ftp:Details des fichiers
Angaben der Datei(en)
- WorkerManager/Worker/FtpWorker.php
+ WorkerManager/Worker/FtpWorker.php
TaskManager/Job/FtpJob.php
task::ftp:Etat d'envoi FTP vers le serveur "%server%" avec le compte "%username%" et pour destination le dossier : "%directory%"
Zustand von FTP-Senden zum Server "%server%" mit Konto "%username%" und Bestimmungsort: "%directory%"
- WorkerManager/Worker/FtpWorker.php
+ WorkerManager/Worker/FtpWorker.php
TaskManager/Job/FtpJob.php
@@ -13852,14 +13800,14 @@ Vorsicht: die aktuelle Werte werden durch die neue Werte überschrieben
task::ftp:File "%file%" (record %record_id%) de la base "%basename%" (Export du Document) : Transfert cancelled (le document n'existe plus)
Übertragung abgebrochen für die Datei "%file%" (recordid %record_id%) von Datenbank "%basename%" (Dokument Export) : Dokument existiert nicht mehr.
- WorkerManager/Worker/FtpWorker.php
+ WorkerManager/Worker/FtpWorker.php
TaskManager/Job/FtpJob.php
task::ftp:Record %recordid% - %filename% de la base (%databoxname% - %collectionname%) - %subdefname%
Datensatz %recordid% - %filename% von Datenbank (%databoxname% - %collectionname%) - %subdefname%
- WorkerManager/Worker/FtpWorker.php
- WorkerManager/Worker/FtpWorker.php
+ WorkerManager/Worker/FtpWorker.php
+ WorkerManager/Worker/FtpWorker.php
TaskManager/Job/FtpJob.php
TaskManager/Job/FtpJob.php
@@ -13872,13 +13820,13 @@ Vorsicht: die aktuelle Werte werden durch die neue Werte überschrieben
task::ftp:TENTATIVE no %number%, %date%
Versuch %number% - %date%
- WorkerManager/Worker/FtpWorker.php
+ WorkerManager/Worker/FtpWorker.php
TaskManager/Job/FtpJob.php
task::ftp:Tous les documents ont ete transferes avec succes
Alle Dokumente wurden erfolgreich übertragen
- WorkerManager/Worker/FtpWorker.php
+ WorkerManager/Worker/FtpWorker.php
TaskManager/Job/FtpJob.php
diff --git a/resources/locales/messages.en.xlf b/resources/locales/messages.en.xlf
index 0b91f982f6..741840c239 100644
--- a/resources/locales/messages.en.xlf
+++ b/resources/locales/messages.en.xlf
@@ -1,6 +1,6 @@
-
+
The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message.
@@ -133,7 +133,7 @@
%d fields have been updated
%d fields have been updated
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
%docs_not_orderable% documents ne peuvent pas etre commandes
@@ -248,12 +248,12 @@
%quantity% records added
%quantity% records added
Controller/Prod/StoryController.php
- Controller/Prod/BasketController.php
+ Controller/Prod/BasketController.php
%quantity% records moved
%quantity% records moved
- Controller/Prod/BasketController.php
+ Controller/Prod/BasketController.php
%quantity% selected files
@@ -395,6 +395,11 @@
*Phraseanet Navigator* is a smartphone application that allow user to connect on this instance.
Form/Configuration/APIClientsFormType.php
+
+ 1
+ 1
+ WorkerManager/Form/QueueSettingsType.php
+
1 record
1 record
@@ -612,7 +617,7 @@
Accuse de reception
Acknowledge receipt
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
prod/templates/push.html.twig
@@ -696,7 +701,7 @@
Add a position
Add a position
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Add an admin
@@ -706,17 +711,17 @@
Add an end point
Add an end point
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Add an entry point
Add an entry point
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Add new range
Add new chapter
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Add this url
@@ -963,7 +968,7 @@
Controller/Prod/StoryController.php
Controller/Prod/ToolsController.php
Controller/Prod/LazaretController.php
- Controller/Prod/BasketController.php
+ Controller/Prod/BasketController.php
Controller/Admin/CollectionController.php
Controller/Admin/CollectionController.php
Controller/Admin/CollectionController.php
@@ -1018,7 +1023,7 @@
An error occured, please retry
An error occured, please try again
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
An error occured, please retry or contact an admin if problem persist
@@ -1035,7 +1040,7 @@
An error occurred
An error occurred
Order/Controller/ProdOrderController.php
- Controller/Prod/BasketController.php
+ Controller/Prod/BasketController.php
Controller/Api/V1Controller.php
Controller/Api/V1Controller.php
Controller/Admin/CollectionController.php
@@ -1046,7 +1051,7 @@
An error occurred reading this file
An error occurred while reading this file
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
An unexpected error occurred during authentication process, please contact an admin
@@ -1159,8 +1164,8 @@
Archive
Archive
- prod/WorkZone/Macros.html.twig
- prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
Are you sure you want delete users rights ?
@@ -1175,7 +1180,7 @@
Are you sure you want to delete this list ?
Are you sure you want to delete this list?
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
prod/templates/push.html.twig
@@ -1191,13 +1196,13 @@
Attention
Warning
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
web/admin/index.html.twig
Attention !
Warning !
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Attention, certain documents ont des sous-definitions substituees
@@ -1207,7 +1212,7 @@
Attention, en supprimant ce preregalge, vous ne pourrez plus modifier ou supprimer de publications prealablement effectues avec celui-ci
Warning : by deleting this setting, modification and delete of existing publications made from it won't be possible
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Aucun
@@ -1222,7 +1227,7 @@
Aucun document selectionne
No document selected
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Aucun statut editable
@@ -1263,7 +1268,7 @@
Aucune publication effectuee, verifiez vos parametres
No publication done, check settings
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Audio
@@ -1462,27 +1467,27 @@
Basket created
Basket created
- Controller/Prod/BasketController.php
+ Controller/Prod/BasketController.php
Basket has been archived
Basket has been archived
- Controller/Prod/BasketController.php
+ Controller/Prod/BasketController.php
Basket has been deleted
Basket has been deleted
- Controller/Prod/BasketController.php
+ Controller/Prod/BasketController.php
Basket has been unarchived
Basket has been unarchived
- Controller/Prod/BasketController.php
+ Controller/Prod/BasketController.php
Basket has been updated
Basket has been updated
- Controller/Prod/BasketController.php
+ Controller/Prod/BasketController.php
Basket is not found
@@ -1492,7 +1497,7 @@
Basket updated
Basket updated
- Controller/Prod/BasketController.php
+ Controller/Prod/BasketController.php
Binary data
@@ -1573,7 +1578,7 @@
Cancel
Cancel
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
actions/Property/type.html.twig
actions/Property/index.html.twig
prod/actions/delete_records_confirm_form.html.twig
@@ -1701,7 +1706,7 @@
Certaines publications n'ont pu etre effectuees, verifiez vos parametres
Some publications failed, check settings
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Certains champs sont obligatoires, veuillez les remplir
@@ -1721,7 +1726,7 @@
Change play speed
Change play speed
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Changes for rotation will be applied only on
@@ -2124,7 +2129,7 @@
Ctrl
Ctrl
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Cumulative total
@@ -2399,7 +2404,7 @@
Delete current
Delete current
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Delete records
@@ -2454,7 +2459,7 @@
Des difficultes ont ete rencontres a la connection au serveur distant
Some difficulties encountered when connecting to distant server
- WorkerManager/Worker/FtpWorker.php
+ WorkerManager/Worker/FtpWorker.php
TaskManager/Job/FtpJob.php
@@ -2634,7 +2639,7 @@
Drag and drop the pin to move position
Drag and drop the pin to move position
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Droits
@@ -2700,7 +2705,7 @@
Edit position
Edit position
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Editer
@@ -2975,7 +2980,7 @@
End Range
End Range
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
End session activity
@@ -3026,7 +3031,7 @@
Erreur : soit les parametres sont incorrects, soit le serveur distant ne repond pas
Either the settings are invalid, either distant server is not responding
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Erreur YouTube a rencontré une erreur lors du traitement de la requête.
@@ -3175,12 +3180,12 @@
Export
Controller/Prod/DoDownloadController.php
Controller/Prod/DoDownloadController.php
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Export ranges
Export ranges
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Export saved in the waiting queue
@@ -3215,7 +3220,7 @@
Feedback
Feedback
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
web/prod/toolbar.html.twig
prod/WorkZone/Story.html.twig
prod/WorkZone/Macros.html.twig
@@ -3368,7 +3373,7 @@
Force sending of the document ?
Force sending of documents?
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Forcer l'envoi du document
@@ -3502,22 +3507,22 @@
Go 1 frame backward
Go 1 frame backward
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Go 1 frame forward
Go 1 frame forward
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Go to end point
Go to end point
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Go to start point
Go to start point
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Good
@@ -3688,9 +3693,9 @@
If you plan to store large files, make sure they will fit in these directories.
web/setup/step2.html.twig
-
+
Il ne vous reste plus que %timeLeft% pour terminer votre validation
- You have only %timeLeft% left to end your feedback
+ You have only %timeLeft% left to end your feedback
Notification/Mail/MailInfoValidationReminder.php
@@ -3879,7 +3884,7 @@
Keyboard shortcuts
Keyboard shortcuts
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Keywords used for indexing purposes by search engines robots
@@ -3900,22 +3905,22 @@
L'utilisateur approuve ce document
User approves this document
- prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
L'utilisateur desapprouve ce document
User disapproves this document
- prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
L'utilisateur n'a pas encore donne son avis sur ce document
User hasn't decided yet
- prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
La connection vers le serveur distant est OK
Successful connection to distant server
- WorkerManager/Worker/FtpWorker.php
+ WorkerManager/Worker/FtpWorker.php
TaskManager/Job/FtpJob.php
@@ -4079,7 +4084,7 @@
Les parametres sont corrects, le serveur distant est operationnel
Valid parameters, distant server is responding
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Les paramétres oauth de votre application.
@@ -4104,8 +4109,8 @@
Lightbox
Lightbox
- prod/WorkZone/Macros.html.twig
- prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
+ prod/WorkZone/Macros.html.twig
Limite temporelle
@@ -4146,7 +4151,7 @@
List name can not be empty
List name can not be emptied
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
List name is required
@@ -4175,9 +4180,9 @@
Live search
admin/fields/templates.html.twig
-
+
Load More
- Load More
+ Load More
prod/WorkZone/ExposePublicationAssets.html.twig
@@ -4324,7 +4329,7 @@
Message
Message
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
prod/templates/push.html.twig
@@ -4428,7 +4433,7 @@
Move
Move
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Move %countable% records to the chosen collection in the list.
@@ -4438,7 +4443,7 @@
Move down range
Move down range
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Move one record to the chosen collection in the list.
@@ -4448,7 +4453,7 @@
Move up range
Move up range
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Moves records
@@ -4479,7 +4484,7 @@
Name
Name
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
actions/Download/prepare.html.twig
Bridge/Dailymotion/playlist_createcontainer.html.twig
prod/templates/push.html.twig
@@ -4493,12 +4498,12 @@
Navigate to end point
Navigate to end point
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Navigate to entry point
Navigate to entry point
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Ne pas autoriser
@@ -4514,7 +4519,7 @@
New list name ?
Give a name to the new recipients list:
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
prod/templates/push.html.twig
@@ -4560,7 +4565,7 @@
No active basket
No active basket
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
No application for registration has been recorded
@@ -4642,7 +4647,7 @@
No users selected
No users selected
- Controller/Prod/LanguageController.php
+ Controller/Prod/LanguageController.php
Nom
@@ -4807,12 +4812,12 @@