mirror of
https://github.com/alchemy-fr/Phraseanet.git
synced 2025-10-10 19:43:16 +00:00
Merge branch 'master' into PHRAS-3278-patch-for-4-1-3
This commit is contained in:
51
.env
51
.env
@@ -1,4 +1,5 @@
|
|||||||
PHRASEANET_PROJECT_NAME=Phraseanet
|
PHRASEANET_PROJECT_NAME=Phraseanet
|
||||||
|
PHRASEANET_SERVER_NAME=localhost
|
||||||
# Registry from where you pull Docker images
|
# Registry from where you pull Docker images
|
||||||
PHRASEANET_DOCKER_REGISTRY=local
|
PHRASEANET_DOCKER_REGISTRY=local
|
||||||
# Tag of the Docker images
|
# 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 : Possible Values: alert, error, warning, notice, debug
|
||||||
PHP_LOG_LEVEL=warning
|
PHP_LOG_LEVEL=warning
|
||||||
|
|
||||||
|
# --------------- MYSQL CONFIGURATION --------------------
|
||||||
|
|
||||||
|
# Mysql max allowed packet
|
||||||
|
MYSQL_MAX_ALLOWED_PACKET=16M
|
||||||
|
|
||||||
# --------------- PHRASEANET CONFIGURATION --------------------
|
# --------------- PHRASEANET CONFIGURATION --------------------
|
||||||
|
|
||||||
# These variables are used in the configuration.yml .
|
# These variables are used in the configuration.yml .
|
||||||
@@ -54,11 +60,6 @@ PHRASEANET_DB_PASSWORD=root
|
|||||||
INSTALL_DB_TEMPLATE=DublinCore
|
INSTALL_DB_TEMPLATE=DublinCore
|
||||||
INSTALL_APPBOX=ab_master
|
INSTALL_APPBOX=ab_master
|
||||||
INSTALL_DATABOX=db_databox1
|
INSTALL_DATABOX=db_databox1
|
||||||
PHRASEANET_SERVER_NAME=localhost
|
|
||||||
|
|
||||||
# Mysql max allowed packet
|
|
||||||
MYSQL_MAX_ALLOWED_PACKET=16M
|
|
||||||
|
|
||||||
# binaries execution timeouts
|
# binaries execution timeouts
|
||||||
PHRASEANET_FFMPEG_TIMEOUT=7200
|
PHRASEANET_FFMPEG_TIMEOUT=7200
|
||||||
PHRASEANET_FFPROBE_TIMEOUT=120
|
PHRASEANET_FFPROBE_TIMEOUT=120
|
||||||
@@ -79,15 +80,32 @@ PHRASEANET_API_AUTH_TOKEN_HEADER_ONLY=false
|
|||||||
|
|
||||||
# Phraseanet mail configuration
|
# Phraseanet mail configuration
|
||||||
PHRASEANET_EMITTER_EMAIL=phraseanet@example.com
|
PHRASEANET_EMITTER_EMAIL=phraseanet@example.com
|
||||||
PHRASEANET_MAIL_OBJECT_PREFIX=
|
PHRASEANET_MAIL_OBJECT_PREFIX="phraseanet"
|
||||||
PHRASEANET_SMTP_ENABLED=false
|
PHRASEANET_SMTP_ENABLED=true
|
||||||
PHRASEANET_SMTP_HOST=
|
PHRASEANET_SMTP_HOST=mailhog
|
||||||
PHRASEANET_SMTP_PORT=
|
PHRASEANET_SMTP_PORT=1025
|
||||||
PHRASEANET_SMTP_AUTH_ENABLED=false
|
PHRASEANET_SMTP_AUTH_ENABLED=false
|
||||||
PHRASEANET_SMTP_SECURE_MODE=tls
|
PHRASEANET_SMTP_SECURE_MODE=null
|
||||||
PHRASEANET_SMTP_USER=
|
PHRASEANET_SMTP_USER=
|
||||||
PHRASEANET_SMTP_PASSWORD=
|
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
|
# Locale setting
|
||||||
|
|
||||||
@@ -100,6 +118,18 @@ LC_CTYPE=C.UTF-8
|
|||||||
LC_TIME=C.UTF-8
|
LC_TIME=C.UTF-8
|
||||||
LC_NAME=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 ---
|
# --- DEV purpose ---
|
||||||
|
|
||||||
# PhpMyAdmin port
|
# PhpMyAdmin port
|
||||||
@@ -140,3 +170,4 @@ SSH_AUTH_SOCK=/dev/null
|
|||||||
# Plugin support
|
# Plugin support
|
||||||
PHRASEANET_PLUGINS=
|
PHRASEANET_PLUGINS=
|
||||||
PHRASEANET_SSH_PRIVATE_KEY=
|
PHRASEANET_SSH_PRIVATE_KEY=
|
||||||
|
|
||||||
|
@@ -215,7 +215,7 @@ CMD ["php-fpm", "-F"]
|
|||||||
|
|
||||||
FROM phraseanet-fpm as phraseanet-worker
|
FROM phraseanet-fpm as phraseanet-worker
|
||||||
ENTRYPOINT ["docker/phraseanet/worker/entrypoint.sh"]
|
ENTRYPOINT ["docker/phraseanet/worker/entrypoint.sh"]
|
||||||
CMD ["bin/console", "worker:execute"]
|
CMD ["/bin/bash", "bin/run-worker.sh"]
|
||||||
|
|
||||||
#########################################################################
|
#########################################################################
|
||||||
# phraseanet-nginx
|
# phraseanet-nginx
|
||||||
|
68
Phraseanet-production-client/dist/production.js
vendored
68
Phraseanet-production-client/dist/production.js
vendored
@@ -10230,15 +10230,15 @@ var workzone = function workzone(services) {
|
|||||||
selection: new _selectable2.default(services, (0, _jquery2.default)('#baskets'), { selector: '.CHIM' }),
|
selection: new _selectable2.default(services, (0, _jquery2.default)('#baskets'), { selector: '.CHIM' }),
|
||||||
refresh: refreshBaskets,
|
refresh: refreshBaskets,
|
||||||
addElementToBasket: function addElementToBasket(options) {
|
addElementToBasket: function addElementToBasket(options) {
|
||||||
var sbas_id = options.sbas_id,
|
var dbId = options.dbId,
|
||||||
record_id = options.record_id,
|
recordId = options.recordId,
|
||||||
event = options.event,
|
event = options.event,
|
||||||
singleSelection = options.singleSelection;
|
singleSelection = options.singleSelection;
|
||||||
|
|
||||||
singleSelection = !!singleSelection || false;
|
singleSelection = !!singleSelection || false;
|
||||||
|
|
||||||
if ((0, _jquery2.default)('#baskets .SSTT.active').length === 1) {
|
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 {
|
} else {
|
||||||
humane.info(localeService.t('noActiveBasket'));
|
humane.info(localeService.t('noActiveBasket'));
|
||||||
}
|
}
|
||||||
@@ -10397,9 +10397,9 @@ var workzone = function workzone(services) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function WorkZoneElementRemover(el, confirm) {
|
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 = {};
|
var buttons = {};
|
||||||
|
|
||||||
buttons[localeService.t('valider')] = function () {
|
buttons[localeService.t('valider')] = function () {
|
||||||
@@ -10411,9 +10411,18 @@ var workzone = function workzone(services) {
|
|||||||
(0, _jquery2.default)('#DIALOG-baskets').dialog('close').remove();
|
(0, _jquery2.default)('#DIALOG-baskets').dialog('close').remove();
|
||||||
};
|
};
|
||||||
|
|
||||||
var texte = '<p>' + localeService.t('confirmRemoveReg') + '</p><div><input type="checkbox" onchange="prodApp.appEvents.emit(\'workzone.doRemoveWarning\', this);"/>' + localeService.t('hideMessage') + '</div>';
|
var texte = '';
|
||||||
|
var title = '';
|
||||||
|
if ((0, _jquery2.default)(el).hasClass('groupings')) {
|
||||||
|
texte = '<p>' + localeService.t('confirmRemoveReg') + '</p><div><input type="checkbox" onchange="prodApp.appEvents.emit(\'workzone.doRemoveWarning\', this);"/>' + localeService.t('hideMessage') + '</div>';
|
||||||
|
title = localeService.t('removeTitle');
|
||||||
|
} else {
|
||||||
|
texte = '<p>' + localeService.t('confirmRemoveFeedBack') + '</p>';
|
||||||
|
title = localeService.t('removeRecordFeedbackTitle');
|
||||||
|
}
|
||||||
|
|
||||||
(0, _jquery2.default)('body').append('<div id="DIALOG-baskets"></div>');
|
(0, _jquery2.default)('body').append('<div id="DIALOG-baskets"></div>');
|
||||||
(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,
|
autoOpen: false,
|
||||||
closeOnEscape: true,
|
closeOnEscape: true,
|
||||||
resizable: false,
|
resizable: false,
|
||||||
@@ -10519,7 +10528,9 @@ var workzone = function workzone(services) {
|
|||||||
|
|
||||||
uiactive.addClass('ui-state-focus active');
|
uiactive.addClass('ui-state-focus active');
|
||||||
|
|
||||||
|
// reset selection when opening a basket type
|
||||||
workzoneOptions.selection.empty();
|
workzoneOptions.selection.empty();
|
||||||
|
appEvents.emit('broadcast.workzoneResultSelection', { asArray: [], serialized: "" });
|
||||||
|
|
||||||
getContent(uiactive);
|
getContent(uiactive);
|
||||||
},
|
},
|
||||||
@@ -10884,6 +10895,10 @@ var workzone = function workzone(services) {
|
|||||||
left: -20
|
left: -20
|
||||||
},
|
},
|
||||||
start: function start(event, ui) {
|
start: function start(event, ui) {
|
||||||
|
if (!(0, _jquery2.default)(this).hasClass('selected')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
var baskets = (0, _jquery2.default)('#baskets');
|
var baskets = (0, _jquery2.default)('#baskets');
|
||||||
baskets.append('<div class="top-scroller"></div>' + '<div class="bottom-scroller"></div>');
|
baskets.append('<div class="top-scroller"></div>' + '<div class="bottom-scroller"></div>');
|
||||||
(0, _jquery2.default)('.bottom-scroller', baskets).bind('mousemove', function () {
|
(0, _jquery2.default)('.bottom-scroller', baskets).bind('mousemove', function () {
|
||||||
@@ -10898,9 +10913,9 @@ var workzone = function workzone(services) {
|
|||||||
},
|
},
|
||||||
drag: function drag(event, ui) {
|
drag: function drag(event, ui) {
|
||||||
if (appCommons.utilsModule.is_ctrl_key(event) || (0, _jquery2.default)(this).closest('.content').hasClass('grouping')) {
|
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 {
|
} 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) {
|
switch (action) {
|
||||||
case 'CHU2CHU':
|
case 'CHU2CHU':
|
||||||
if (!appCommons.utilsModule.is_ctrl_key(event)) act = 'MOV';
|
if (appCommons.utilsModule.is_ctrl_key(event)) act = 'MOV';
|
||||||
break;
|
break;
|
||||||
case 'IMGT2REG':
|
case 'IMGT2REG':
|
||||||
case 'CHU2REG':
|
case 'CHU2REG':
|
||||||
@@ -11125,6 +11140,8 @@ var workzone = function workzone(services) {
|
|||||||
var publicationId = destKey.attr('data-publication-id');
|
var publicationId = destKey.attr('data-publication-id');
|
||||||
var exposeName = (0, _jquery2.default)('#expose_list').val();
|
var exposeName = (0, _jquery2.default)('#expose_list').val();
|
||||||
var assetsContainer = destKey.find('.expose_item_deployed');
|
var assetsContainer = destKey.find('.expose_item_deployed');
|
||||||
|
|
||||||
|
if (publicationId !== undefined) {
|
||||||
assetsContainer.empty().addClass('loading');
|
assetsContainer.empty().addClass('loading');
|
||||||
|
|
||||||
_jquery2.default.ajax({
|
_jquery2.default.ajax({
|
||||||
@@ -11146,6 +11163,7 @@ var workzone = function workzone(services) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function fix() {
|
function fix() {
|
||||||
_jquery2.default.ajax({
|
_jquery2.default.ajax({
|
||||||
@@ -63419,7 +63437,7 @@ var addToBasket = function addToBasket(services) {
|
|||||||
var dbId = $el.data('db-id');
|
var dbId = $el.data('db-id');
|
||||||
var recordId = $el.data('record-id');
|
var recordId = $el.data('record-id');
|
||||||
appEvents.emit('workzone.doAddToBasket', {
|
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();
|
event.preventDefault();
|
||||||
closePreview();
|
closePreview();
|
||||||
}).on('dblclick', '.open-preview-action', function (event) {
|
}).on('dblclick', '.open-preview-action', function (event) {
|
||||||
var $el = (0, _jquery2.default)(event.currentTarget);
|
var $element = (0, _jquery2.default)(event.currentTarget);
|
||||||
// env, pos, contId, reload
|
openPreview($element);
|
||||||
var reload = $el.data('reload') === true ? true : false;
|
|
||||||
_openPreview(event.currentTarget, $el.data('kind'), $el.data('position'), $el.data('id'), $el.data('kind'));
|
|
||||||
}).on('click', '.to-open-preview-action', function (event) {
|
}).on('click', '.to-open-preview-action', function (event) {
|
||||||
event.preventDefault();
|
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) {
|
$previewContainer.on('click', '.preview-navigate-action', function (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@@ -65481,7 +65498,18 @@ var previewRecordService = function previewRecordService(services) {
|
|||||||
(0, _jquery2.default)('#PREVIEWBOX img.record.zoomable').draggable();
|
(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 = "<img src='/assets/common/images/icons/basket_validation.png' title='' width='24' class='btn-image' style='width:24px;height: 24px;'/>";
|
||||||
|
} else if (data.containerType === 'push') {
|
||||||
|
basketIcon = "<img src='/assets/common/images/icons/basket_push.png' title='' width='24' class='btn-image' style='width:24px;height: 24px;'/>";
|
||||||
|
} else {
|
||||||
|
basketIcon = "<img src='/assets/common/images/icons/basket.png' title='' width='24' class='btn-image' style='width:24px;height: 24px;'/>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(0, _jquery2.default)('#SPANTITLE').empty().append(basketIcon + data.title);
|
||||||
(0, _jquery2.default)('#PREVIEWTITLE_COLLLOGO').empty().append(data.collection_logo);
|
(0, _jquery2.default)('#PREVIEWTITLE_COLLLOGO').empty().append(data.collection_logo);
|
||||||
(0, _jquery2.default)('#PREVIEWTITLE_COLLNAME').empty().append(data.databox_name + ' / ' + data.collection_name);
|
(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);
|
(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() {
|
function closePreview() {
|
||||||
options.open = false;
|
options.open = false;
|
||||||
if (activeThumbnailFrame !== false) {
|
if (activeThumbnailFrame !== false) {
|
||||||
|
@@ -10230,15 +10230,15 @@ var workzone = function workzone(services) {
|
|||||||
selection: new _selectable2.default(services, (0, _jquery2.default)('#baskets'), { selector: '.CHIM' }),
|
selection: new _selectable2.default(services, (0, _jquery2.default)('#baskets'), { selector: '.CHIM' }),
|
||||||
refresh: refreshBaskets,
|
refresh: refreshBaskets,
|
||||||
addElementToBasket: function addElementToBasket(options) {
|
addElementToBasket: function addElementToBasket(options) {
|
||||||
var sbas_id = options.sbas_id,
|
var dbId = options.dbId,
|
||||||
record_id = options.record_id,
|
recordId = options.recordId,
|
||||||
event = options.event,
|
event = options.event,
|
||||||
singleSelection = options.singleSelection;
|
singleSelection = options.singleSelection;
|
||||||
|
|
||||||
singleSelection = !!singleSelection || false;
|
singleSelection = !!singleSelection || false;
|
||||||
|
|
||||||
if ((0, _jquery2.default)('#baskets .SSTT.active').length === 1) {
|
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 {
|
} else {
|
||||||
humane.info(localeService.t('noActiveBasket'));
|
humane.info(localeService.t('noActiveBasket'));
|
||||||
}
|
}
|
||||||
@@ -10397,9 +10397,9 @@ var workzone = function workzone(services) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function WorkZoneElementRemover(el, confirm) {
|
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 = {};
|
var buttons = {};
|
||||||
|
|
||||||
buttons[localeService.t('valider')] = function () {
|
buttons[localeService.t('valider')] = function () {
|
||||||
@@ -10411,9 +10411,18 @@ var workzone = function workzone(services) {
|
|||||||
(0, _jquery2.default)('#DIALOG-baskets').dialog('close').remove();
|
(0, _jquery2.default)('#DIALOG-baskets').dialog('close').remove();
|
||||||
};
|
};
|
||||||
|
|
||||||
var texte = '<p>' + localeService.t('confirmRemoveReg') + '</p><div><input type="checkbox" onchange="prodApp.appEvents.emit(\'workzone.doRemoveWarning\', this);"/>' + localeService.t('hideMessage') + '</div>';
|
var texte = '';
|
||||||
|
var title = '';
|
||||||
|
if ((0, _jquery2.default)(el).hasClass('groupings')) {
|
||||||
|
texte = '<p>' + localeService.t('confirmRemoveReg') + '</p><div><input type="checkbox" onchange="prodApp.appEvents.emit(\'workzone.doRemoveWarning\', this);"/>' + localeService.t('hideMessage') + '</div>';
|
||||||
|
title = localeService.t('removeTitle');
|
||||||
|
} else {
|
||||||
|
texte = '<p>' + localeService.t('confirmRemoveFeedBack') + '</p>';
|
||||||
|
title = localeService.t('removeRecordFeedbackTitle');
|
||||||
|
}
|
||||||
|
|
||||||
(0, _jquery2.default)('body').append('<div id="DIALOG-baskets"></div>');
|
(0, _jquery2.default)('body').append('<div id="DIALOG-baskets"></div>');
|
||||||
(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,
|
autoOpen: false,
|
||||||
closeOnEscape: true,
|
closeOnEscape: true,
|
||||||
resizable: false,
|
resizable: false,
|
||||||
@@ -10519,7 +10528,9 @@ var workzone = function workzone(services) {
|
|||||||
|
|
||||||
uiactive.addClass('ui-state-focus active');
|
uiactive.addClass('ui-state-focus active');
|
||||||
|
|
||||||
|
// reset selection when opening a basket type
|
||||||
workzoneOptions.selection.empty();
|
workzoneOptions.selection.empty();
|
||||||
|
appEvents.emit('broadcast.workzoneResultSelection', { asArray: [], serialized: "" });
|
||||||
|
|
||||||
getContent(uiactive);
|
getContent(uiactive);
|
||||||
},
|
},
|
||||||
@@ -10884,6 +10895,10 @@ var workzone = function workzone(services) {
|
|||||||
left: -20
|
left: -20
|
||||||
},
|
},
|
||||||
start: function start(event, ui) {
|
start: function start(event, ui) {
|
||||||
|
if (!(0, _jquery2.default)(this).hasClass('selected')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
var baskets = (0, _jquery2.default)('#baskets');
|
var baskets = (0, _jquery2.default)('#baskets');
|
||||||
baskets.append('<div class="top-scroller"></div>' + '<div class="bottom-scroller"></div>');
|
baskets.append('<div class="top-scroller"></div>' + '<div class="bottom-scroller"></div>');
|
||||||
(0, _jquery2.default)('.bottom-scroller', baskets).bind('mousemove', function () {
|
(0, _jquery2.default)('.bottom-scroller', baskets).bind('mousemove', function () {
|
||||||
@@ -10898,9 +10913,9 @@ var workzone = function workzone(services) {
|
|||||||
},
|
},
|
||||||
drag: function drag(event, ui) {
|
drag: function drag(event, ui) {
|
||||||
if (appCommons.utilsModule.is_ctrl_key(event) || (0, _jquery2.default)(this).closest('.content').hasClass('grouping')) {
|
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 {
|
} 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) {
|
switch (action) {
|
||||||
case 'CHU2CHU':
|
case 'CHU2CHU':
|
||||||
if (!appCommons.utilsModule.is_ctrl_key(event)) act = 'MOV';
|
if (appCommons.utilsModule.is_ctrl_key(event)) act = 'MOV';
|
||||||
break;
|
break;
|
||||||
case 'IMGT2REG':
|
case 'IMGT2REG':
|
||||||
case 'CHU2REG':
|
case 'CHU2REG':
|
||||||
@@ -11125,6 +11140,8 @@ var workzone = function workzone(services) {
|
|||||||
var publicationId = destKey.attr('data-publication-id');
|
var publicationId = destKey.attr('data-publication-id');
|
||||||
var exposeName = (0, _jquery2.default)('#expose_list').val();
|
var exposeName = (0, _jquery2.default)('#expose_list').val();
|
||||||
var assetsContainer = destKey.find('.expose_item_deployed');
|
var assetsContainer = destKey.find('.expose_item_deployed');
|
||||||
|
|
||||||
|
if (publicationId !== undefined) {
|
||||||
assetsContainer.empty().addClass('loading');
|
assetsContainer.empty().addClass('loading');
|
||||||
|
|
||||||
_jquery2.default.ajax({
|
_jquery2.default.ajax({
|
||||||
@@ -11146,6 +11163,7 @@ var workzone = function workzone(services) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function fix() {
|
function fix() {
|
||||||
_jquery2.default.ajax({
|
_jquery2.default.ajax({
|
||||||
@@ -63419,7 +63437,7 @@ var addToBasket = function addToBasket(services) {
|
|||||||
var dbId = $el.data('db-id');
|
var dbId = $el.data('db-id');
|
||||||
var recordId = $el.data('record-id');
|
var recordId = $el.data('record-id');
|
||||||
appEvents.emit('workzone.doAddToBasket', {
|
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();
|
event.preventDefault();
|
||||||
closePreview();
|
closePreview();
|
||||||
}).on('dblclick', '.open-preview-action', function (event) {
|
}).on('dblclick', '.open-preview-action', function (event) {
|
||||||
var $el = (0, _jquery2.default)(event.currentTarget);
|
var $element = (0, _jquery2.default)(event.currentTarget);
|
||||||
// env, pos, contId, reload
|
openPreview($element);
|
||||||
var reload = $el.data('reload') === true ? true : false;
|
|
||||||
_openPreview(event.currentTarget, $el.data('kind'), $el.data('position'), $el.data('id'), $el.data('kind'));
|
|
||||||
}).on('click', '.to-open-preview-action', function (event) {
|
}).on('click', '.to-open-preview-action', function (event) {
|
||||||
event.preventDefault();
|
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) {
|
$previewContainer.on('click', '.preview-navigate-action', function (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@@ -65481,7 +65498,18 @@ var previewRecordService = function previewRecordService(services) {
|
|||||||
(0, _jquery2.default)('#PREVIEWBOX img.record.zoomable').draggable();
|
(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 = "<img src='/assets/common/images/icons/basket_validation.png' title='' width='24' class='btn-image' style='width:24px;height: 24px;'/>";
|
||||||
|
} else if (data.containerType === 'push') {
|
||||||
|
basketIcon = "<img src='/assets/common/images/icons/basket_push.png' title='' width='24' class='btn-image' style='width:24px;height: 24px;'/>";
|
||||||
|
} else {
|
||||||
|
basketIcon = "<img src='/assets/common/images/icons/basket.png' title='' width='24' class='btn-image' style='width:24px;height: 24px;'/>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(0, _jquery2.default)('#SPANTITLE').empty().append(basketIcon + data.title);
|
||||||
(0, _jquery2.default)('#PREVIEWTITLE_COLLLOGO').empty().append(data.collection_logo);
|
(0, _jquery2.default)('#PREVIEWTITLE_COLLLOGO').empty().append(data.collection_logo);
|
||||||
(0, _jquery2.default)('#PREVIEWTITLE_COLLNAME').empty().append(data.databox_name + ' / ' + data.collection_name);
|
(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);
|
(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() {
|
function closePreview() {
|
||||||
options.open = false;
|
options.open = false;
|
||||||
if (activeThumbnailFrame !== false) {
|
if (activeThumbnailFrame !== false) {
|
||||||
|
@@ -11,7 +11,7 @@ const addToBasket = (services) => {
|
|||||||
let dbId = $el.data('db-id');
|
let dbId = $el.data('db-id');
|
||||||
let recordId = $el.data('record-id');
|
let recordId = $el.data('record-id');
|
||||||
appEvents.emit('workzone.doAddToBasket', {
|
appEvents.emit('workzone.doAddToBasket', {
|
||||||
dbId, recordId, event: event.currentTarget
|
dbId, recordId, event: event.currentTarget, singleSelection: true
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@@ -81,20 +81,14 @@ const previewRecordService = services => {
|
|||||||
closePreview();
|
closePreview();
|
||||||
})
|
})
|
||||||
.on('dblclick', '.open-preview-action', event => {
|
.on('dblclick', '.open-preview-action', event => {
|
||||||
let $el = $(event.currentTarget);
|
let $element = $(event.currentTarget);
|
||||||
// env, pos, contId, reload
|
openPreview($element);
|
||||||
let reload = $el.data('reload') === true ? true : false;
|
|
||||||
_openPreview(
|
|
||||||
event.currentTarget,
|
|
||||||
$el.data('kind'),
|
|
||||||
$el.data('position'),
|
|
||||||
$el.data('id'),
|
|
||||||
$el.data('kind')
|
|
||||||
);
|
|
||||||
})
|
})
|
||||||
.on('click', '.to-open-preview-action', event => {
|
.on('click', '.to-open-preview-action', event => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
$( '.open-preview-action' ).trigger( "dblclick" );
|
let $element = $(event.currentTarget);
|
||||||
|
openPreview($element);
|
||||||
})
|
})
|
||||||
;
|
;
|
||||||
$previewContainer
|
$previewContainer
|
||||||
@@ -387,7 +381,18 @@ const previewRecordService = services => {
|
|||||||
$('#PREVIEWBOX img.record.zoomable').draggable();
|
$('#PREVIEWBOX img.record.zoomable').draggable();
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#SPANTITLE').empty().append(data.title);
|
let basketIcon = '';
|
||||||
|
if (data.containerType !== null ) {
|
||||||
|
if (data.containerType === 'feedback') {
|
||||||
|
basketIcon = "<img src='/assets/common/images/icons/basket_validation.png' title='' width='24' class='btn-image' style='width:24px;height: 24px;'/>";
|
||||||
|
} else if (data.containerType === 'push') {
|
||||||
|
basketIcon = "<img src='/assets/common/images/icons/basket_push.png' title='' width='24' class='btn-image' style='width:24px;height: 24px;'/>";
|
||||||
|
} else {
|
||||||
|
basketIcon = "<img src='/assets/common/images/icons/basket.png' title='' width='24' class='btn-image' style='width:24px;height: 24px;'/>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#SPANTITLE').empty().append(basketIcon + data.title);
|
||||||
$('#PREVIEWTITLE_COLLLOGO')
|
$('#PREVIEWTITLE_COLLLOGO')
|
||||||
.empty()
|
.empty()
|
||||||
.append(data.collection_logo);
|
.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() {
|
function closePreview() {
|
||||||
options.open = false;
|
options.open = false;
|
||||||
if (activeThumbnailFrame !== false) {
|
if (activeThumbnailFrame !== false) {
|
||||||
|
@@ -214,11 +214,11 @@ const workzone = (services) => {
|
|||||||
selection: new Selectable(services, $('#baskets'), {selector: '.CHIM'}),
|
selection: new Selectable(services, $('#baskets'), {selector: '.CHIM'}),
|
||||||
refresh: refreshBaskets,
|
refresh: refreshBaskets,
|
||||||
addElementToBasket: function (options) {
|
addElementToBasket: function (options) {
|
||||||
let {sbas_id, record_id, event, singleSelection} = options;
|
let {dbId, recordId, event, singleSelection} = options;
|
||||||
singleSelection = !!singleSelection || false;
|
singleSelection = !!singleSelection || false;
|
||||||
|
|
||||||
if ($('#baskets .SSTT.active').length === 1) {
|
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 {
|
} else {
|
||||||
humane.info(localeService.t('noActiveBasket'));
|
humane.info(localeService.t('noActiveBasket'));
|
||||||
}
|
}
|
||||||
@@ -373,9 +373,9 @@ const workzone = (services) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function WorkZoneElementRemover(el, confirm) {
|
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 = {};
|
var buttons = {};
|
||||||
|
|
||||||
buttons[localeService.t('valider')] = function () {
|
buttons[localeService.t('valider')] = function () {
|
||||||
@@ -387,9 +387,18 @@ const workzone = (services) => {
|
|||||||
$('#DIALOG-baskets').dialog('close').remove();
|
$('#DIALOG-baskets').dialog('close').remove();
|
||||||
};
|
};
|
||||||
|
|
||||||
var texte = '<p>' + localeService.t('confirmRemoveReg') + '</p><div><input type="checkbox" onchange="prodApp.appEvents.emit(\'workzone.doRemoveWarning\', this);"/>' + localeService.t('hideMessage') + '</div>';
|
var texte = '';
|
||||||
|
var title = '';
|
||||||
|
if ($(el).hasClass('groupings')) {
|
||||||
|
texte = '<p>' + localeService.t('confirmRemoveReg') + '</p><div><input type="checkbox" onchange="prodApp.appEvents.emit(\'workzone.doRemoveWarning\', this);"/>' + localeService.t('hideMessage') + '</div>';
|
||||||
|
title = localeService.t('removeTitle');
|
||||||
|
} else {
|
||||||
|
texte = '<p>' + localeService.t('confirmRemoveFeedBack') + '</p>';
|
||||||
|
title = localeService.t('removeRecordFeedbackTitle');
|
||||||
|
}
|
||||||
|
|
||||||
$('body').append('<div id="DIALOG-baskets"></div>');
|
$('body').append('<div id="DIALOG-baskets"></div>');
|
||||||
$('#DIALOG-baskets').attr('title', localeService.t('removeTitle'))
|
$('#DIALOG-baskets').attr('title', title)
|
||||||
.empty()
|
.empty()
|
||||||
.append(texte)
|
.append(texte)
|
||||||
.dialog({
|
.dialog({
|
||||||
@@ -500,7 +509,9 @@ const workzone = (services) => {
|
|||||||
|
|
||||||
uiactive.addClass('ui-state-focus active');
|
uiactive.addClass('ui-state-focus active');
|
||||||
|
|
||||||
|
// reset selection when opening a basket type
|
||||||
workzoneOptions.selection.empty();
|
workzoneOptions.selection.empty();
|
||||||
|
appEvents.emit('broadcast.workzoneResultSelection', {asArray:[], serialized:""});
|
||||||
|
|
||||||
getContent(uiactive);
|
getContent(uiactive);
|
||||||
|
|
||||||
@@ -874,6 +885,10 @@ const workzone = (services) => {
|
|||||||
left: -20
|
left: -20
|
||||||
},
|
},
|
||||||
start: function (event, ui) {
|
start: function (event, ui) {
|
||||||
|
if (!$(this).hasClass('selected')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
var baskets = $('#baskets');
|
var baskets = $('#baskets');
|
||||||
baskets.append('<div class="top-scroller"></div>' +
|
baskets.append('<div class="top-scroller"></div>' +
|
||||||
'<div class="bottom-scroller"></div>');
|
'<div class="bottom-scroller"></div>');
|
||||||
@@ -891,11 +906,10 @@ const workzone = (services) => {
|
|||||||
},
|
},
|
||||||
drag: function (event, ui) {
|
drag: function (event, ui) {
|
||||||
if (appCommons.utilsModule.is_ctrl_key(event) || $(this).closest('.content').hasClass('grouping')) {
|
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 {
|
} else {
|
||||||
$('#dragDropCursor div').empty().append(workzoneOptions.selection.length());
|
$('#dragDropCursor div').empty().append('+ ' + workzoneOptions.selection.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
window.workzoneOptions = workzoneOptions;
|
window.workzoneOptions = workzoneOptions;
|
||||||
@@ -1043,7 +1057,7 @@ const workzone = (services) => {
|
|||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case 'CHU2CHU' :
|
case 'CHU2CHU' :
|
||||||
if (!appCommons.utilsModule.is_ctrl_key(event)) act = 'MOV';
|
if (appCommons.utilsModule.is_ctrl_key(event)) act = 'MOV';
|
||||||
break;
|
break;
|
||||||
case 'IMGT2REG':
|
case 'IMGT2REG':
|
||||||
case 'CHU2REG' :
|
case 'CHU2REG' :
|
||||||
@@ -1129,6 +1143,8 @@ const workzone = (services) => {
|
|||||||
let publicationId = destKey.attr('data-publication-id');
|
let publicationId = destKey.attr('data-publication-id');
|
||||||
let exposeName = $('#expose_list').val();
|
let exposeName = $('#expose_list').val();
|
||||||
let assetsContainer = destKey.find('.expose_item_deployed');
|
let assetsContainer = destKey.find('.expose_item_deployed');
|
||||||
|
|
||||||
|
if (publicationId !== undefined) {
|
||||||
assetsContainer.empty().addClass('loading');
|
assetsContainer.empty().addClass('loading');
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
@@ -1151,6 +1167,7 @@ const workzone = (services) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function fix() {
|
function fix() {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
|
@@ -331,6 +331,15 @@ workers:
|
|||||||
user: guest
|
user: guest
|
||||||
password: guest
|
password: guest
|
||||||
vhost: /
|
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:
|
externalservice:
|
||||||
ginger:
|
ginger:
|
||||||
|
@@ -119,6 +119,7 @@ services:
|
|||||||
- redis
|
- redis
|
||||||
- rabbitmq
|
- rabbitmq
|
||||||
- elasticsearch
|
- elasticsearch
|
||||||
|
- phraseanet
|
||||||
environment:
|
environment:
|
||||||
- PHRASEANET_PROJECT_NAME
|
- PHRASEANET_PROJECT_NAME
|
||||||
- PHRASEANET_TRUSTED_PROXIES
|
- PHRASEANET_TRUSTED_PROXIES
|
||||||
@@ -135,7 +136,30 @@ services:
|
|||||||
- LC_CTYPE=C.UTF-8
|
- LC_CTYPE=C.UTF-8
|
||||||
- LC_TIME=C.UTF-8
|
- LC_TIME=C.UTF-8
|
||||||
- LC_NAME=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:
|
volumes:
|
||||||
- ${PHRASEANET_CONFIG_DIR}:/var/alchemy/Phraseanet/config:rw
|
- ${PHRASEANET_CONFIG_DIR}:/var/alchemy/Phraseanet/config:rw
|
||||||
- ${PHRASEANET_LOGS_DIR}:/var/alchemy/Phraseanet/logs:rw
|
- ${PHRASEANET_LOGS_DIR}:/var/alchemy/Phraseanet/logs:rw
|
||||||
|
@@ -38,7 +38,7 @@ if [ -f "$FILE" ]; then
|
|||||||
if [[ $PHRASEANET_SMTP_ENABLED && $PHRASEANET_SMTP_ENABLED = true ]]; 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-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-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-host $PHRASEANET_SMTP_HOST
|
||||||
bin/setup system:config set registry.email.smtp-port $PHRASEANET_SMTP_PORT
|
bin/setup system:config set registry.email.smtp-port $PHRASEANET_SMTP_PORT
|
||||||
bin/setup system:config set registry.email.smtp-user $PHRASEANET_SMTP_USER
|
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
|
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
|
bin/console user:password --user_id=$PHRASEANET_ADMIN_ACCOUNT_ID --password $PHRASEANET_ADMIN_ACCOUNT_PASSWORD -y
|
||||||
fi
|
fi
|
||||||
|
echo `date +"%Y-%m-%d %H:%M:%S"` " - config/configuration.yml update by Phraseanet entrypoint.sh Finished !"
|
||||||
else
|
else
|
||||||
echo "$FILE doesn't exist, entering setup..."
|
echo "$FILE doesn't exist, entering setup..."
|
||||||
|
|
||||||
@@ -62,6 +62,7 @@ else
|
|||||||
datas
|
datas
|
||||||
|
|
||||||
runuser app -c docker/phraseanet/auto-install.sh
|
runuser app -c docker/phraseanet/auto-install.sh
|
||||||
|
echo `date +"%Y-%m-%d %H:%M:%S"` " - End of Phraseanet Installation"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ${XDEBUG_ENABLED} == "1" ]; then
|
if [ ${XDEBUG_ENABLED} == "1" ]; then
|
||||||
@@ -70,7 +71,8 @@ if [ ${XDEBUG_ENABLED} == "1" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
./docker/phraseanet/plugins/console init
|
./docker/phraseanet/plugins/console init
|
||||||
#rm -Rf cache/
|
rm -Rf cache/*
|
||||||
|
chmod 600 config/configuration.yml
|
||||||
|
|
||||||
chown -R app:app \
|
chown -R app:app \
|
||||||
cache \
|
cache \
|
||||||
@@ -84,6 +86,7 @@ if [ -d "plugins/" ];then
|
|||||||
chown -R app:app plugins;
|
chown -R app:app plugins;
|
||||||
fi
|
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 $@
|
bash -e docker-php-entrypoint $@
|
||||||
|
@@ -15,4 +15,47 @@ if [ ${XDEBUG_ENABLED} == "1" ]; then
|
|||||||
docker-php-ext-enable xdebug
|
docker-php-ext-enable xdebug
|
||||||
fi
|
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=\".*/<domain=\"resource\" name=\"temporary-path\" value=\"\\$IMAGEMAGICK_POLICY_TEMPORARY_PATH\" \/\>/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 -- $@
|
runuser -u app -- $@
|
||||||
|
@@ -13,6 +13,7 @@ use Alchemy\Phrasea\Controller\Controller;
|
|||||||
use Alchemy\Phrasea\Controller\RecordsRequest;
|
use Alchemy\Phrasea\Controller\RecordsRequest;
|
||||||
use Alchemy\Phrasea\Model\Entities\Basket;
|
use Alchemy\Phrasea\Model\Entities\Basket;
|
||||||
use Alchemy\Phrasea\Model\Entities\BasketElement;
|
use Alchemy\Phrasea\Model\Entities\BasketElement;
|
||||||
|
use Alchemy\Phrasea\Model\Entities\ValidationData;
|
||||||
use Alchemy\Phrasea\Model\Manipulator\BasketManipulator;
|
use Alchemy\Phrasea\Model\Manipulator\BasketManipulator;
|
||||||
use Alchemy\Phrasea\Model\Repositories\BasketElementRepository;
|
use Alchemy\Phrasea\Model\Repositories\BasketElementRepository;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
@@ -251,8 +252,25 @@ class BasketController extends Controller
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$basket_element->getBasket()->removeElement($basket_element);
|
$oldBasket = $basket_element->getBasket();
|
||||||
|
|
||||||
|
$oldBasket->removeElement($basket_element);
|
||||||
$basket->addElement($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++;
|
$n++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -59,9 +59,12 @@ class LanguageController
|
|||||||
'feed_require_fields' => $translator->trans('Vous n\'avez pas rempli tous les champ requis'),
|
'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'),
|
'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'),
|
'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 !'),
|
'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 !'),
|
'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.'),
|
'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'),
|
'advsearch_title' => $translator->trans('phraseanet::recherche avancee'),
|
||||||
'bask_rename' => $translator->trans('panier:: renommer le panier'),
|
'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'),
|
'reg_wrong_sbas' => $translator->trans('panier:: Un reportage ne peux recevoir que des elements provenants de la base ou il est enregistre'),
|
||||||
|
@@ -146,7 +146,7 @@ class PushController extends Controller
|
|||||||
|
|
||||||
$this->getDataboxLogger($element->getDatabox())->log(
|
$this->getDataboxLogger($element->getDatabox())->log(
|
||||||
$element,
|
$element,
|
||||||
Session_Logger::EVENT_VALIDATE,
|
Session_Logger::EVENT_PUSH,
|
||||||
$user_receiver->getId(),
|
$user_receiver->getId(),
|
||||||
''
|
''
|
||||||
);
|
);
|
||||||
@@ -386,7 +386,7 @@ class PushController extends Controller
|
|||||||
|
|
||||||
$this->getDataboxLogger($basketElement->getRecord($this->app)->getDatabox())->log(
|
$this->getDataboxLogger($basketElement->getRecord($this->app)->getDatabox())->log(
|
||||||
$basketElement->getRecord($this->app),
|
$basketElement->getRecord($this->app),
|
||||||
Session_Logger::EVENT_PUSH,
|
Session_Logger::EVENT_VALIDATE,
|
||||||
$participantUser->getId(),
|
$participantUser->getId(),
|
||||||
''
|
''
|
||||||
);
|
);
|
||||||
|
@@ -103,6 +103,18 @@ class RecordController extends Controller
|
|||||||
$recordTitle = htmlspecialchars($record->get_title());
|
$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([
|
return $this->app->json([
|
||||||
"desc" => $this->render('prod/preview/caption.html.twig', [
|
"desc" => $this->render('prod/preview/caption.html.twig', [
|
||||||
'record' => $record,
|
'record' => $record,
|
||||||
@@ -131,6 +143,7 @@ class RecordController extends Controller
|
|||||||
]),
|
]),
|
||||||
"pos" => $record->getNumber(),
|
"pos" => $record->getNumber(),
|
||||||
"title" => $recordTitle,
|
"title" => $recordTitle,
|
||||||
|
"containerType" => $containerType,
|
||||||
"databox_name" => $record->getDatabox()->get_dbname(),
|
"databox_name" => $record->getDatabox()->get_dbname(),
|
||||||
"collection_name" => $record->getCollection()->get_name(),
|
"collection_name" => $record->getCollection()->get_name(),
|
||||||
"collection_logo" => $record->getCollection()->getLogo($record->getBaseId(), $this->app),
|
"collection_logo" => $record->getCollection()->getLogo($record->getBaseId(), $this->app),
|
||||||
|
@@ -319,7 +319,8 @@ class LegacyRecordRepository implements RecordRepository
|
|||||||
. $userFilter
|
. $userFilter
|
||||||
. " WHERE g.rid_parent IN ( :storyIds )\n"
|
. " WHERE g.rid_parent IN ( :storyIds )\n"
|
||||||
. " ORDER BY g.rid_parent, g.ord ASC\n"
|
. " ORDER BY g.rid_parent, g.ord ASC\n"
|
||||||
. ") r\n"
|
. ") r \n"
|
||||||
|
. "ORDER BY r.rid_parent, r.ord ASC\n"
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -6,6 +6,7 @@ use Alchemy\Phrasea\Command\Command;
|
|||||||
use Alchemy\Phrasea\WorkerManager\Queue\AMQPConnection;
|
use Alchemy\Phrasea\WorkerManager\Queue\AMQPConnection;
|
||||||
use Alchemy\Phrasea\WorkerManager\Queue\MessageHandler;
|
use Alchemy\Phrasea\WorkerManager\Queue\MessageHandler;
|
||||||
use Alchemy\Phrasea\WorkerManager\Worker\WorkerInvoker;
|
use Alchemy\Phrasea\WorkerManager\Worker\WorkerInvoker;
|
||||||
|
use Doctrine\DBAL\Connection;
|
||||||
use PhpAmqpLib\Channel\AMQPChannel;
|
use PhpAmqpLib\Channel\AMQPChannel;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
@@ -45,7 +46,7 @@ class WorkerExecuteCommand extends Command
|
|||||||
if ($channel == null) {
|
if ($channel == null) {
|
||||||
$output->writeln("Can't connect to rabbit, check configuration!");
|
$output->writeln("Can't connect to rabbit, check configuration!");
|
||||||
|
|
||||||
return;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
$serverConnection->declareExchange();
|
$serverConnection->declareExchange();
|
||||||
@@ -56,7 +57,7 @@ class WorkerExecuteCommand extends Command
|
|||||||
if ($input->getOption('max-processes') != null && $maxProcesses == 0) {
|
if ($input->getOption('max-processes') != null && $maxProcesses == 0) {
|
||||||
$output->writeln('<error>Invalid max-processes option.Need an integer</error>');
|
$output->writeln('<error>Invalid max-processes option.Need an integer</error>');
|
||||||
|
|
||||||
return;
|
return 1;
|
||||||
} elseif($maxProcesses) {
|
} elseif($maxProcesses) {
|
||||||
$workerInvoker->setMaxProcessPoolValue($maxProcesses);
|
$workerInvoker->setMaxProcessPoolValue($maxProcesses);
|
||||||
}
|
}
|
||||||
@@ -69,8 +70,26 @@ class WorkerExecuteCommand extends Command
|
|||||||
$messageHandler = $this->container['alchemy_worker.message.handler'];
|
$messageHandler = $this->container['alchemy_worker.message.handler'];
|
||||||
$messageHandler->consume($serverConnection, $workerInvoker, $argQueueName, $maxProcesses);
|
$messageHandler->consume($serverConnection, $workerInvoker, $argQueueName, $maxProcesses);
|
||||||
|
|
||||||
|
/** @var Connection $dbConnection */
|
||||||
|
$dbConnection = $this->container['orm.em']->getConnection();
|
||||||
|
|
||||||
while (count($channel->callbacks)) {
|
while (count($channel->callbacks)) {
|
||||||
$output->writeln("[*] Waiting for messages. To exit press CTRL+C");
|
$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();
|
$channel->wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -13,19 +13,22 @@ use Alchemy\Phrasea\WorkerManager\Form\WorkerConfigurationType;
|
|||||||
use Alchemy\Phrasea\WorkerManager\Form\WorkerFtpType;
|
use Alchemy\Phrasea\WorkerManager\Form\WorkerFtpType;
|
||||||
use Alchemy\Phrasea\WorkerManager\Form\WorkerPullAssetsType;
|
use Alchemy\Phrasea\WorkerManager\Form\WorkerPullAssetsType;
|
||||||
use Alchemy\Phrasea\WorkerManager\Form\WorkerSearchengineType;
|
use Alchemy\Phrasea\WorkerManager\Form\WorkerSearchengineType;
|
||||||
|
use Alchemy\Phrasea\WorkerManager\Form\WorkerValidationReminderType;
|
||||||
use Alchemy\Phrasea\WorkerManager\Queue\AMQPConnection;
|
use Alchemy\Phrasea\WorkerManager\Queue\AMQPConnection;
|
||||||
use Alchemy\Phrasea\WorkerManager\Queue\MessagePublisher;
|
use Alchemy\Phrasea\WorkerManager\Queue\MessagePublisher;
|
||||||
|
use Doctrine\ORM\OptimisticLockException;
|
||||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||||
|
use Symfony\Component\Form\Form;
|
||||||
use Symfony\Component\Form\FormInterface;
|
use Symfony\Component\Form\FormInterface;
|
||||||
|
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||||
|
|
||||||
|
|
||||||
class AdminConfigurationController extends Controller
|
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 */
|
/** @var WorkerRunningJobRepository $repoWorker */
|
||||||
$repoWorker = $app['repo.worker-running-job'];
|
$repoWorker = $app['repo.worker-running-job'];
|
||||||
|
|
||||||
@@ -39,9 +42,10 @@ class AdminConfigurationController extends Controller
|
|||||||
$workerRunningJob = $repoWorker->findByStatus($filterStatus);
|
$workerRunningJob = $repoWorker->findByStatus($filterStatus);
|
||||||
|
|
||||||
return $this->render('admin/worker-manager/index.html.twig', [
|
return $this->render('admin/worker-manager/index.html.twig', [
|
||||||
'isConnected' => ($serverConnection->getChannel() != null) ? true : false,
|
'isConnected' => $this->getAMQPConnection()->getChannel() != null,
|
||||||
'workerRunningJob' => $workerRunningJob,
|
'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)
|
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);
|
$form->handleRequest($request);
|
||||||
|
|
||||||
if ($form->isValid()) {
|
if ($form->isValid()) {
|
||||||
// save config in file
|
// save config
|
||||||
$app['conf']->set(['workers', 'retry_queue'], $form->getData());
|
// 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);
|
$queues = array_intersect_key(AMQPConnection::$defaultQueues, $retryQueueConfig);
|
||||||
$retryQueuesToReset = array_intersect_key(AMQPConnection::$defaultRetryQueues, array_flip($queues));
|
$retryQueuesToReset = array_intersect_key(AMQPConnection::$defaultRetryQueues, array_flip($queues));
|
||||||
|
|
||||||
/** @var AMQPConnection $serverConnection */
|
|
||||||
$serverConnection = $this->app['alchemy_worker.amqp.connection'];
|
|
||||||
// change the queue TTL
|
// change the queue TTL
|
||||||
$serverConnection->reinitializeQueue($retryQueuesToReset);
|
$AMQPConnection->reinitializeQueue($retryQueuesToReset);
|
||||||
$serverConnection->reinitializeQueue(AMQPConnection::$defaultDelayedQueues);
|
$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', [
|
return $this->render('admin/worker-manager/worker_configuration.html.twig', [
|
||||||
@@ -84,7 +116,7 @@ class AdminConfigurationController extends Controller
|
|||||||
/** @var WorkerRunningJobRepository $repoWorker */
|
/** @var WorkerRunningJobRepository $repoWorker */
|
||||||
$repoWorker = $app['repo.worker-running-job'];
|
$repoWorker = $app['repo.worker-running-job'];
|
||||||
|
|
||||||
$reload = ($request->query->get('reload')) == 1 ? true : false ;
|
$reload = ($request->query->get('reload') == 1);
|
||||||
|
|
||||||
$workerRunningJob = [];
|
$workerRunningJob = [];
|
||||||
$filterStatus = [];
|
$filterStatus = [];
|
||||||
@@ -114,8 +146,8 @@ class AdminConfigurationController extends Controller
|
|||||||
/**
|
/**
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @param $workerId
|
* @param $workerId
|
||||||
* @return \Symfony\Component\HttpFoundation\JsonResponse
|
* @return JsonResponse
|
||||||
* @throws \Doctrine\ORM\OptimisticLockException
|
* @throws OptimisticLockException
|
||||||
*/
|
*/
|
||||||
public function changeStatusAction(Request $request, $workerId)
|
public function changeStatusAction(Request $request, $workerId)
|
||||||
{
|
{
|
||||||
@@ -140,13 +172,11 @@ class AdminConfigurationController extends Controller
|
|||||||
|
|
||||||
public function queueMonitorAction(PhraseaApplication $app, Request $request)
|
public function queueMonitorAction(PhraseaApplication $app, Request $request)
|
||||||
{
|
{
|
||||||
$reload = ($request->query->get('reload')) == 1 ? true : false ;
|
$reload = ($request->query->get('reload') == 1);
|
||||||
|
|
||||||
/** @var AMQPConnection $serverConnection */
|
$this->getAMQPConnection()->getChannel();
|
||||||
$serverConnection = $app['alchemy_worker.amqp.connection'];
|
$this->getAMQPConnection()->declareExchange();
|
||||||
$serverConnection->getChannel();
|
$queuesStatus = $this->getAMQPConnection()->getQueuesStatus();
|
||||||
$serverConnection->declareExchange();
|
|
||||||
$queuesStatus = $serverConnection->getQueuesStatus();
|
|
||||||
|
|
||||||
return $this->render('admin/worker-manager/worker_queue_monitor.html.twig', [
|
return $this->render('admin/worker-manager/worker_queue_monitor.html.twig', [
|
||||||
'queuesStatus' => $queuesStatus,
|
'queuesStatus' => $queuesStatus,
|
||||||
@@ -162,10 +192,20 @@ class AdminConfigurationController extends Controller
|
|||||||
return $this->app->json(['success' => false]);
|
return $this->app->json(['success' => false]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var AMQPConnection $serverConnection */
|
$this->getAMQPConnection()->reinitializeQueue([$queueName]);
|
||||||
$serverConnection = $this->app['alchemy_worker.amqp.connection'];
|
|
||||||
|
|
||||||
$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]);
|
return $this->app->json(['success' => true]);
|
||||||
}
|
}
|
||||||
@@ -176,7 +216,8 @@ class AdminConfigurationController extends Controller
|
|||||||
$repoWorker = $app['repo.worker-running-job'];
|
$repoWorker = $app['repo.worker-running-job'];
|
||||||
$repoWorker->truncateWorkerTable();
|
$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)
|
public function deleteFinishedAction(PhraseaApplication $app)
|
||||||
@@ -185,7 +226,8 @@ class AdminConfigurationController extends Controller
|
|||||||
$repoWorker = $app['repo.worker-running-job'];
|
$repoWorker = $app['repo.worker-running-job'];
|
||||||
$repoWorker->deleteFinishedWorks();
|
$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)
|
public function searchengineAction(PhraseaApplication $app, Request $request)
|
||||||
@@ -201,7 +243,8 @@ class AdminConfigurationController extends Controller
|
|||||||
|
|
||||||
$this->getDispatcher()->dispatch(WorkerEvents::POPULATE_INDEX, new PopulateIndexEvent($populateInfo));
|
$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', [
|
return $this->render('admin/worker-manager/worker_searchengine.html.twig', [
|
||||||
@@ -211,14 +254,12 @@ class AdminConfigurationController extends Controller
|
|||||||
|
|
||||||
public function subviewAction()
|
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()
|
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)
|
public function ftpAction(PhraseaApplication $app, Request $request)
|
||||||
@@ -231,7 +272,8 @@ class AdminConfigurationController extends Controller
|
|||||||
// save new ftp config
|
// save new ftp config
|
||||||
$app['conf']->set(['workers', 'ftp'], array_merge($ftpConfig, $form->getData()));
|
$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', [
|
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)
|
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') {
|
$form->handleRequest($request);
|
||||||
$reminderInterval = (int)$request->request->get('worker_reminder_interval');
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
|
$data = $form->getData();
|
||||||
/** @var AMQPConnection $serverConnection */
|
switch($data['act']) {
|
||||||
$serverConnection = $this->app['alchemy_worker.amqp.connection'];
|
case 'save' : // save the form content (settings)
|
||||||
$serverConnection->setQueue(MessagePublisher::VALIDATION_REMINDER_QUEUE);
|
unset($data['act']); // don't save this
|
||||||
|
// the interval was displayed in sec. in form, convert back to msec
|
||||||
// save the period interval in second
|
if(isset($data['ttl_retry'])) {
|
||||||
$app['conf']->set(['workers', 'validationReminder', 'interval'], $reminderInterval);
|
$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
|
// reinitialize the validation reminder queues
|
||||||
$serverConnection->reinitializeQueue([MessagePublisher::VALIDATION_REMINDER_QUEUE]);
|
$this->getAMQPConnection()->setQueue(MessagePublisher::VALIDATION_REMINDER_TYPE);
|
||||||
$this->app['alchemy_worker.message.publisher']->initializeLoopQueue(MessagePublisher::VALIDATION_REMINDER_TYPE);
|
$this->getAMQPConnection()->reinitializeQueue([MessagePublisher::VALIDATION_REMINDER_TYPE]);
|
||||||
|
$this->getMessagePublisher()->initializeLoopQueue(MessagePublisher::VALIDATION_REMINDER_TYPE);
|
||||||
return $app->redirectPath('worker_admin');
|
break;
|
||||||
|
case 'stop':
|
||||||
|
$this->getAMQPConnection()->reinitializeQueue([MessagePublisher::VALIDATION_REMINDER_TYPE]);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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', [
|
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)
|
public function pullAssetsAction(PhraseaApplication $app, Request $request)
|
||||||
{
|
{
|
||||||
$pullAssetsConfig = $this->getPullAssetsConfiguration();
|
$config = $this->getConf()->get(['workers', 'pull_assets'], []);
|
||||||
$form = $app->form(new WorkerPullAssetsType(), $pullAssetsConfig);
|
// 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);
|
$form->handleRequest($request);
|
||||||
if ($form->isValid()) {
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
/** @var AMQPConnection $serverConnection */
|
|
||||||
$serverConnection = $this->app['alchemy_worker.amqp.connection'];
|
|
||||||
$serverConnection->setQueue(MessagePublisher::PULL_QUEUE);
|
|
||||||
|
|
||||||
// save new pull config
|
$data = $form->getData();
|
||||||
$app['conf']->set(['workers', 'pull_assets'], array_merge($pullAssetsConfig, $form->getData()));
|
switch($data['act']) {
|
||||||
|
case 'save' : // save the form content (settings) in 2 places
|
||||||
// reinitialize the pull queues
|
$ttl_retry = $data['pullInterval'];
|
||||||
$serverConnection->reinitializeQueue([MessagePublisher::PULL_QUEUE]);
|
unset($data['act'], $data['pullInterval'], $config['pullInterval']);
|
||||||
$this->app['alchemy_worker.message.publisher']->initializeLoopQueue(MessagePublisher::PULL_ASSETS_TYPE);
|
// save most data under workers/pull_assets
|
||||||
|
$app['conf']->set(['workers', 'pull_assets'], array_merge($config, $data));
|
||||||
return $app->redirectPath('worker_admin');
|
// 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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', [
|
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
|
* @return EventDispatcherInterface
|
||||||
*/
|
*/
|
||||||
@@ -333,18 +453,25 @@ class AdminConfigurationController extends Controller
|
|||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getPullAssetsConfiguration()
|
|
||||||
{
|
|
||||||
return $this->app['conf']->get(['workers', 'pull_assets'], []);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getFtpConfiguration()
|
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'];
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -10,7 +10,7 @@ class AssetsCreationFailureEvent extends SfEvent
|
|||||||
private $workerMessage;
|
private $workerMessage;
|
||||||
private $count;
|
private $count;
|
||||||
|
|
||||||
public function __construct($payload, $workerMessage, $count = 2)
|
public function __construct($payload, $workerMessage, $count)
|
||||||
{
|
{
|
||||||
$this->payload = $payload;
|
$this->payload = $payload;
|
||||||
$this->workerMessage = $workerMessage;
|
$this->workerMessage = $workerMessage;
|
||||||
|
@@ -12,7 +12,7 @@ class AssetsCreationRecordFailureEvent extends SfEvent
|
|||||||
private $count;
|
private $count;
|
||||||
private $workerJobId;
|
private $workerJobId;
|
||||||
|
|
||||||
public function __construct($payload, $workerMessage = '', $count = 2, $workerJobId = 0)
|
public function __construct($payload, $workerMessage, $count, $workerJobId )
|
||||||
{
|
{
|
||||||
$this->payload = $payload;
|
$this->payload = $payload;
|
||||||
$this->workerMessage = $workerMessage;
|
$this->workerMessage = $workerMessage;
|
||||||
|
@@ -13,7 +13,7 @@ class ExportMailFailureEvent extends SfEvent
|
|||||||
private $workerMessage;
|
private $workerMessage;
|
||||||
private $count;
|
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->emitterUserId = $emitterUserId;
|
||||||
$this->tokenValue = $tokenValue;
|
$this->tokenValue = $tokenValue;
|
||||||
|
@@ -14,7 +14,7 @@ class PopulateIndexFailureEvent extends SfEvent
|
|||||||
private $count;
|
private $count;
|
||||||
private $workerJobId;
|
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->host = $host;
|
||||||
$this->port = $port;
|
$this->port = $port;
|
||||||
|
@@ -12,7 +12,7 @@ class SubdefinitionCreationFailureEvent extends RecordEvent
|
|||||||
private $count;
|
private $count;
|
||||||
private $workerJobId;
|
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);
|
parent::__construct($record);
|
||||||
|
|
||||||
|
@@ -11,7 +11,7 @@ class WebhookDeliverFailureEvent extends SfEvent
|
|||||||
private $count;
|
private $count;
|
||||||
private $deleveryId;
|
private $deleveryId;
|
||||||
|
|
||||||
public function __construct($webhookEventId, $workerMessage, $count = 2, $deleveryId = null)
|
public function __construct($webhookEventId, $workerMessage, $count, $deleveryId = null)
|
||||||
{
|
{
|
||||||
$this->webhookEventId = $webhookEventId;
|
$this->webhookEventId = $webhookEventId;
|
||||||
$this->workerMessage = $workerMessage;
|
$this->workerMessage = $workerMessage;
|
||||||
|
68
lib/Alchemy/Phrasea/WorkerManager/Form/QueueSettingsType.php
Normal file
68
lib/Alchemy/Phrasea/WorkerManager/Form/QueueSettingsType.php
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Alchemy\Phrasea\WorkerManager\Form;
|
||||||
|
|
||||||
|
use Alchemy\Phrasea\WorkerManager\Queue\AMQPConnection;
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
|
||||||
|
class QueueSettingsType extends AbstractType
|
||||||
|
{
|
||||||
|
private $AMQPConnection;
|
||||||
|
private $baseQueueName;
|
||||||
|
|
||||||
|
public function __construct(AMQPConnection $AMQPConnection, string $baseQueueName)
|
||||||
|
{
|
||||||
|
$this->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';
|
||||||
|
}
|
||||||
|
}
|
@@ -2,48 +2,43 @@
|
|||||||
|
|
||||||
namespace Alchemy\Phrasea\WorkerManager\Form;
|
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\AbstractType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\FormType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
|
||||||
class WorkerConfigurationType extends AbstractType
|
class WorkerConfigurationType extends AbstractType
|
||||||
{
|
{
|
||||||
|
private $AMQPConnection;
|
||||||
|
|
||||||
|
public function __construct(AMQPConnection $AMQPConnection)
|
||||||
|
{
|
||||||
|
$this->AMQPConnection = $AMQPConnection;
|
||||||
|
}
|
||||||
|
|
||||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
{
|
{
|
||||||
parent::buildForm($builder, $options);
|
parent::buildForm($builder, $options);
|
||||||
|
|
||||||
$builder
|
$g = $builder->create("queues", FormType::class, ['attr'=>['class'=>'form-row']]);
|
||||||
->add(MessagePublisher::ASSETS_INGEST_TYPE, 'text', [
|
|
||||||
'label' => 'admin::workermanager:tab:workerconfig: Ingest retry delay in ms'
|
foreach($this->AMQPConnection->getBaseQueueNames() as $baseQueueName) {
|
||||||
])
|
if($this->AMQPConnection->hasRetryQueue($baseQueueName)
|
||||||
->add(MessagePublisher::CREATE_RECORD_TYPE, 'text', [
|
|| $this->AMQPConnection->hasLoopQueue($baseQueueName)
|
||||||
'label' => 'admin::workermanager:tab:workerconfig: Create record retry delay in ms'
|
|| $this->AMQPConnection->hasDelayedQueue($baseQueueName)
|
||||||
])
|
) {
|
||||||
->add(MessagePublisher::SUBDEF_CREATION_TYPE, 'text', [
|
$f = new QueueSettingsType($this->AMQPConnection, $baseQueueName);
|
||||||
'label' => 'admin::workermanager:tab:workerconfig: Subdefinition retry delay in ms'
|
$g->add($baseQueueName, $f, ['attr' => ['class' => 'norow'], 'block_name' => 'queue']);
|
||||||
])
|
}
|
||||||
->add(MessagePublisher::WRITE_METADATAS_TYPE, 'text', [
|
}
|
||||||
'label' => 'admin::workermanager:tab:workerconfig: Metadatas retry delay in ms'
|
|
||||||
])
|
$builder->add($g);
|
||||||
->add(MessagePublisher::WEBHOOK_TYPE, 'text', [
|
|
||||||
'label' => 'admin::workermanager:tab:workerconfig: Webhook retry delay in ms'
|
$builder->add("boutton::appliquer", SubmitType::class,
|
||||||
])
|
[
|
||||||
->add(MessagePublisher::EXPORT_MAIL_TYPE, 'text', [
|
'label' => "boutton::appliquer"
|
||||||
'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'
|
|
||||||
])
|
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getName()
|
public function getName()
|
||||||
|
@@ -3,6 +3,7 @@
|
|||||||
namespace Alchemy\Phrasea\WorkerManager\Form;
|
namespace Alchemy\Phrasea\WorkerManager\Form;
|
||||||
|
|
||||||
use Symfony\Component\Form\AbstractType;
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
|
||||||
class WorkerFtpType extends AbstractType
|
class WorkerFtpType extends AbstractType
|
||||||
@@ -12,19 +13,19 @@ class WorkerFtpType extends AbstractType
|
|||||||
parent::buildForm($builder, $options);
|
parent::buildForm($builder, $options);
|
||||||
|
|
||||||
$builder
|
$builder
|
||||||
->add('proxy', 'text', [
|
->add('proxy', TextType::class, [
|
||||||
'label' => 'admin::workermanager:tab:ftp: Proxy',
|
'label' => 'admin::workermanager:tab:ftp: Proxy',
|
||||||
'required' => false
|
'required' => false
|
||||||
])
|
])
|
||||||
->add('proxyPort', 'text', [
|
->add('proxyPort', TextType::class, [
|
||||||
'label' => 'admin::workermanager:tab:ftp: Proxy port',
|
'label' => 'admin::workermanager:tab:ftp: Proxy port',
|
||||||
'required' => false
|
'required' => false
|
||||||
])
|
])
|
||||||
->add('proxyUser', 'text', [
|
->add('proxyUser', TextType::class, [
|
||||||
'label' => 'admin::workermanager:tab:ftp: Proxy user',
|
'label' => 'admin::workermanager:tab:ftp: Proxy user',
|
||||||
'required' => false
|
'required' => false
|
||||||
])
|
])
|
||||||
->add('proxyPassword', 'text', [
|
->add('proxyPassword', TextType::class, [
|
||||||
'label' => 'admin::workermanager:tab:ftp: Proxy password',
|
'label' => 'admin::workermanager:tab:ftp: Proxy password',
|
||||||
'required' => false
|
'required' => false
|
||||||
])
|
])
|
||||||
|
@@ -3,6 +3,9 @@
|
|||||||
namespace Alchemy\Phrasea\WorkerManager\Form;
|
namespace Alchemy\Phrasea\WorkerManager\Form;
|
||||||
|
|
||||||
use Symfony\Component\Form\AbstractType;
|
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;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
|
||||||
class WorkerPullAssetsType extends AbstractType
|
class WorkerPullAssetsType extends AbstractType
|
||||||
@@ -11,20 +14,36 @@ class WorkerPullAssetsType extends AbstractType
|
|||||||
{
|
{
|
||||||
parent::buildForm($builder, $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
|
$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'
|
'label' => 'admin::workermanager:tab:pullassets: Uploader api base uri'
|
||||||
])
|
])
|
||||||
->add('clientSecret', 'text', [
|
->add('clientSecret', TextType::class, [
|
||||||
'label' => 'admin::workermanager:tab:pullassets: Client secret'
|
'label' => 'admin::workermanager:tab:pullassets: Client secret'
|
||||||
])
|
])
|
||||||
->add('clientId', 'text', [
|
->add('clientId', TextType::class, [
|
||||||
'label' => 'admin::workermanager:tab:pullassets: Client ID'
|
'label' => 'admin::workermanager:tab:pullassets: Client ID'
|
||||||
])
|
])
|
||||||
->add('pullInterval', 'text', [
|
->add('pullInterval', TextType::class, [
|
||||||
'label' => 'admin::workermanager:tab:pullassets: Fetching interval in second'
|
'label' => 'admin::workermanager:tab:pullassets: Fetching interval in second'
|
||||||
])
|
]);
|
||||||
;
|
|
||||||
|
$builder
|
||||||
|
->add("boutton::appliquer", SubmitType::class, [
|
||||||
|
'label' => "boutton::appliquer",
|
||||||
|
'attr' => ['value' => 'save']
|
||||||
|
]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getName()
|
public function getName()
|
||||||
|
@@ -3,6 +3,8 @@
|
|||||||
namespace Alchemy\Phrasea\WorkerManager\Form;
|
namespace Alchemy\Phrasea\WorkerManager\Form;
|
||||||
|
|
||||||
use Symfony\Component\Form\AbstractType;
|
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\Form\FormBuilderInterface;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
|
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
|
||||||
use Symfony\Component\Validator\Constraints\NotBlank;
|
use Symfony\Component\Validator\Constraints\NotBlank;
|
||||||
@@ -15,18 +17,18 @@ class WorkerSearchengineType extends AbstractType
|
|||||||
parent::buildForm($builder, $options);
|
parent::buildForm($builder, $options);
|
||||||
|
|
||||||
$builder
|
$builder
|
||||||
->add('host', 'text', [
|
->add('host', TextType::class, [
|
||||||
'label' => 'admin::workermanager:tab:searchengine: Elasticsearch server host',
|
'label' => 'admin::workermanager:tab:searchengine: Elasticsearch server host',
|
||||||
'constraints' => new NotBlank(),
|
'constraints' => new NotBlank(),
|
||||||
])
|
])
|
||||||
->add('port', 'integer', [
|
->add('port', IntegerType::class, [
|
||||||
'label' => 'admin::workermanager:tab:searchengine: Elasticsearch service port',
|
'label' => 'admin::workermanager:tab:searchengine: Elasticsearch service port',
|
||||||
'constraints' => [
|
'constraints' => [
|
||||||
new Range(['min' => 1, 'max' => 65535]),
|
new Range(['min' => 1, 'max' => 65535]),
|
||||||
new NotBlank()
|
new NotBlank()
|
||||||
]
|
]
|
||||||
])
|
])
|
||||||
->add('indexName', 'text', [
|
->add('indexName', TextType::class, [
|
||||||
'label' => 'admin::workermanager:tab:searchengine: Elasticsearch index name',
|
'label' => 'admin::workermanager:tab:searchengine: Elasticsearch index name',
|
||||||
'constraints' => new NotBlank(),
|
'constraints' => new NotBlank(),
|
||||||
'attr' =>['data-class'=>'inline']
|
'attr' =>['data-class'=>'inline']
|
||||||
|
@@ -0,0 +1,68 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Alchemy\Phrasea\WorkerManager\Form;
|
||||||
|
|
||||||
|
use Alchemy\Phrasea\WorkerManager\Queue\AMQPConnection;
|
||||||
|
use Alchemy\Phrasea\WorkerManager\Queue\MessagePublisher;
|
||||||
|
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 WorkerValidationReminderType extends AbstractType
|
||||||
|
{
|
||||||
|
private $AMQPConnection;
|
||||||
|
|
||||||
|
public function __construct(AMQPConnection $AMQPConnection)
|
||||||
|
{
|
||||||
|
$this->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';
|
||||||
|
// }
|
||||||
|
}
|
@@ -45,61 +45,81 @@ class ControllerServiceProvider implements ControllerProviderInterface, ServiceP
|
|||||||
$firewall->requireRight(\ACL::TASKMANAGER);
|
$firewall->requireRight(\ACL::TASKMANAGER);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/** @uses AdminConfigurationController::indexAction */
|
||||||
$controllers->match('/', 'controller.worker.admin.configuration:indexAction')
|
$controllers->match('/', 'controller.worker.admin.configuration:indexAction')
|
||||||
->method('GET')
|
->method('GET')
|
||||||
->bind('worker_admin');
|
->bind('worker_admin');
|
||||||
|
|
||||||
|
/** @uses AdminConfigurationController::configurationAction */
|
||||||
$controllers->match('/configuration', 'controller.worker.admin.configuration:configurationAction')
|
$controllers->match('/configuration', 'controller.worker.admin.configuration:configurationAction')
|
||||||
->method('GET|POST')
|
->method('GET|POST')
|
||||||
->bind('worker_admin_configuration');
|
->bind('worker_admin_configuration');
|
||||||
|
|
||||||
|
/** @uses AdminConfigurationController::infoAction */
|
||||||
$controllers->match('/info', 'controller.worker.admin.configuration:infoAction')
|
$controllers->match('/info', 'controller.worker.admin.configuration:infoAction')
|
||||||
->method('GET')
|
->method('GET')
|
||||||
->bind('worker_admin_info');
|
->bind('worker_admin_info');
|
||||||
|
|
||||||
|
/** @uses AdminConfigurationController::truncateTableAction */
|
||||||
$controllers->match('/truncate', 'controller.worker.admin.configuration:truncateTableAction')
|
$controllers->match('/truncate', 'controller.worker.admin.configuration:truncateTableAction')
|
||||||
->method('POST')
|
->method('POST')
|
||||||
->bind('worker_admin_truncate');
|
->bind('worker_admin_truncate');
|
||||||
|
|
||||||
|
/** @uses AdminConfigurationController::deleteFinishedAction */
|
||||||
$controllers->match('/delete-finished', 'controller.worker.admin.configuration:deleteFinishedAction')
|
$controllers->match('/delete-finished', 'controller.worker.admin.configuration:deleteFinishedAction')
|
||||||
->method('POST')
|
->method('POST')
|
||||||
->bind('worker_admin_delete_finished');
|
->bind('worker_admin_delete_finished');
|
||||||
|
|
||||||
|
/** @uses AdminConfigurationController::searchengineAction */
|
||||||
$controllers->match('/searchengine', 'controller.worker.admin.configuration:searchengineAction')
|
$controllers->match('/searchengine', 'controller.worker.admin.configuration:searchengineAction')
|
||||||
->method('GET|POST')
|
->method('GET|POST')
|
||||||
->bind('worker_admin_searchengine');
|
->bind('worker_admin_searchengine');
|
||||||
|
|
||||||
|
/** @uses AdminConfigurationController::subviewAction */
|
||||||
$controllers->match('/subview', 'controller.worker.admin.configuration:subviewAction')
|
$controllers->match('/subview', 'controller.worker.admin.configuration:subviewAction')
|
||||||
->method('GET|POST')
|
->method('GET|POST')
|
||||||
->bind('worker_admin_subview');
|
->bind('worker_admin_subview');
|
||||||
|
|
||||||
|
/** @uses AdminConfigurationController::metadataAction */
|
||||||
$controllers->match('/metadata', 'controller.worker.admin.configuration:metadataAction')
|
$controllers->match('/metadata', 'controller.worker.admin.configuration:metadataAction')
|
||||||
->method('GET|POST')
|
->method('GET|POST')
|
||||||
->bind('worker_admin_metadata');
|
->bind('worker_admin_metadata');
|
||||||
|
|
||||||
|
/** @uses AdminConfigurationController::ftpAction */
|
||||||
$controllers->match('/ftp', 'controller.worker.admin.configuration:ftpAction')
|
$controllers->match('/ftp', 'controller.worker.admin.configuration:ftpAction')
|
||||||
->method('GET|POST')
|
->method('GET|POST')
|
||||||
->bind('worker_admin_ftp');
|
->bind('worker_admin_ftp');
|
||||||
|
|
||||||
|
/** @uses AdminConfigurationController::populateStatusAction */
|
||||||
$controllers->get('/populate-status', 'controller.worker.admin.configuration:populateStatusAction')
|
$controllers->get('/populate-status', 'controller.worker.admin.configuration:populateStatusAction')
|
||||||
->bind('worker_admin_populate_status');
|
->bind('worker_admin_populate_status');
|
||||||
|
|
||||||
|
/** @uses AdminConfigurationController::pullAssetsAction */
|
||||||
$controllers->match('/pull-assets', 'controller.worker.admin.configuration:pullAssetsAction')
|
$controllers->match('/pull-assets', 'controller.worker.admin.configuration:pullAssetsAction')
|
||||||
->method('GET|POST')
|
->method('GET|POST')
|
||||||
->bind('worker_admin_pullAssets');
|
->bind('worker_admin_pullAssets');
|
||||||
|
|
||||||
|
/** @uses AdminConfigurationController::validationReminderAction */
|
||||||
$controllers->match('/validation-reminder', 'controller.worker.admin.configuration:validationReminderAction')
|
$controllers->match('/validation-reminder', 'controller.worker.admin.configuration:validationReminderAction')
|
||||||
->method('GET|POST')
|
->method('GET|POST')
|
||||||
->bind('worker_admin_validationReminder');
|
->bind('worker_admin_validationReminder');
|
||||||
|
|
||||||
|
/** @uses AdminConfigurationController::queueMonitorAction */
|
||||||
$controllers->match('/queue-monitor', 'controller.worker.admin.configuration:queueMonitorAction')
|
$controllers->match('/queue-monitor', 'controller.worker.admin.configuration:queueMonitorAction')
|
||||||
->method('GET')
|
->method('GET')
|
||||||
->bind('worker_admin_queue_monitor');
|
->bind('worker_admin_queue_monitor');
|
||||||
|
|
||||||
|
/** @uses AdminConfigurationController::purgeQueueAction */
|
||||||
$controllers->match('/purge-queue', 'controller.worker.admin.configuration:purgeQueueAction')
|
$controllers->match('/purge-queue', 'controller.worker.admin.configuration:purgeQueueAction')
|
||||||
->method('POST')
|
->method('POST')
|
||||||
->bind('worker_admin_purge_queue');
|
->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')
|
$controllers->match('/{workerId}/change-status', 'controller.worker.admin.configuration:changeStatusAction')
|
||||||
->method('POST')
|
->method('POST')
|
||||||
->assert('workerId', '\d+')
|
->assert('workerId', '\d+')
|
||||||
|
@@ -3,6 +3,7 @@
|
|||||||
namespace Alchemy\Phrasea\WorkerManager\Queue;
|
namespace Alchemy\Phrasea\WorkerManager\Queue;
|
||||||
|
|
||||||
use Alchemy\Phrasea\Core\Configuration\PropertyAccess;
|
use Alchemy\Phrasea\Core\Configuration\PropertyAccess;
|
||||||
|
use Exception;
|
||||||
use PhpAmqpLib\Channel\AMQPChannel;
|
use PhpAmqpLib\Channel\AMQPChannel;
|
||||||
use PhpAmqpLib\Connection\AMQPStreamConnection;
|
use PhpAmqpLib\Connection\AMQPStreamConnection;
|
||||||
use PhpAmqpLib\Wire\AMQPTable;
|
use PhpAmqpLib\Wire\AMQPTable;
|
||||||
@@ -20,67 +21,109 @@ class AMQPConnection
|
|||||||
private $hostConfig;
|
private $hostConfig;
|
||||||
private $conf;
|
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
|
// default message TTL in retry queue in millisecond
|
||||||
const RETRY_DELAY = 10000;
|
const DEFAULT_RETRY_DELAY_VALUE = 10000;
|
||||||
|
|
||||||
// default message TTL for some retry queue , 3 minute
|
|
||||||
const RETRY_LARGE_DELAY = 180000;
|
|
||||||
|
|
||||||
// default message TTL in delayed queue in millisecond
|
// 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)
|
public function __construct(PropertyAccess $conf)
|
||||||
{
|
{
|
||||||
@@ -94,6 +137,165 @@ class AMQPConnection
|
|||||||
|
|
||||||
$this->hostConfig = $conf->get(['workers', 'queue', 'worker-queue'], $defaultConfiguration);
|
$this->hostConfig = $conf->get(['workers', 'queue', 'worker-queue'], $defaultConfiguration);
|
||||||
$this->conf = $conf;
|
$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()
|
public function getConnection()
|
||||||
@@ -108,8 +310,9 @@ class AMQPConnection
|
|||||||
$this->hostConfig['vhost']
|
$this->hostConfig['vhost']
|
||||||
);
|
);
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
}
|
||||||
|
catch (Exception $e) {
|
||||||
|
// no-op
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,7 +330,8 @@ class AMQPConnection
|
|||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
return $this->channel;
|
return $this->channel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -156,106 +360,191 @@ class AMQPConnection
|
|||||||
$this->declareExchange();
|
$this->declareExchange();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset(self::$defaultRetryQueues[$queueName])) {
|
$queue = $this->queues[$queueName];
|
||||||
$this->channel->queue_declare($queueName, false, true, false, false, false, new AMQPTable([
|
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-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
|
'x-dead-letter-routing-key' => $queue['RetryQ'] // the routing key to apply to this 'dead' message
|
||||||
]));
|
]);
|
||||||
|
$this->setQueue($queue['RetryQ']);
|
||||||
$this->channel->queue_bind($queueName, self::ALCHEMY_EXCHANGE, $queueName);
|
break;
|
||||||
|
case self::BASE_QUEUE_WITH_LOOP:
|
||||||
// declare also the corresponding retry queue
|
$this->queue_declare_and_bind($queueName, self::ALCHEMY_EXCHANGE, [
|
||||||
// use this to delay the delivery of a message to the alchemy-exchange
|
'x-dead-letter-exchange' => self::RETRY_ALCHEMY_EXCHANGE, // the exchange to which republish a 'dead' message
|
||||||
$this->channel->queue_declare(self::$defaultRetryQueues[$queueName], false, true, false, false, false, new AMQPTable([
|
'x-dead-letter-routing-key' => $queue['LoopQ'] // the routing key to apply to this 'dead' message
|
||||||
'x-dead-letter-exchange' => AMQPConnection::ALCHEMY_EXCHANGE,
|
]);
|
||||||
'x-dead-letter-routing-key' => $queueName,
|
$this->setQueue($queue['LoopQ']);
|
||||||
'x-message-ttl' => $this->getTtlRetryPerRouting($queueName)
|
break;
|
||||||
]));
|
case self::LOOP_QUEUE:
|
||||||
|
case self::RETRY_QUEUE:
|
||||||
$this->channel->queue_bind(self::$defaultRetryQueues[$queueName], AMQPConnection::RETRY_ALCHEMY_EXCHANGE, self::$defaultRetryQueues[$queueName]);
|
$this->queue_declare_and_bind($queueName, self::RETRY_ALCHEMY_EXCHANGE, [
|
||||||
|
'x-dead-letter-exchange' => self::ALCHEMY_EXCHANGE,
|
||||||
} elseif (in_array($queueName, self::$defaultRetryQueues)) {
|
'x-dead-letter-routing-key' => $queue['BaseQ'],
|
||||||
// if it's a retry queue
|
'x-message-ttl' => (int)$this->queues[$queue['BaseQ']]['settings'][self::TTL_RETRY]
|
||||||
$routing = array_search($queueName, AMQPConnection::$defaultRetryQueues);
|
]);
|
||||||
$this->channel->queue_declare($queueName, false, true, false, false, false, new AMQPTable([
|
break;
|
||||||
'x-dead-letter-exchange' => AMQPConnection::ALCHEMY_EXCHANGE,
|
case self::DELAYED_QUEUE:
|
||||||
'x-dead-letter-routing-key' => $routing,
|
$this->queue_declare_and_bind($queueName, self::RETRY_ALCHEMY_EXCHANGE, [
|
||||||
'x-message-ttl' => $this->getTtlRetryPerRouting($routing)
|
'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]
|
||||||
$this->channel->queue_bind($queueName, AMQPConnection::RETRY_ALCHEMY_EXCHANGE, $queueName);
|
]);
|
||||||
} elseif (in_array($queueName, self::$defaultFailedQueues)) {
|
break;
|
||||||
// if it's a failed queue
|
case self::FAILED_QUEUE:
|
||||||
$this->channel->queue_declare($queueName, false, true, false, false, false);
|
$this->queue_declare_and_bind($queueName, self::RETRY_ALCHEMY_EXCHANGE);
|
||||||
|
break;
|
||||||
$this->channel->queue_bind($queueName, AMQPConnection::RETRY_ALCHEMY_EXCHANGE, $queueName);
|
case self::BASE_QUEUE:
|
||||||
} elseif (in_array($queueName, self::$defaultDelayedQueues)) {
|
$this->queue_declare_and_bind($queueName, self::ALCHEMY_EXCHANGE);
|
||||||
// if it's a delayed queue
|
break;
|
||||||
$routing = array_search($queueName, AMQPConnection::$defaultDelayedQueues);
|
default:
|
||||||
$this->channel->queue_declare($queueName, false, true, false, false, false, new AMQPTable([
|
throw new Exception(sprintf('undefined q type "%s', $queueName));
|
||||||
'x-dead-letter-exchange' => AMQPConnection::ALCHEMY_EXCHANGE,
|
break;
|
||||||
'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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->channel;
|
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)) {
|
if (!isset($this->channel)) {
|
||||||
$this->getChannel();
|
$this->getChannel();
|
||||||
$this->declareExchange();
|
$this->declareExchange();
|
||||||
}
|
}
|
||||||
foreach ($queuNames as $queuName) {
|
|
||||||
if (in_array($queuName, self::$defaultQueues)) {
|
foreach ($queueNames as $queueName) {
|
||||||
$this->channel->queue_purge($queuName);
|
// re-inject conf values (some may have changed)
|
||||||
} else {
|
$settings = $this->conf->get(['workers', 'queues', $queueName], []);
|
||||||
$this->channel->queue_delete($queuName);
|
if(array_key_exists($queueName, $this->queues)) {
|
||||||
|
$this->queues[$queueName]['settings'] = array_merge($this->queues[$queueName]['settings'], $settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset(self::$defaultRetryQueues[$queuName])) {
|
if(array_key_exists($queueName, self::MESSAGES)) {
|
||||||
$this->channel->queue_delete(self::$defaultRetryQueues[$queuName]);
|
// 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
|
* Get queueName, messageCount, consumerCount of queues
|
||||||
* @return array
|
* @return array
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function getQueuesStatus()
|
public function getQueuesStatus()
|
||||||
{
|
{
|
||||||
$queuesList = array_merge(
|
|
||||||
array_values(self::$defaultQueues),
|
|
||||||
array_values(self::$defaultDelayedQueues),
|
|
||||||
array_values(self::$defaultRetryQueues),
|
|
||||||
array_values(self::$defaultFailedQueues)
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->getChannel();
|
$this->getChannel();
|
||||||
$queuesStatus = [];
|
$queuesStatus = [];
|
||||||
|
|
||||||
foreach ($queuesList as $queue) {
|
foreach($this->queues as $name => $queue) {
|
||||||
$this->setQueue($queue);
|
|
||||||
list($queueName, $messageCount, $consumerCount) = $this->channel->queue_declare($queue, true);
|
|
||||||
|
|
||||||
$status['queueName'] = $queueName;
|
$this->setQueue($name); // todo : BASE_QUEUE_WITH_RETRY will set both BASE and RETRY Q, so we should skip one of 2
|
||||||
$status['messageCount'] = $messageCount;
|
|
||||||
$status['consumerCount'] = $consumerCount;
|
|
||||||
|
|
||||||
$queuesStatus[] = $status;
|
$this->getConnection();
|
||||||
unset($status);
|
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;
|
return $queuesStatus;
|
||||||
}
|
}
|
||||||
@@ -265,58 +554,4 @@ class AMQPConnection
|
|||||||
$this->channel->close();
|
$this->channel->close();
|
||||||
$this->connection->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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -4,6 +4,7 @@ namespace Alchemy\Phrasea\WorkerManager\Queue;
|
|||||||
|
|
||||||
use Alchemy\Phrasea\WorkerManager\Worker\ProcessPool;
|
use Alchemy\Phrasea\WorkerManager\Worker\ProcessPool;
|
||||||
use Alchemy\Phrasea\WorkerManager\Worker\WorkerInvoker;
|
use Alchemy\Phrasea\WorkerManager\Worker\WorkerInvoker;
|
||||||
|
use Exception;
|
||||||
use PhpAmqpLib\Channel\AMQPChannel;
|
use PhpAmqpLib\Channel\AMQPChannel;
|
||||||
use PhpAmqpLib\Message\AMQPMessage;
|
use PhpAmqpLib\Message\AMQPMessage;
|
||||||
use PhpAmqpLib\Wire\AMQPTable;
|
use PhpAmqpLib\Wire\AMQPTable;
|
||||||
@@ -11,8 +12,6 @@ use Ramsey\Uuid\Uuid;
|
|||||||
|
|
||||||
class MessageHandler
|
class MessageHandler
|
||||||
{
|
{
|
||||||
const MAX_OF_TRY = 3;
|
|
||||||
|
|
||||||
private $messagePublisher;
|
private $messagePublisher;
|
||||||
|
|
||||||
public function __construct(MessagePublisher $messagePublisher)
|
public function __construct(MessagePublisher $messagePublisher)
|
||||||
@@ -20,27 +19,37 @@ class MessageHandler
|
|||||||
$this->messagePublisher = $messagePublisher;
|
$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) {
|
if ($channel == null) {
|
||||||
|
// todo : if there is no channel, can we push ?
|
||||||
$this->messagePublisher->pushLog("Can't connect to rabbit, check configuration!", "error");
|
$this->messagePublisher->pushLog("Can't connect to rabbit, check configuration!", "error");
|
||||||
|
|
||||||
return ;
|
return ;
|
||||||
}
|
}
|
||||||
|
|
||||||
$serverConnection->declareExchange();
|
$AMQPConnection->declareExchange();
|
||||||
|
|
||||||
// define consume callbacks
|
// 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);
|
$data = json_decode($message->getBody(), true);
|
||||||
|
|
||||||
$count = 0;
|
$count = 0;
|
||||||
|
|
||||||
|
$headers = null;
|
||||||
if ($message->has('application_headers')) {
|
if ($message->has('application_headers')) {
|
||||||
/** @var AMQPTable $headers */
|
/** @var AMQPTable $headers */
|
||||||
$headers = $message->get('application_headers');
|
$headers = $message->get('application_headers');
|
||||||
@@ -49,9 +58,10 @@ class MessageHandler
|
|||||||
if (isset($headerData['x-death'])) {
|
if (isset($headerData['x-death'])) {
|
||||||
$xDeathHeader = $headerData['x-death'];
|
$xDeathHeader = $headerData['x-death'];
|
||||||
|
|
||||||
|
// todo : if there are more than 1 xdeath ? what is $count ?
|
||||||
foreach ($xDeathHeader as $xdeath) {
|
foreach ($xDeathHeader as $xdeath) {
|
||||||
$queue = $xdeath['queue'];
|
$queue = $xdeath['queue'];
|
||||||
if (!in_array($queue, AMQPConnection::$defaultQueues)) {
|
if (!$AMQPConnection->isBaseQueue($queue)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,51 +71,45 @@ class MessageHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if message is yet executed 3 times, save the unprocessed message in the corresponding failed queues
|
$msgType = $data['message_type'];
|
||||||
if ($count > self::MAX_OF_TRY && !in_array($data['message_type'], AMQPConnection::$defaultLoopTypes)) {
|
|
||||||
$this->messagePublisher->publishFailedMessage($data['payload'], $headers, AMQPConnection::$defaultFailedQueues[$data['message_type']]);
|
|
||||||
|
|
||||||
$logMessage = sprintf("Rabbit message executed 3 times, it's to be saved in %s , payload >>> %s",
|
if($count > $AMQPConnection->getSetting($msgType, AMQPConnection::MAX_RETRY) && !$AMQPConnection->hasLoopQueue($msgType)) {
|
||||||
AMQPConnection::$defaultFailedQueues[$data['message_type']],
|
$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'])
|
json_encode($data['payload'])
|
||||||
);
|
);
|
||||||
$this->messagePublisher->pushLog($logMessage);
|
$publisher->pushLog($logMessage);
|
||||||
|
|
||||||
$channel->basic_ack($message->delivery_info['delivery_tag']);
|
$channel->basic_ack($message->delivery_info['delivery_tag']);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
try {
|
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
|
// make a loop for the loop type
|
||||||
$channel->basic_nack($message->delivery_info['delivery_tag']);
|
$channel->basic_nack($message->delivery_info['delivery_tag']);
|
||||||
} else {
|
} else {
|
||||||
$channel->basic_ack($message->delivery_info['delivery_tag']);
|
$channel->basic_ack($message->delivery_info['delivery_tag']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$oldPayload = $data['payload'];
|
$publisher->pushLog(
|
||||||
$message = $data['message_type'].' to be consumed! >> Payload ::'. json_encode($oldPayload);
|
sprintf('"%s" to be consumed! >> Payload :: %s', $msgType, json_encode($data['payload']))
|
||||||
|
);
|
||||||
$publisher->pushLog($message);
|
}
|
||||||
} catch (\Exception $e) {
|
catch (Exception $e) {
|
||||||
$channel->basic_nack($message->delivery_info['delivery_tag']);
|
$channel->basic_nack($message->delivery_info['delivery_tag']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$prefetchCount = ProcessPool::MAX_PROCESSES;
|
$prefetchCount = $maxProcesses ? $maxProcesses : ProcessPool::MAX_PROCESSES;
|
||||||
|
foreach($AMQPConnection->getBaseQueueNames() as $queueName) {
|
||||||
if ($maxProcesses) {
|
if (!$argQueueNames || in_array($queueName, $argQueueNames)) {
|
||||||
$prefetchCount = $maxProcesses;
|
$this->runConsumer($queueName, $AMQPConnection, $channel, $prefetchCount, $callback);
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -114,9 +118,10 @@ class MessageHandler
|
|||||||
{
|
{
|
||||||
$serverConnection->setQueue($queueName);
|
$serverConnection->setQueue($queueName);
|
||||||
|
|
||||||
|
// todo : remove this if !!! move code to a generic place
|
||||||
// initialize validation reminder when starting consumer
|
// initialize validation reminder when starting consumer
|
||||||
if ($queueName == MessagePublisher::VALIDATION_REMINDER_QUEUE) {
|
if ($queueName == MessagePublisher::VALIDATION_REMINDER_TYPE) {
|
||||||
$serverConnection->reinitializeQueue([MessagePublisher::VALIDATION_REMINDER_QUEUE]);
|
$serverConnection->reinitializeQueue([MessagePublisher::VALIDATION_REMINDER_TYPE]);
|
||||||
$this->messagePublisher->initializeLoopQueue(MessagePublisher::VALIDATION_REMINDER_TYPE);
|
$this->messagePublisher->initializeLoopQueue(MessagePublisher::VALIDATION_REMINDER_TYPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
namespace Alchemy\Phrasea\WorkerManager\Queue;
|
namespace Alchemy\Phrasea\WorkerManager\Queue;
|
||||||
|
|
||||||
|
use DateTime;
|
||||||
|
use DateTimeZone;
|
||||||
use Monolog\Logger;
|
use Monolog\Logger;
|
||||||
use PhpAmqpLib\Message\AMQPMessage;
|
use PhpAmqpLib\Message\AMQPMessage;
|
||||||
use PhpAmqpLib\Wire\AMQPTable;
|
use PhpAmqpLib\Wire\AMQPTable;
|
||||||
@@ -28,107 +30,96 @@ class MessagePublisher
|
|||||||
const MAIN_QUEUE_TYPE = 'mainQueue';
|
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';
|
const NEW_RECORD_MESSAGE = 'newrecord';
|
||||||
|
|
||||||
|
|
||||||
/** @var AMQPConnection $serverConnection */
|
/** @var AMQPConnection $AMQPConnection */
|
||||||
private $serverConnection;
|
private $AMQPConnection;
|
||||||
|
|
||||||
/** @var Logger */
|
/** @var Logger */
|
||||||
private $logger;
|
private $logger;
|
||||||
|
|
||||||
public function __construct(AMQPConnection $serverConnection, LoggerInterface $logger)
|
public function __construct(AMQPConnection $AMQPConnection, LoggerInterface $logger)
|
||||||
{
|
{
|
||||||
$this->serverConnection = $serverConnection;
|
$this->AMQPConnection = $AMQPConnection;
|
||||||
$this->logger = $logger;
|
$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
|
$this->AMQPConnection->getBaseQueueName($queueName); // just to throw an exception if q is undefined
|
||||||
$payload['payload']['published'] = time();
|
|
||||||
$msg = new AMQPMessage(json_encode($payload));
|
|
||||||
$routing = array_search($queueName, AMQPConnection::$defaultRetryQueues);
|
|
||||||
|
|
||||||
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
|
// add a message header information
|
||||||
$headers = new AMQPTable([
|
$headers = new AMQPTable([
|
||||||
'x-death' => [
|
'x-death' => [
|
||||||
[
|
[
|
||||||
'count' => $retryCount,
|
'count' => $retryCount,
|
||||||
'exchange' => AMQPConnection::ALCHEMY_EXCHANGE,
|
'exchange' => AMQPConnection::ALCHEMY_EXCHANGE,
|
||||||
'queue' => $routing,
|
'queue' => $baseQueueName,
|
||||||
'routing-keys' => $routing,
|
'routing-keys' => $baseQueueName,
|
||||||
'reason' => 'rejected', // rejected is sended like nack
|
'reason' => 'rejected', // rejected is sended like nack
|
||||||
'time' => new \DateTime('now', new \DateTimeZone('UTC'))
|
'time' => new DateTime('now', new DateTimeZone('UTC'))
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'worker-message' => $workerMessage
|
'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);
|
$msg->set('application_headers', $headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
$channel = $this->serverConnection->setQueue($queueName);
|
if (is_null( ($channel = $this->AMQPConnection->setQueue($queueName)) )) {
|
||||||
|
|
||||||
if ($channel == null) {
|
|
||||||
$this->pushLog("Can't connect to rabbit, check configuration!", "error");
|
$this->pushLog("Can't connect to rabbit, check configuration!", "error");
|
||||||
|
|
||||||
return true;
|
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);
|
$channel->basic_publish($msg, $exchange, $queueName);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -139,16 +130,16 @@ class MessagePublisher
|
|||||||
$payload = [
|
$payload = [
|
||||||
'message_type' => $type,
|
'message_type' => $type,
|
||||||
'payload' => [
|
'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()
|
public function connectionClose()
|
||||||
{
|
{
|
||||||
$this->serverConnection->connectionClose();
|
$this->AMQPConnection->connectionClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -163,18 +154,4 @@ class MessagePublisher
|
|||||||
call_user_func(array($this->logger, $method), $message, $context);
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -24,6 +24,6 @@ class WebhookPublisher implements WebhookPublisherInterface
|
|||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->messagePublisher->publishMessage($payload, MessagePublisher::WEBHOOK_QUEUE);
|
$this->messagePublisher->publishMessage($payload, MessagePublisher::WEBHOOK_TYPE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -33,7 +33,7 @@ class AssetsIngestSubscriber implements EventSubscriberInterface
|
|||||||
'payload' => array_merge($event->getData(), ['type' => WorkerRunningJob::TYPE_PUSH])
|
'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)
|
public function onAssetsCreationFailure(AssetsCreationFailureEvent $event)
|
||||||
@@ -43,9 +43,9 @@ class AssetsIngestSubscriber implements EventSubscriberInterface
|
|||||||
'payload' => $event->getPayload()
|
'payload' => $event->getPayload()
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->messagePublisher->publishMessage(
|
$this->messagePublisher->publishRetryMessage(
|
||||||
$payload,
|
$payload,
|
||||||
MessagePublisher::RETRY_ASSETS_INGEST_QUEUE,
|
MessagePublisher::ASSETS_INGEST_TYPE,
|
||||||
$event->getCount(),
|
$event->getCount(),
|
||||||
$event->getWorkerMessage()
|
$event->getWorkerMessage()
|
||||||
);
|
);
|
||||||
@@ -84,9 +84,9 @@ class AssetsIngestSubscriber implements EventSubscriberInterface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->messagePublisher->publishMessage(
|
$this->messagePublisher->publishRetryMessage(
|
||||||
$payload,
|
$payload,
|
||||||
MessagePublisher::RETRY_CREATE_RECORD_QUEUE,
|
MessagePublisher::CREATE_RECORD_TYPE, // todo
|
||||||
$event->getCount(),
|
$event->getCount(),
|
||||||
$event->getWorkerMessage()
|
$event->getWorkerMessage()
|
||||||
);
|
);
|
||||||
|
@@ -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)
|
public function onExportMailFailure(ExportMailFailureEvent $event)
|
||||||
@@ -47,9 +47,9 @@ class ExportSubscriber implements EventSubscriberInterface
|
|||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->messagePublisher->publishMessage(
|
$this->messagePublisher->publishRetryMessage(
|
||||||
$payload,
|
$payload,
|
||||||
MessagePublisher::RETRY_EXPORT_QUEUE,
|
MessagePublisher::EXPORT_MAIL_TYPE,
|
||||||
$event->getCount(),
|
$event->getCount(),
|
||||||
$event->getWorkerMessage()
|
$event->getWorkerMessage()
|
||||||
);
|
);
|
||||||
@@ -66,7 +66,7 @@ class ExportSubscriber implements EventSubscriberInterface
|
|||||||
|
|
||||||
$this->messagePublisher->publishMessage(
|
$this->messagePublisher->publishMessage(
|
||||||
$payload,
|
$payload,
|
||||||
MessagePublisher::FTP_QUEUE
|
MessagePublisher::FTP_TYPE
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -36,7 +36,7 @@ class ExposeSubscriber implements EventSubscriberInterface
|
|||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->messagePublisher->publishMessage($payload, MessagePublisher::EXPOSE_UPLOAD_QUEUE);
|
$this->messagePublisher->publishMessage($payload, MessagePublisher::EXPOSE_UPLOAD_TYPE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -5,7 +5,6 @@ namespace Alchemy\Phrasea\WorkerManager\Subscriber;
|
|||||||
use Alchemy\Phrasea\Application;
|
use Alchemy\Phrasea\Application;
|
||||||
use Alchemy\Phrasea\Core\Event\Record\DeletedEvent;
|
use Alchemy\Phrasea\Core\Event\Record\DeletedEvent;
|
||||||
use Alchemy\Phrasea\Core\Event\Record\DeleteEvent;
|
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\RecordEvent;
|
||||||
use Alchemy\Phrasea\Core\Event\Record\RecordEvents;
|
use Alchemy\Phrasea\Core\Event\Record\RecordEvents;
|
||||||
use Alchemy\Phrasea\Core\Event\Record\SubdefinitionCreateEvent;
|
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\CreateRecordWorker;
|
||||||
use Alchemy\Phrasea\WorkerManager\Worker\Factory\WorkerFactoryInterface;
|
use Alchemy\Phrasea\WorkerManager\Worker\Factory\WorkerFactoryInterface;
|
||||||
use Alchemy\Phrasea\WorkerManager\Worker\Resolver\TypeBasedWorkerResolver;
|
use Alchemy\Phrasea\WorkerManager\Worker\Resolver\TypeBasedWorkerResolver;
|
||||||
|
use databox;
|
||||||
|
use Exception;
|
||||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||||
|
|
||||||
class RecordSubscriber implements 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)
|
public function onSubdefinitionCreationFailure(SubdefinitionCreationFailureEvent $event)
|
||||||
@@ -123,14 +124,14 @@ class RecordSubscriber implements EventSubscriberInterface
|
|||||||
$em->persist($workerRunningJob);
|
$em->persist($workerRunningJob);
|
||||||
$em->flush();
|
$em->flush();
|
||||||
$em->commit();
|
$em->commit();
|
||||||
} catch (\Exception $e) {
|
} catch (Exception $e) {
|
||||||
$em->rollback();
|
$em->rollback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->messagePublisher->publishMessage(
|
$this->messagePublisher->publishRetryMessage(
|
||||||
$payload,
|
$payload,
|
||||||
MessagePublisher::RETRY_SUBDEF_QUEUE,
|
MessagePublisher::SUBDEF_CREATION_TYPE,
|
||||||
$event->getCount(),
|
$event->getCount(),
|
||||||
$event->getWorkerMessage()
|
$event->getWorkerMessage()
|
||||||
);
|
);
|
||||||
@@ -170,18 +171,19 @@ class RecordSubscriber implements EventSubscriberInterface
|
|||||||
];
|
];
|
||||||
|
|
||||||
if ($subdef->is_physically_present()) {
|
if ($subdef->is_physically_present()) {
|
||||||
$this->messagePublisher->publishMessage($payload, MessagePublisher::METADATAS_QUEUE);
|
$this->messagePublisher->publishMessage($payload, MessagePublisher::WRITE_METADATAS_TYPE);
|
||||||
} else {
|
}
|
||||||
$logMessage = sprintf("Subdef %s is not physically present! to be passed in the %s ! payload >>> %s",
|
else {
|
||||||
|
$logMessage = sprintf('Subdef "%s" is not physically present! to be passed in the retry q of "%s" ! payload >>> %s',
|
||||||
$subdef->get_name(),
|
$subdef->get_name(),
|
||||||
MessagePublisher::RETRY_METADATAS_QUEUE,
|
MessagePublisher::WRITE_METADATAS_TYPE,
|
||||||
json_encode($payload)
|
json_encode($payload)
|
||||||
);
|
);
|
||||||
$this->messagePublisher->pushLog($logMessage);
|
$this->messagePublisher->pushLog($logMessage);
|
||||||
|
|
||||||
$this->messagePublisher->publishMessage(
|
$this->messagePublisher->publishRetryMessage(
|
||||||
$payload,
|
$payload,
|
||||||
MessagePublisher::RETRY_METADATAS_QUEUE,
|
MessagePublisher::WRITE_METADATAS_TYPE,
|
||||||
2,
|
2,
|
||||||
'Subdef is not physically present!'
|
'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->getSubdefName(),
|
||||||
$event->getWorkerMessage(),
|
$event->getWorkerMessage(),
|
||||||
MessagePublisher::RETRY_METADATAS_QUEUE,
|
MessagePublisher::WRITE_METADATAS_TYPE,
|
||||||
json_encode($payload)
|
json_encode($payload)
|
||||||
);
|
);
|
||||||
$this->messagePublisher->pushLog($logMessage);
|
$this->messagePublisher->pushLog($logMessage);
|
||||||
@@ -243,14 +245,14 @@ class RecordSubscriber implements EventSubscriberInterface
|
|||||||
$em->persist($workerRunningJob);
|
$em->persist($workerRunningJob);
|
||||||
$em->flush();
|
$em->flush();
|
||||||
$em->commit();
|
$em->commit();
|
||||||
} catch (\Exception $e) {
|
} catch (Exception $e) {
|
||||||
$em->rollback();
|
$em->rollback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->messagePublisher->publishMessage(
|
$this->messagePublisher->publishRetryMessage(
|
||||||
$payload,
|
$payload,
|
||||||
MessagePublisher::RETRY_METADATAS_QUEUE,
|
MessagePublisher::WRITE_METADATAS_TYPE,
|
||||||
$event->getCount(),
|
$event->getCount(),
|
||||||
$event->getWorkerMessage()
|
$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()
|
public static function getSubscribedEvents()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
|
/** @uses onRecordCreated */
|
||||||
RecordEvents::CREATED => 'onRecordCreated',
|
RecordEvents::CREATED => 'onRecordCreated',
|
||||||
|
/** @uses onSubdefinitionCreate */
|
||||||
RecordEvents::SUBDEFINITION_CREATE => 'onSubdefinitionCreate',
|
RecordEvents::SUBDEFINITION_CREATE => 'onSubdefinitionCreate',
|
||||||
|
/** @uses onDelete */
|
||||||
RecordEvents::DELETE => 'onDelete',
|
RecordEvents::DELETE => 'onDelete',
|
||||||
|
/** @uses onSubdefinitionCreationFailure */
|
||||||
WorkerEvents::SUBDEFINITION_CREATION_FAILURE => 'onSubdefinitionCreationFailure',
|
WorkerEvents::SUBDEFINITION_CREATION_FAILURE => 'onSubdefinitionCreationFailure',
|
||||||
|
/** @uses onRecordsWriteMeta */
|
||||||
WorkerEvents::RECORDS_WRITE_META => 'onRecordsWriteMeta',
|
WorkerEvents::RECORDS_WRITE_META => 'onRecordsWriteMeta',
|
||||||
|
/** @uses onStoryCreateCover */
|
||||||
WorkerEvents::STORY_CREATE_COVER => 'onStoryCreateCover',
|
WorkerEvents::STORY_CREATE_COVER => 'onStoryCreateCover',
|
||||||
|
/** @uses onSubdefinitionWritemeta */
|
||||||
WorkerEvents::SUBDEFINITION_WRITE_META => 'onSubdefinitionWritemeta',
|
WorkerEvents::SUBDEFINITION_WRITE_META => 'onSubdefinitionWritemeta',
|
||||||
|
/** @uses onRecordEditInWorker */
|
||||||
WorkerEvents::RECORD_EDIT_IN_WORKER => '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 $subdefType
|
||||||
* @param string $subdefName
|
* @param string $subdefName
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
private function isSubdefMetadataUpdateRequired(\databox $databox, $subdefType, $subdefName)
|
private function isSubdefMetadataUpdateRequired(databox $databox, $subdefType, $subdefName)
|
||||||
{
|
{
|
||||||
if ($databox->get_subdef_structure()->hasSubdef($subdefType, $subdefName)) {
|
if ($databox->get_subdef_structure()->hasSubdef($subdefType, $subdefName)) {
|
||||||
return $databox->get_subdef_structure()->get_subdef($subdefType, $subdefName)->isMetadataUpdateRequired();
|
return $databox->get_subdef_structure()->get_subdef($subdefType, $subdefName)->isMetadataUpdateRequired();
|
||||||
|
@@ -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,
|
$payload,
|
||||||
MessagePublisher::RETRY_POPULATE_INDEX_QUEUE,
|
MessagePublisher::POPULATE_INDEX_TYPE,
|
||||||
$event->getCount(),
|
$event->getCount(),
|
||||||
$event->getWorkerMessage()
|
$event->getWorkerMessage()
|
||||||
);
|
);
|
||||||
|
@@ -65,7 +65,7 @@ class SubtitleSubscriber implements EventSubscriberInterface
|
|||||||
'payload' => $data
|
'payload' => $data
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->messagePublisher->publishMessage($payload, MessagePublisher::MAIN_QUEUE);
|
$this->messagePublisher->publishMessage($payload, MessagePublisher::MAIN_QUEUE_TYPE);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$em->rollback();
|
$em->rollback();
|
||||||
}
|
}
|
||||||
|
@@ -29,9 +29,9 @@ class WebhookSubscriber implements EventSubscriberInterface
|
|||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->messagePublisher->publishMessage(
|
$this->messagePublisher->publishRetryMessage(
|
||||||
$payload,
|
$payload,
|
||||||
MessagePublisher::RETRY_WEBHOOK_QUEUE,
|
MessagePublisher::WEBHOOK_TYPE,
|
||||||
$event->getCount(),
|
$event->getCount(),
|
||||||
$event->getWorkerMessage()
|
$event->getWorkerMessage()
|
||||||
);
|
);
|
||||||
|
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
namespace Alchemy\Phrasea\WorkerManager\Worker;
|
namespace Alchemy\Phrasea\WorkerManager\Worker;
|
||||||
|
|
||||||
use Alchemy\Phrasea\Application\Helper\EntityManagerAware;
|
|
||||||
use Alchemy\Phrasea\Application as PhraseaApplication;
|
use Alchemy\Phrasea\Application as PhraseaApplication;
|
||||||
|
use Alchemy\Phrasea\Application\Helper\EntityManagerAware;
|
||||||
use Alchemy\Phrasea\Model\Entities\StoryWZ;
|
use Alchemy\Phrasea\Model\Entities\StoryWZ;
|
||||||
use Alchemy\Phrasea\Model\Entities\WorkerRunningJob;
|
use Alchemy\Phrasea\Model\Entities\WorkerRunningJob;
|
||||||
use Alchemy\Phrasea\Model\Repositories\UserRepository;
|
use Alchemy\Phrasea\Model\Repositories\UserRepository;
|
||||||
@@ -80,7 +80,7 @@ class AssetsIngestWorker implements WorkerInterface
|
|||||||
'commit_id' => $payload['commit_id']
|
'commit_id' => $payload['commit_id']
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->messagePublisher->publishMessage($createRecordMessage, MessagePublisher::CREATE_RECORD_QUEUE);
|
$this->messagePublisher->publishMessage($createRecordMessage, MessagePublisher::CREATE_RECORD_TYPE);
|
||||||
|
|
||||||
/** @var WorkerRunningJob $workerRunningJob */
|
/** @var WorkerRunningJob $workerRunningJob */
|
||||||
$workerRunningJob = $this->repoWorkerJob->findOneBy([
|
$workerRunningJob = $this->repoWorkerJob->findOneBy([
|
||||||
|
@@ -5,7 +5,6 @@ namespace Alchemy\Phrasea\WorkerManager\Worker;
|
|||||||
use Alchemy\Phrasea\Application;
|
use Alchemy\Phrasea\Application;
|
||||||
use Alchemy\Phrasea\Application\Helper\NotifierAware;
|
use Alchemy\Phrasea\Application\Helper\NotifierAware;
|
||||||
use Alchemy\Phrasea\Core\LazyLocator;
|
use Alchemy\Phrasea\Core\LazyLocator;
|
||||||
use Alchemy\Phrasea\Exception\InvalidArgumentException;
|
|
||||||
use Alchemy\Phrasea\Model\Entities\FtpExport;
|
use Alchemy\Phrasea\Model\Entities\FtpExport;
|
||||||
use Alchemy\Phrasea\Model\Entities\FtpExportElement;
|
use Alchemy\Phrasea\Model\Entities\FtpExportElement;
|
||||||
use Alchemy\Phrasea\Model\Entities\WorkerRunningJob;
|
use Alchemy\Phrasea\Model\Entities\WorkerRunningJob;
|
||||||
@@ -371,9 +370,9 @@ class FtpWorker implements WorkerInterface
|
|||||||
'payload' => $payload
|
'payload' => $payload
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->app['alchemy_worker.message.publisher']->publishMessage(
|
$this->getMessagePublisher()->publishRetryMessage(
|
||||||
$fullPayload,
|
$fullPayload,
|
||||||
MessagePublisher::RETRY_FTP_QUEUE,
|
MessagePublisher::FTP_TYPE,
|
||||||
$count,
|
$count,
|
||||||
$workerMessage
|
$workerMessage
|
||||||
);
|
);
|
||||||
@@ -503,4 +502,13 @@ class FtpWorker implements WorkerInterface
|
|||||||
{
|
{
|
||||||
return $this->app['repo.ftp-exports'];
|
return $this->app['repo.ftp-exports'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return MessagePublisher
|
||||||
|
*/
|
||||||
|
private function getMessagePublisher()
|
||||||
|
{
|
||||||
|
return $this->app['alchemy_worker.message.publisher'];
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -29,7 +29,7 @@ class MainQueueWorker implements WorkerInterface
|
|||||||
|
|
||||||
switch ($payload['type']) {
|
switch ($payload['type']) {
|
||||||
case MessagePublisher::SUBTITLE_TYPE:
|
case MessagePublisher::SUBTITLE_TYPE:
|
||||||
$queue = MessagePublisher::SUBTITLE_QUEUE;
|
$queue = MessagePublisher::SUBTITLE_TYPE;
|
||||||
$messageType = $payload['type'];
|
$messageType = $payload['type'];
|
||||||
unset($payload['type']);
|
unset($payload['type']);
|
||||||
|
|
||||||
|
@@ -82,7 +82,7 @@ class PullAssetsWorker implements WorkerInterface
|
|||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->messagePublisher->publishMessage($payload, MessagePublisher::ASSETS_INGEST_QUEUE);
|
$this->messagePublisher->publishMessage($payload, MessagePublisher::ASSETS_INGEST_TYPE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -75,7 +75,7 @@ class SubdefCreationWorker implements WorkerInterface
|
|||||||
if (!$canCreateSubdef) {
|
if (!$canCreateSubdef) {
|
||||||
// the file is in used to write meta
|
// 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 ;
|
return ;
|
||||||
}
|
}
|
||||||
@@ -178,7 +178,10 @@ class SubdefCreationWorker implements WorkerInterface
|
|||||||
// checking ended
|
// checking ended
|
||||||
|
|
||||||
// order to write meta for the subdef if needed
|
// 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);
|
$this->subdefGenerator->setLogger($oldLogger);
|
||||||
|
|
||||||
|
@@ -170,7 +170,11 @@ class WebhookWorker implements WorkerInterface
|
|||||||
$this->messagePublisher->pushLog($workerMessage);
|
$this->messagePublisher->pushLog($workerMessage);
|
||||||
|
|
||||||
// count = 0 mean do not retry because no api application defined
|
// 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;
|
return;
|
||||||
}
|
}
|
||||||
@@ -235,7 +239,7 @@ class WebhookWorker implements WorkerInterface
|
|||||||
$this->messagePublisher->publishFailedMessage(
|
$this->messagePublisher->publishFailedMessage(
|
||||||
$payload,
|
$payload,
|
||||||
new AMQPTable(['worker-message' => $e->getMessage()]),
|
new AMQPTable(['worker-message' => $e->getMessage()]),
|
||||||
MessagePublisher::FAILED_WEBHOOK_QUEUE
|
MessagePublisher::WEBHOOK_TYPE
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -12,6 +12,8 @@ use Alchemy\Phrasea\Model\Repositories\WorkerRunningJobRepository;
|
|||||||
use Alchemy\Phrasea\WorkerManager\Event\SubdefinitionWritemetaEvent;
|
use Alchemy\Phrasea\WorkerManager\Event\SubdefinitionWritemetaEvent;
|
||||||
use Alchemy\Phrasea\WorkerManager\Event\WorkerEvents;
|
use Alchemy\Phrasea\WorkerManager\Event\WorkerEvents;
|
||||||
use Alchemy\Phrasea\WorkerManager\Queue\MessagePublisher;
|
use Alchemy\Phrasea\WorkerManager\Queue\MessagePublisher;
|
||||||
|
use DateTime;
|
||||||
|
use Exception;
|
||||||
use Monolog\Logger;
|
use Monolog\Logger;
|
||||||
use PHPExiftool\Driver\Metadata\Metadata;
|
use PHPExiftool\Driver\Metadata\Metadata;
|
||||||
use PHPExiftool\Driver\Metadata\MetadataBag;
|
use PHPExiftool\Driver\Metadata\MetadataBag;
|
||||||
@@ -21,6 +23,7 @@ use PHPExiftool\Driver\Value\Multi;
|
|||||||
use PHPExiftool\Exception\TagUnknown;
|
use PHPExiftool\Exception\TagUnknown;
|
||||||
use PHPExiftool\Writer;
|
use PHPExiftool\Writer;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
|
use record_adapter;
|
||||||
|
|
||||||
class WriteMetadatasWorker implements WorkerInterface
|
class WriteMetadatasWorker implements WorkerInterface
|
||||||
{
|
{
|
||||||
@@ -73,7 +76,7 @@ class WriteMetadatasWorker implements WorkerInterface
|
|||||||
if (!$canWriteMeta) {
|
if (!$canWriteMeta) {
|
||||||
// the file is in used to generate subdef
|
// 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 ;
|
return ;
|
||||||
}
|
}
|
||||||
@@ -113,7 +116,7 @@ class WriteMetadatasWorker implements WorkerInterface
|
|||||||
$em->beginTransaction();
|
$em->beginTransaction();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$date = new \DateTime();
|
$date = new DateTime();
|
||||||
$workerRunningJob = new WorkerRunningJob();
|
$workerRunningJob = new WorkerRunningJob();
|
||||||
$workerRunningJob
|
$workerRunningJob
|
||||||
->setDataboxId($databoxId)
|
->setDataboxId($databoxId)
|
||||||
@@ -129,14 +132,17 @@ class WriteMetadatasWorker implements WorkerInterface
|
|||||||
$em->flush();
|
$em->flush();
|
||||||
|
|
||||||
$em->commit();
|
$em->commit();
|
||||||
} catch (\Exception $e) {
|
} catch (Exception $e) {
|
||||||
$em->rollback();
|
$em->rollback();
|
||||||
|
$this->logger->error("Error persisting WorkerRunningJob !");
|
||||||
|
|
||||||
|
return ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$subdef = $record->get_subdef($payload['subdefName']);
|
$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;
|
$workerMessage = "Exception catched when try to get subdef " .$payload['subdefName']. " from DB for the recordID: " .$recordId;
|
||||||
$this->logger->error($workerMessage);
|
$this->logger->error($workerMessage);
|
||||||
|
|
||||||
@@ -221,7 +227,7 @@ class WriteMetadatasWorker implements WorkerInterface
|
|||||||
try {
|
try {
|
||||||
$value = self::fixDate($value); // will return NULL if the date is not valid
|
$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
|
$value = null; // do NOT write back to iptc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -230,7 +236,7 @@ class WriteMetadatasWorker implements WorkerInterface
|
|||||||
$value = new Mono($value);
|
$value = new Mono($value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch(\Exception $e) {
|
} catch(Exception $e) {
|
||||||
// the field is not set in the record, erase it
|
// the field is not set in the record, erase it
|
||||||
if ($fieldStructure->is_multi()) {
|
if ($fieldStructure->is_multi()) {
|
||||||
$value = new Multi(array(''));
|
$value = new Multi(array(''));
|
||||||
@@ -260,8 +266,8 @@ class WriteMetadatasWorker implements WorkerInterface
|
|||||||
$this->writer->write($subdef->getRealPath(), $metadata);
|
$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() ));
|
$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) {
|
} 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());
|
$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);
|
$this->logger->error($workerMessage);
|
||||||
|
|
||||||
$count = isset($payload['count']) ? $payload['count'] + 1 : 2 ;
|
$count = isset($payload['count']) ? $payload['count'] + 1 : 2 ;
|
||||||
@@ -297,11 +303,11 @@ class WriteMetadatasWorker implements WorkerInterface
|
|||||||
$em->beginTransaction();
|
$em->beginTransaction();
|
||||||
try {
|
try {
|
||||||
$workerRunningJob->setStatus(WorkerRunningJob::FINISHED);
|
$workerRunningJob->setStatus(WorkerRunningJob::FINISHED);
|
||||||
$workerRunningJob->setFinished(new \DateTime('now'));
|
$workerRunningJob->setFinished(new DateTime('now'));
|
||||||
$em->persist($workerRunningJob);
|
$em->persist($workerRunningJob);
|
||||||
$em->flush();
|
$em->flush();
|
||||||
$em->commit();
|
$em->commit();
|
||||||
} catch (\Exception $e) {
|
} catch (Exception $e) {
|
||||||
$em->rollback();
|
$em->rollback();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,7 +320,7 @@ class WriteMetadatasWorker implements WorkerInterface
|
|||||||
return str_replace("\0", "", $value);
|
return str_replace("\0", "", $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function updateJeton(\record_adapter $record)
|
private function updateJeton(record_adapter $record)
|
||||||
{
|
{
|
||||||
$connection = $record->getDatabox()->get_connection();
|
$connection = $record->getDatabox()->get_connection();
|
||||||
|
|
||||||
@@ -344,16 +350,16 @@ class WriteMetadatasWorker implements WorkerInterface
|
|||||||
$a = explode(';', preg_replace('/\D+/', ';', trim($value)));
|
$a = explode(';', preg_replace('/\D+/', ';', trim($value)));
|
||||||
switch (count($a)) {
|
switch (count($a)) {
|
||||||
case 3: // yyyy;mm;dd
|
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');
|
$date = $date->format('Y-m-d H:i:s');
|
||||||
break;
|
break;
|
||||||
case 6: // yyyy;mm;dd;hh;mm;ss
|
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');
|
$date = $date->format('Y-m-d H:i:s');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (\Exception $e) {
|
catch (Exception $e) {
|
||||||
$date = null;
|
$date = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
119
lib/classes/patch/413_PHRAS_3282.php
Normal file
119
lib/classes/patch/413_PHRAS_3282.php
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Alchemy\Phrasea\Application;
|
||||||
|
use Alchemy\Phrasea\Core\Configuration\PropertyAccess;
|
||||||
|
use Alchemy\Phrasea\WorkerManager\Queue\MessagePublisher;
|
||||||
|
|
||||||
|
|
||||||
|
class patch_413_PHRAS_3282 implements patchInterface
|
||||||
|
{
|
||||||
|
const OLDQ2NEWQ_ttl_retry = [
|
||||||
|
'assetsIngest' => 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']);
|
||||||
|
}
|
||||||
|
}
|
@@ -270,8 +270,7 @@ class record_preview extends record_adapter
|
|||||||
$this->title .= parent::get_title($options);
|
$this->title .= parent::get_title($options);
|
||||||
break;
|
break;
|
||||||
case "BASK":
|
case "BASK":
|
||||||
$this->title .= $this->name . ' - ' . parent::get_title($options)
|
$this->title .= $this->name . ' (' . $this->getNumber() . '/' . $this->total . ') - ' . parent::get_title($options);
|
||||||
. ' (' . $this->getNumber() . '/' . $this->total . ') ';
|
|
||||||
break;
|
break;
|
||||||
case "REG":
|
case "REG":
|
||||||
$title = parent::get_title($options);
|
$title = parent::get_title($options);
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2">
|
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2">
|
||||||
<file date="2020-12-16T08:29:44Z" source-language="en" target-language="de" datatype="plaintext" original="not.available">
|
<file date="2021-01-13T14:26:33Z" source-language="en" target-language="de" datatype="plaintext" original="not.available">
|
||||||
<header>
|
<header>
|
||||||
<tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/>
|
<tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/>
|
||||||
<note>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.</note>
|
<note>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.</note>
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2">
|
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2">
|
||||||
<file date="2020-12-16T08:30:32Z" source-language="en" target-language="en" datatype="plaintext" original="not.available">
|
<file date="2021-01-13T14:27:16Z" source-language="en" target-language="en" datatype="plaintext" original="not.available">
|
||||||
<header>
|
<header>
|
||||||
<tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/>
|
<tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/>
|
||||||
<note>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.</note>
|
<note>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.</note>
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2">
|
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2">
|
||||||
<file date="2020-12-16T08:31:21Z" source-language="en" target-language="fr" datatype="plaintext" original="not.available">
|
<file date="2021-01-13T14:28:04Z" source-language="en" target-language="fr" datatype="plaintext" original="not.available">
|
||||||
<header>
|
<header>
|
||||||
<tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/>
|
<tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/>
|
||||||
<note>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.</note>
|
<note>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.</note>
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2">
|
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2">
|
||||||
<file date="2020-12-16T08:32:13Z" source-language="en" target-language="nl" datatype="plaintext" original="not.available">
|
<file date="2021-01-13T14:28:55Z" source-language="en" target-language="nl" datatype="plaintext" original="not.available">
|
||||||
<header>
|
<header>
|
||||||
<tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/>
|
<tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/>
|
||||||
<note>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.</note>
|
<note>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.</note>
|
||||||
|
@@ -10,7 +10,7 @@
|
|||||||
{{ "admin::workermanager:tab:configuration: title" | trans }}
|
{{ "admin::workermanager:tab:configuration: title" | trans }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="worker-info active" role="presentation">
|
<li class="worker-info" role="presentation">
|
||||||
<a href="#worker-info" aria-controls="worker-info" role="tab" data-toggle="tab" data-url="/admin/worker-manager/info">
|
<a href="#worker-info" aria-controls="worker-info" role="tab" data-toggle="tab" data-url="/admin/worker-manager/info">
|
||||||
{{ 'admin::workermanager:tab:workerinfo: title' |trans }}
|
{{ 'admin::workermanager:tab:workerinfo: title' |trans }}
|
||||||
</a>
|
</a>
|
||||||
@@ -56,9 +56,7 @@
|
|||||||
<!-- Tab panes -->
|
<!-- Tab panes -->
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
<div role="tabpanel" class="tab-pane fade" id="worker-configuration"></div>
|
<div role="tabpanel" class="tab-pane fade" id="worker-configuration"></div>
|
||||||
<div role="tabpanel" class="tab-pane fade in active" id="worker-info">
|
<div role="tabpanel" class="tab-pane fade" id="worker-info"></div>
|
||||||
{% include "admin/worker-manager/worker_info.html.twig" %}
|
|
||||||
</div>
|
|
||||||
<div role="tabpanel" class="tab-pane fade" id="worker-searchengine"></div>
|
<div role="tabpanel" class="tab-pane fade" id="worker-searchengine"></div>
|
||||||
<div role="tabpanel" class="tab-pane fade" id="worker-pull-assets"></div>
|
<div role="tabpanel" class="tab-pane fade" id="worker-pull-assets"></div>
|
||||||
<div role="tabpanel" class="tab-pane fade" id="worker-ftp"></div>
|
<div role="tabpanel" class="tab-pane fade" id="worker-ftp"></div>
|
||||||
@@ -101,6 +99,10 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var sel = '#configurationTabs li.{{ _fragment }} a';
|
||||||
|
$(sel).click();
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
{% else %}
|
{% else %}
|
||||||
<h1 class="alert alert-danger">
|
<h1 class="alert alert-danger">
|
||||||
|
@@ -1,58 +1,38 @@
|
|||||||
|
{% form_theme form 'form_table_layout.html.twig' %}
|
||||||
|
{% form_theme form.queues 'bootstrap_3_horizontal_layout.html.twig' %}
|
||||||
|
|
||||||
|
|
||||||
<h1>{{ 'admin::workermanager:tab:workerconfig: title' |trans }}</h1>
|
<h1>{{ 'admin::workermanager:tab:workerconfig: title' |trans }}</h1>
|
||||||
<p class="alert alert-danger">
|
<p class="alert alert-danger">
|
||||||
{{ 'admin::workermanager:tab:workerconfig: warning' |trans }}
|
{{ 'admin::workermanager:tab:workerconfig: warning' |trans }}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>{{ 'admin::workermanager:tab:workerconfig: Set up the delay between two attempts per queue! (if not set, default 10000 millisecond)' |trans }}</p>
|
|
||||||
{{ form_start(form, {'action': path('worker_admin_configuration')}) }}
|
{{ form_start(form, {'action': path('worker_admin_configuration')}) }}
|
||||||
|
|
||||||
<div class="control-group">
|
<table>
|
||||||
{{ form_row(form.assetsIngest) }}
|
{% for child in form.queues.children %}
|
||||||
</div>
|
<tr>
|
||||||
|
<td colspan="4">
|
||||||
<div class="control-group">
|
<hr/>
|
||||||
{{ form_row(form.createRecord) }}
|
{{ form_label(child) }}
|
||||||
</div>
|
{{ form_errors(child) }}
|
||||||
|
</td>
|
||||||
<div class="control-group">
|
</tr>
|
||||||
{{ form_row(form.subdefCreation) }}
|
<tr>
|
||||||
</div>
|
{% for child2 in child.children %}
|
||||||
|
<td>
|
||||||
<div class="control-group">
|
{{ form_row(child2) }}
|
||||||
{{ form_row(form.writeMetadatas) }}
|
</td>
|
||||||
</div>
|
{% endfor %}
|
||||||
|
{{ form_widget(child) }}
|
||||||
<div class="control-group">
|
</tr>
|
||||||
{{ form_row(form.webhook) }}
|
{% endfor %}
|
||||||
</div>
|
</table>
|
||||||
|
<br/>
|
||||||
<div class="control-group">
|
<br/>
|
||||||
{{ form_row(form.exportMail) }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="control-group">
|
|
||||||
{{ form_row(form.populateIndex) }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="control-group">
|
|
||||||
{{ form_row(form.ftp) }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h3> {{ 'admin::workermanager:tab:workerconfig: Config Worker queue delayed' |trans }}</h3>
|
|
||||||
<p> {{ 'admin::workermanager:tab:workerconfig: if not set ,default 5000 millisecond' |trans }}</p>
|
|
||||||
|
|
||||||
<div class="control-group">
|
|
||||||
{{ form_row(form.delayedSubdef) }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="control-group">
|
|
||||||
{{ form_row(form.delayedWriteMeta) }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="control-group">
|
|
||||||
<input type="submit" class="btn btn-primary" value={{ "admin::workermanager:tab:workerconfig:Apply in queue"|trans }} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
{{ form_widget(form) }}
|
||||||
|
|
||||||
{{ form_end(form) }}
|
{{ form_end(form) }}
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
@@ -1,53 +1,40 @@
|
|||||||
<h1>{{ 'admin::workermanager:tab:pullassets: description' |trans }}</h1>
|
<h1>{{ 'admin::workermanager:tab:pullassets: description' |trans }}</h1>
|
||||||
|
|
||||||
{{ form_start(form, {'action': path('worker_admin_pullAssets')}) }}
|
{{ form_start(form, {'action': path('worker_admin_pullAssets')}) }}
|
||||||
|
{{ form_widget(form) }}
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
<div class="control-group">
|
<div class="control-group">
|
||||||
{{ form_row(form.UploaderApiBaseUri) }}
|
{% if(running) %}
|
||||||
|
<button type="submit" value="stop" class="btn btn-danger stop-pull-assets">{{ 'Stop' | trans }}</button>
|
||||||
|
{% else %}
|
||||||
|
<button type="submit" value="start" class="btn btn-primary start-pull-assets">{{ "Start"|trans }}</button>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="control-group">
|
|
||||||
{{ form_row(form.clientSecret) }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="control-group">
|
|
||||||
{{ form_row(form.clientId) }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="control-group">
|
|
||||||
{{ form_row(form.pullInterval) }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="control-group">
|
|
||||||
<button class="btn btn-primary start-pull-mode">{{ "admin::workermanager:tab:pullassets: Initialize pull assets"|trans }}</button>
|
|
||||||
|
|
||||||
<button class="btn btn-danger stop-pull-mode">{{ 'admin::workermanager:tab:pullassets: Stop pull assets' | trans }}</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{ form_end(form) }}
|
{{ form_end(form) }}
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$("#worker-pull-assets").on('click', '.stop-pull-mode', function(e) {
|
$("#worker-pull-assets").on('click', 'BUTTON[type=submit]', function(e, z) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (confirm("Warning! You are about to stop pull mode!")) {
|
var button = $(e.target);
|
||||||
$.ajax({
|
var form = button.closest("FORM");
|
||||||
type: "POST",
|
$("INPUT.act", form).val(button.val()); // "save", "start" or "stop"
|
||||||
url: "/admin/worker-manager/purge-queue",
|
|
||||||
dataType: 'json',
|
var ok = true;
|
||||||
data : {
|
{% if(running) %}
|
||||||
queueName : "pull-queue"
|
if(button.val() === 'save') {
|
||||||
},
|
// saving will empty the queue, "stopping"
|
||||||
success: function (data) {
|
ok = confirm("Warning! Changing the settings will stop pulling assets!")
|
||||||
console.log(data);
|
}
|
||||||
return false;
|
{% endif %}
|
||||||
|
if(button.val() === 'stop') {
|
||||||
|
// saving will empty the queue, "stopping"
|
||||||
|
ok = confirm("Warning! You are about to stop pulling assets!")
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ok) {
|
||||||
|
form.submit();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#worker-pull-assets").on('click', '.start-pull-mode', function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
$('form[name="worker_pullAssets"]').submit();
|
|
||||||
});
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
@@ -12,6 +12,7 @@
|
|||||||
<th>{{ 'admin::workermanager:tab:queueMonitor: Message count' |trans }}</th>
|
<th>{{ 'admin::workermanager:tab:queueMonitor: Message count' |trans }}</th>
|
||||||
<th>{{ 'admin::workermanager:tab:queueMonitor: Consumer count' |trans }}</th>
|
<th>{{ 'admin::workermanager:tab:queueMonitor: Consumer count' |trans }}</th>
|
||||||
<th></th>
|
<th></th>
|
||||||
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="queue-list">
|
<tbody class="queue-list">
|
||||||
@@ -19,12 +20,15 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% for queueStatus in queuesStatus %}
|
{% for queueStatus in queuesStatus %}
|
||||||
<tr>
|
<tr>
|
||||||
<th>{{ queueStatus.queueName }}</th>
|
<td>{{ queueStatus.queueName }}</td>
|
||||||
<td>{{ queueStatus.messageCount }}</td>
|
<td>{{ queueStatus.messageCount }}</td>
|
||||||
<td>{{ queueStatus.consumerCount }}</td>
|
<td>{{ queueStatus.consumerCount }}</td>
|
||||||
<td>
|
<td>
|
||||||
<button class="btn btn-danger btn-mini purge-queue" data-queue-name="{{ queueStatus.queueName }}">{{ 'admin::workermanager:tab:queueMonitor: Purge Queue' | trans }}</button>
|
<button class="btn btn-danger btn-mini purge-queue" data-queue-name="{{ queueStatus.queueName }}">{{ 'admin::workermanager:tab:queueMonitor: Purge Queue' | trans }}</button>
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
<button class="btn btn-danger btn-mini delete-queue" data-queue-name="{{ queueStatus.queueName }}">{{ 'admin::workermanager:tab:queueMonitor: Delete Queue' | trans }}</button>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
@@ -60,5 +64,21 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$("#worker-queue-monitor").on('click', '.delete-queue', function() {
|
||||||
|
if (confirm("Warning! Are you sure? Messages cannot be recovered after deleting queue.")) {
|
||||||
|
$.ajax({
|
||||||
|
type: "POST",
|
||||||
|
url: "/admin/worker-manager/delete-queue",
|
||||||
|
dataType: 'json',
|
||||||
|
data : {
|
||||||
|
queueName : $(this).attr("data-queue-name")
|
||||||
|
},
|
||||||
|
success: function (data) {
|
||||||
|
$("#refresh-monitor").trigger("click");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@@ -1,45 +1,41 @@
|
|||||||
<h1>{{ 'admin::workermanager:tab:Reminder: description' |trans }}</h1>
|
<h1>{{ 'admin::workermanager:tab:Reminder: description' |trans }}</h1>
|
||||||
|
|
||||||
<form name="worker_validation_reminder" method="post" action="/admin/worker-manager/validation-reminder">
|
{{ form_start(form, {'action': path('worker_admin_validationReminder')}) }}
|
||||||
<div class="control-group">
|
{{ form_widget(form) }}
|
||||||
<div>
|
<br/>
|
||||||
<label for="worker_reminder_interval" class="required">{{ "admin::workermanager:tab:Reminder: Interval in second"|trans }}</label>
|
<br/>
|
||||||
<input type="text" id="worker_reminder_interval" name="worker_reminder_interval" required="required" value="{{ interval }}">
|
<br/>
|
||||||
</div>
|
<div class="control-group">
|
||||||
</div>
|
{% if(running) %}
|
||||||
|
<button type="submit" value="stop" class="btn btn-danger stop-validation-reminder">{{ 'Stop' | trans }}</button>
|
||||||
<div class="control-group">
|
{% else %}
|
||||||
<button class="btn btn-primary start-validation-reminder">{{ "admin::workermanager:tab:Reminder: Start"|trans }}</button>
|
<button type="submit" value="start" class="btn btn-primary start-validation-reminder">{{ "Start"|trans }}</button>
|
||||||
|
{% endif %}
|
||||||
<button class="btn btn-danger stop-validation-reminder">{{ 'admin::workermanager:tab:Reminder: Stop' | trans }}</button>
|
</div>
|
||||||
</div>
|
{{ form_end(form) }}
|
||||||
</form>
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$("#worker-reminder").on('click', '.stop-validation-reminder', function(e) {
|
$("#worker-reminder").on('click', 'BUTTON[type=submit]', function(e, z) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (confirm("Warning! You are about to stop validation Reminder!")) {
|
var button = $(e.target);
|
||||||
$.ajax({
|
var form = button.closest("FORM");
|
||||||
type: "POST",
|
$("INPUT.act", form).val(button.val()); // "save", "start" or "stop"
|
||||||
url: "/admin/worker-manager/purge-queue",
|
|
||||||
dataType: 'json',
|
|
||||||
data : {
|
|
||||||
queueName : "validationReminder-queue"
|
|
||||||
},
|
|
||||||
success: function (data) {
|
|
||||||
$('#tree li.selected a').trigger('click');
|
|
||||||
console.log(data);
|
|
||||||
|
|
||||||
return false;
|
var ok = true;
|
||||||
|
{% if(running) %}
|
||||||
|
if(button.val() === 'save') {
|
||||||
|
// saving will empty the queue, "stopping"
|
||||||
|
ok = confirm("Warning! Changing the settings will stop validation Reminder!")
|
||||||
|
}
|
||||||
|
{% endif %}
|
||||||
|
if(button.val() === 'stop') {
|
||||||
|
// saving will empty the queue, "stopping"
|
||||||
|
ok = confirm("Warning! You are about to stop validation Reminder!")
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ok) {
|
||||||
|
form.submit();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#worker-reminder").on('click', '.start-validation-reminder', function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
$('form[name="worker_validation_reminder"]').submit();
|
|
||||||
});
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@@ -76,11 +76,6 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<div class="context-menu context-menu-theme-vista">
|
<div class="context-menu context-menu-theme-vista">
|
||||||
<div title="" class="context-menu-item">
|
|
||||||
<div class="context-menu-item-inner export-record-action"
|
|
||||||
data-kind="basket" data-id="{{basket.getId()}}">{{ 'action::exporter' | trans }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% if app.getAclForUser(app.getAuthenticatedUser()).has_right(constant('\\ACL::CANMODIFRECORD')) %}
|
{% if app.getAclForUser(app.getAuthenticatedUser()).has_right(constant('\\ACL::CANMODIFRECORD')) %}
|
||||||
<div title="" class="context-menu-item menu3-custom-item">
|
<div title="" class="context-menu-item menu3-custom-item">
|
||||||
<div data-kind="basket" data-id="{{basket.getId()}}"
|
<div data-kind="basket" data-id="{{basket.getId()}}"
|
||||||
@@ -174,15 +169,6 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<div class="context-menu context-menu-theme-flat">
|
<div class="context-menu context-menu-theme-flat">
|
||||||
<div title="" class="context-menu-item">
|
|
||||||
<div class="context-menu-item-inner export-record-action"
|
|
||||||
data-kind="basket" data-id="{{basket.getId()}}">
|
|
||||||
<a href="#">
|
|
||||||
<img src="/assets/common/images/icons/export-shadow.png" style="width: 22px;" alt="{{ 'action::exporter' | trans }}">
|
|
||||||
<span>{{ 'action::exporter' | trans }}</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div title="" class="context-menu-item">
|
<div title="" class="context-menu-item">
|
||||||
<div class="context-menu-item-inner">
|
<div class="context-menu-item-inner">
|
||||||
<a href="{{ path('lightbox_compare', { 'basket' : basket.getId() }) }}" target="_blank">
|
<a href="{{ path('lightbox_compare', { 'basket' : basket.getId() }) }}" target="_blank">
|
||||||
@@ -279,15 +265,6 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<div class="context-menu context-menu-theme-flat">
|
<div class="context-menu context-menu-theme-flat">
|
||||||
<div title="" class="context-menu-item">
|
|
||||||
<div class="context-menu-item-inner export-record-action"
|
|
||||||
data-kind="record" data-id="{{story.getRecord(app).get_serialize_key()}}">
|
|
||||||
<a href="#">
|
|
||||||
<img src="/assets/common/images/icons/export-shadow.png" style="width: 22px;" alt="{{ 'action::exporter' | trans }}">
|
|
||||||
<span>{{ 'action::exporter' | trans }}</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% if app.getAclForUser(app.getAuthenticatedUser()).has_right(constant('\\ACL::CANMODIFRECORD')) %}
|
{% if app.getAclForUser(app.getAuthenticatedUser()).has_right(constant('\\ACL::CANMODIFRECORD')) %}
|
||||||
<div title="" class="context-menu-item menu3-custom-item">
|
<div title="" class="context-menu-item menu3-custom-item">
|
||||||
<div class="context-menu-item-inner edit-record-action"
|
<div class="context-menu-item-inner edit-record-action"
|
||||||
|
@@ -9,7 +9,7 @@
|
|||||||
{% if record.is_from_basket() %}
|
{% if record.is_from_basket() %}
|
||||||
<a sbas="{{record.get_sbas_id()}}" id="PREV_BASKDEL_{{record.get_serialize_key}}"
|
<a sbas="{{record.get_sbas_id()}}" id="PREV_BASKDEL_{{record.get_serialize_key}}"
|
||||||
class="WorkZoneElementRemover record-remove-from-basket-action"
|
class="WorkZoneElementRemover record-remove-from-basket-action"
|
||||||
data-context="reg_train_basket"
|
data-context="reg_train_basket" style="display: contents;height: 24px;width: 24px;position: relative;bottom: 0px;"
|
||||||
|
|
||||||
href="{{ path('prod_baskets_basket_element_remove', { 'basket' : record.get_container().getId(), 'basket_element_id' : record.get_original_item().getId()}) }}">
|
href="{{ path('prod_baskets_basket_element_remove', { 'basket' : record.get_container().getId(), 'basket_element_id' : record.get_original_item().getId()}) }}">
|
||||||
<img src="/assets/common/images/icons/delete.png" height="16" width="16" class="btn-image" title="{{ 'Remove from basket' | trans }}">
|
<img src="/assets/common/images/icons/delete.png" height="16" width="16" class="btn-image" title="{{ 'Remove from basket' | trans }}">
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div class="record-print-action" data-kind="record" data-id="{{record.get_sbas_id()}}_{{record.get_record_id()}}">
|
<div class="record-print-action" data-kind="record" data-id="{{record.get_sbas_id()}}_{{record.get_record_id()}}">
|
||||||
<img src="/assets/common/images/icons/print_history.png" height="16" width="16" class="btn-image" title="'{{ 'action : print' | trans }}">
|
<img src="/assets/common/images/icons/print_history.png" height="16" width="16" class="btn-image" title="{{ 'action : print' | trans }}">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if app.getAclForUser(app.getAuthenticatedUser()).has_right_on_base(record.get_base_id(), constant('\\ACL::CANDWNLDHD')) or app.getAclForUser(app.getAuthenticatedUser()).has_right_on_base(record.get_base_id(), constant('\\ACL::CANDWNLDPREVIEW')) %}
|
{% if app.getAclForUser(app.getAuthenticatedUser()).has_right_on_base(record.get_base_id(), constant('\\ACL::CANDWNLDHD')) or app.getAclForUser(app.getAuthenticatedUser()).has_right_on_base(record.get_base_id(), constant('\\ACL::CANDWNLDPREVIEW')) %}
|
||||||
|
Reference in New Issue
Block a user