scripts/apps/publish/controllers/PublishQueueController.ts
import _ from 'lodash';
import {isSuperdeskContent} from 'apps/workspace/helpers/isSuperdeskContent';
import {gettext} from 'core/utils';
PublishQueueController.$inject = [
'$scope',
'subscribersService',
'api',
'$q',
'notify',
'$location',
'ingestSources',
'vocabularies',
];
export function PublishQueueController($scope, subscribersService, api, $q, notify, $location, ingestSources,
vocabularies) {
$scope.subscribers = null;
$scope.subscriberLookup = {};
$scope.ingestProviders = null;
$scope.ingestProvidersLookup = {};
$scope.publish_queue = [];
$scope.contentTypes = null;
$scope.selectedFilterSubscriber = null;
$scope.selectedFilterIngestProvider = null;
$scope.selectedFilterContentType = null;
$scope.multiSelectCount = 0;
$scope.selectedQueueItems = [];
$scope.showResendBtn = false;
$scope.showCancelBtn = false;
$scope.showCancelSelectionBtn = false;
$scope.queueSearch = false;
$scope.selected = {};
$scope.publish_queue_statuses = ['pending', 'in-progress', 'success', 'error', 'retrying', 'failed', 'canceled'];
$scope.pagination = {page: 1};
$scope.pageSize = 25;
$scope.$watch('pagination.page', () => {
$scope.reload();
});
var promises = [];
promises.push(subscribersService.fetchSubscribers().then((items) => {
$scope.subscribers = items;
$scope.subscriberLookup = _.keyBy(items, '_id');
}));
promises.push(ingestSources.fetchAllIngestProviders().then((items) => {
$scope.ingestProviders = items;
$scope.ingestProvidersLookup = _.keyBy($scope.ingestProviders, '_id');
}));
promises.push(vocabularies.getVocabulary('type').then((items) => {
$scope.contentTypes = items.items;
}));
/*
* Get search input from search box to search for headline or unique_name,
* and perfrom reload function to populate publish queue.
*/
$scope.search = function(query) {
$scope.searchQuery = query;
$scope.pagination.page = 1;
$scope.reload();
};
/*
* Populates the publish queue and update the flags after fetch operation.
*/
function populatePublishQueue() {
return fetchPublishQueue().then((queue) => {
var queuedItems = queue._items;
_.forEach(queuedItems, (item) => {
angular.extend(item, {selected: false});
});
$scope.publish_queue = queuedItems;
$scope.lastRefreshedAt = new Date();
$scope.showResendBtn = false;
$scope.showCancelSelectionBtn = false;
$scope.maxPage = Math.ceil(queue._meta.total / $scope.pageSize);
}).finally(() => {
$scope.loading = false;
});
}
/*
* Fetch the publish queue on the basis of built criteria.
*/
function fetchPublishQueue() {
var criteria = criteria || {};
criteria.max_results = $scope.pageSize;
criteria.page = $scope.pagination.page;
var orTerms = null;
if (!_.isEmpty($scope.searchQuery)) {
orTerms = {$or: [
{headline: {
$regex: $scope.searchQuery,
$options: 'i'},
}, {unique_name: $scope.searchQuery},
]};
}
var filterTerms = [];
if (!_.isNil($scope.selectedFilterSubscriber)) {
filterTerms.push({subscriber_id: $scope.selectedFilterSubscriber._id});
}
if (!_.isNil($scope.selectedFilterStatus)) {
filterTerms.push({state: $scope.selectedFilterStatus});
}
if (!_.isNil($scope.selectedFilterIngestProvider)) {
filterTerms.push({ingest_provider: $scope.selectedFilterIngestProvider._id});
}
if (!_.isNil($scope.selectedFilterContentType)) {
filterTerms.push({content_type: $scope.selectedFilterContentType.qcode});
}
var andTerms = [];
_.each(filterTerms, (term) => {
andTerms.push(term);
});
if (orTerms !== null) {
andTerms.push(orTerms);
}
if (!_.isEmpty(andTerms)) {
criteria.where = JSON.stringify({
$and: andTerms,
});
}
return api.publish_queue.query(criteria);
}
$scope.reload = function() {
$scope.loading = true;
$q.all(promises).then(() => {
populatePublishQueue();
previewItem();
});
};
$scope.buildNewSchedule = function(item) {
var pickFields = ['item_id', 'item_version', 'publishing_action', 'formatted_item', 'headline',
'content_type', 'subscriber_id', 'unique_name', 'destination', 'ingest_provider',
'item_encoding', 'encoded_item_id', 'associated_items'];
var newItem = _.pick(item, pickFields);
return newItem;
};
$scope.scheduleToSend = function(item) {
var queueItems = [];
if (angular.isDefined(item)) {
queueItems.push($scope.buildNewSchedule(item));
} else if ($scope.multiSelectCount > 0) {
_.forEach($scope.selectedQueueItems, (_item) => {
queueItems.push($scope.buildNewSchedule(_item));
});
}
api.publish_queue.save([], queueItems).then(
(response) => {
$scope.reload();
$scope.cancelSelection();
},
(response) => {
if (angular.isDefined(response.data._issues)) {
if (angular.isDefined(response.data._issues['validator exception'])) {
notify.error(gettext('Error: ' + response.data._issues['validator exception']));
}
} else {
notify.error(gettext('Error: Failed to re-schedule'));
}
},
);
};
$scope.cancelSend = function(item) {
var itemList = [];
if (angular.isDefined(item)) {
itemList.push(item);
} else if ($scope.multiSelectCount > 0) {
_.forEach($scope.selectedQueueItems, (_item) => {
if (_item.state === 'pending' || _item.state === 'retrying') {
_item.state = 'canceled';
itemList.push(_item);
}
});
}
_.forEach(itemList, (_item) => {
api.publish_queue.update(_item, {state: 'canceled'});
});
$scope.cancelSelection();
};
$scope.filterPublishQueue = function(item, type) {
switch (type) {
case 'subscriber':
$scope.selectedFilterSubscriber = item;
break;
case 'ingest_provider':
$scope.selectedFilterIngestProvider = item;
break;
case 'status':
$scope.selectedFilterStatus = item;
break;
case 'type':
$scope.selectedFilterContentType = item;
break;
default:
$scope.selectedFilterSubscriber = null;
$scope.selectedFilterIngestProvider = null;
$scope.selectedFilterStatus = null;
$scope.selectedFilterContentType = null;
}
populatePublishQueue();
$scope.multiSelectCount = 0;
$scope.selectedQueueItems = [];
$scope.pagination.page = 1;
};
$scope.selectQueuedItem = function(queuedItem) {
if (queuedItem.selected) {
$scope.selectedQueueItems = _.union($scope.selectedQueueItems, [queuedItem]);
} else {
$scope.selectedQueueItems = _.without($scope.selectedQueueItems, queuedItem);
}
/* look for any items in states that cannot be resent */
var idx = _.findIndex($scope.selectedQueueItems,
(item: any) => _.includes(['pending', 'in-progress', 'retrying'], item.state));
/* All selected items can be resent */
if (idx === -1) {
$scope.showResendBtn = true;
$scope.showCancelBtn = false;
$scope.showCanceSelectionlBtn = false;
} else {
/* Find the index of any item that can be resent */
idx = _.findIndex($scope.selectedQueueItems,
(item: any) => item.state === 'success' || item.state === 'in-progress' || item.state === 'canceled' ||
item.state === 'error' || item.state === 'retrying');
/* Nothing to resend found */
if (idx === -1) {
$scope.showResendBtn = false;
$scope.showCancelSelectionBtn = true;
/* look for items that can be canceled */
idx = _.findIndex($scope.selectedQueueItems,
(item: any) => item.state === 'pending' || item.state === 'retrying');
/* Something can be canceled so show the button */
if (idx !== -1) {
$scope.showCancelBtn = true;
} else {
$scope.showCancelBtn = false;
}
} else {
$scope.showResendBtn = false;
$scope.showCancelBtn = false;
$scope.showCancelSelectionBtn = false;
}
}
$scope.multiSelectCount = $scope.selectedQueueItems.length;
};
$scope.cancelSelection = function() {
$scope.selectedQueueItems = [];
$scope.multiSelectCount = 0;
populatePublishQueue();
};
function refreshQueueState(data) {
var item = _.find($scope.publish_queue, {_id: data.queue_id});
if (item) {
var fields = ['error_message', 'completed_at', 'state'];
angular.extend(item, _.pick(data, fields));
$scope.$apply();
}
}
$scope.preview = function(queueItem) {
$location.search('_id', queueItem ? queueItem._id : queueItem);
};
function previewItem() {
var queueItem: any = _.find($scope.publish_queue, {_id: $location.search()._id}) || null;
$scope.selected.extensionPoint = false;
if (queueItem) {
let endpoint = 'archive';
if (isSuperdeskContent(queueItem.content_type)) {
if (queueItem.publishing_action === 'being_corrected') {
endpoint = 'published';
}
api.find(endpoint, queueItem.item_id, {version: queueItem.item_version})
.then((item) => {
$scope.selected.preview = item;
});
} else {
$scope.selected.preview = queueItem;
$scope.selected.extensionPoint = true;
}
} else {
$scope.selected.preview = null;
}
}
$scope.$on('$routeUpdate', previewItem);
$scope.$on('publish_queue:update', (evt, data) => {
refreshQueueState(data);
});
$scope.reload();
}