superdesk/superdesk-client-core

View on GitHub
scripts/apps/publish/directives/SubscribersDirective.ts

Summary

Maintainability
D
2 days
Test Coverage
import _ from 'lodash';
import {gettext} from 'core/utils';
import {appConfig} from 'appConfig';

/**
 * @ngdoc directive
 * @module superdesk.apps.publish
 * @name sdAdminPubSubscribers
 * @requires notify
 * @requires api
 * @requires subscribersService
 * @requires adminPublishSettingsService
 * @requires modal
 * @requires contentFilters
 * @requires $q
 * @requires $filter
 * @requires products
 * @param {Array} subscribersList - provided list of subscribers to display
 * @param {Boolean} hideHeader - controls the visibility of the header section
 * @description SubscribersDirective handles subscriber maintenance.
 */
SubscribersDirective.$inject = [
    'notify', 'api', 'subscribersService', 'adminPublishSettingsService', 'modal',
    'contentFilters', '$q', '$filter', 'products', '$rootScope',
];

export function SubscribersDirective(
    notify, api, subscribersService, adminPublishSettingsService,
    modal, contentFilters, $q, $filter, products, $rootScope,
) {
    return {
        scope: {
            subscribersList: '=',
            hideHeader: '=',
        },
        templateUrl: 'scripts/apps/publish/views/subscribers.html',
        link: function($scope) {
            $scope.subscriber = null;
            $scope.origSubscriber = null;
            $scope.subscribers = $scope.subscribersList || null;
            $scope.newDestination = null;
            $scope.contentFilters = null;
            $scope.apiProducts = null;
            $scope.directProducts = null;
            $scope.search = {};
            $scope.highPriorityQueueEnabled = appConfig.high_priority_queue_enabled;

            api.query('output_formats').then((result) => {
                $scope.formats = result._items.map((format) => ({
                    name: format.name,
                    qcode: format.type,
                }));
            });

            $scope.statusFilters = [
                {label: gettext('Active'), value: true, id: 'active'},
                {label: gettext('Both'), value: null, id: 'both'},
                {label: gettext('Inactive'), value: false, id: 'inactive'},
            ];

            $scope.subTypes = [
                {name: gettext('All'), qcode: 'all'},
                {name: gettext('Digital/Internet'), qcode: 'digital'},
                {name: gettext('Wire/Paper'), qcode: 'wire'},
            ];

            $scope.search.subscriber_status = $scope.statusFilters[0];
            /**
             * Fetches all subscribers from backend
             */
            const fetchSubscribers = () => {
                subscribersService.fetchSubscribers().then(
                    (result) => {
                        $scope.subscribers = result;
                    },
                );
            };

            /**
             * Fetches content filters from backend and returns the same.
             *
             * @return {*}
             */
            const fetchProducts = () =>
                products.fetchAllProducts().then((items) => {
                    $scope.productLookup = [];
                    _.each(items, (item) => {
                        item.name += ` [${item.product_type || 'both'}]`;
                        $scope.productLookup[item._id] = item;
                    });
                    $scope.directProducts = _.filter(items, (item) =>
                        _.includes(['direct', 'both'], item.product_type || 'both'));
                    $scope.apiProducts = _.filter(items, (item) =>
                        _.includes(['api', 'both'], item.product_type || 'both'));
                });

            /**
             * Initializes the Global Filters on the selected subscriber.
             */
            const initGlobalFilters = () => {
                if (!$scope.subscriber) {
                    return;
                }

                if (!$scope.subscriber.global_filters) {
                    $scope.subscriber.global_filters = {};
                }

                _.each($scope.globalFilters, (filter) => {
                    if (!(filter._id in $scope.subscriber.global_filters)) {
                        $scope.subscriber.global_filters[filter._id] = true;
                    }
                });
            };

            /**
             * Fetches list of global content filters and returns the same.
             *
             * @return {*}
             */
            const fetchGlobalContentFilters = () =>
                contentFilters.getGlobalContentFilters().then((filters) => {
                    $scope.globalFilters = filters;
                });

            /**
             * Fetch list of publish errors from the backend allowing the user to configure for the selected subscriber.
             *
             * @return {*}
             */
            const fetchPublishErrors = () =>
                adminPublishSettingsService.fetchPublishErrors().then((result) => {
                    $scope.all_errors = result._items[0].all_errors;
                });

            /**
             * Initializes the new destination object.
             */
            $scope.addNewDestination = function() {
                $scope.newDestination = {};
            };

            /**
             * Reverts the changes made to the new destination object
             */
            $scope.cancelNewDestination = function() {
                $scope.newDestination = null;
            };

            /**
             * Saves the destination and adds it to the destinations list of the selected subscriber
             */
            $scope.saveNewDestination = function() {
                $scope.destinations.push($scope.newDestination);
                $scope.newDestination = null;
                $scope.saveEnabled = true;
            };

            /**
             * Removes the selected destination from the destinations list of the selected subscriber.
             */
            $scope.deleteDestination = function(destination) {
                _.remove($scope.destinations, destination);
                $scope.saveEnabled = true;
            };

            /**
             * Upserts the selected subscriber.
             */
            $scope.save = function() {
                $scope.subscriber.destinations = $scope.destinations;

                let diff = {};

                _.forOwn($scope.subscriber, (value, key) => {
                    if (_.includes(['api_products', 'products'], key)) {
                        diff[key] = _.map(value, '_id');
                        return;
                    }
                    diff[key] = value;
                });

                api.subscribers.save($scope.origSubscriber, diff)
                    .then(
                        () => {
                            notify.success(gettext('Subscriber saved.'));
                            $scope.cancel();
                        },
                        (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 if (angular.isDefined(response.data._issues.name) &&
                                    angular.isDefined(response.data._issues.name.unique)) {
                                    notify.error(gettext('Error: Subscriber with Name ' + $scope.subscriber.name +
                                        ' already exists.'));
                                } else if (angular.isDefined(response.data._issues.destinations)) {
                                    notify.error(gettext('Error: Subscriber must have at least one destination.'));
                                }
                            } else {
                                notify.error(gettext('Error: Failed to save Subscriber.'));
                            }
                        },
                    )
                    .then(fetchSubscribers);
            };

            /**
             * Either initializes a new Subscriber object for adding a new subscriber or
             * initializes the subscriber object with the selected subscriber allowing
             * user to update the subscriber details.
             */
            $scope.edit = function(subscriber) {
                let promises = [];

                promises.push(fetchPublishErrors());
                promises.push(fetchProducts());
                promises.push(fetchGlobalContentFilters());

                $q.all(promises).then(() => {
                    $scope.origSubscriber = subscriber || {};
                    $scope.subscriber = _.create($scope.origSubscriber);
                    $scope.subscriber.critical_errors = $scope.origSubscriber.critical_errors;
                    $scope.subscriber.sequence_num_settings = $scope.origSubscriber.sequence_num_settings;

                    if (!('is_targetable' in $scope.origSubscriber)) {
                        $scope.subscriber.is_targetable = true;
                    }

                    initSubscriberProducts('products');
                    initSubscriberProducts('api_products');

                    $scope.subscriber.global_filters = $scope.origSubscriber.global_filters || {};

                    $scope.destinations = [];
                    if (angular.isDefined($scope.subscriber.destinations)
                        && !_.isNull($scope.subscriber.destinations) &&
                        $scope.subscriber.destinations.length > 0) {
                        $scope.destinations = _.clone($scope.subscriber.destinations);
                    }

                    $scope.subscriberType = $scope.subscriber.subscriber_type || '';
                    initGlobalFilters();
                }, () => {
                    notify.error(gettext('Subscriber could not be initialized!'));
                });
            };

            /**
             * Initialize Subscriber Products
             * @param field
             */
            function initSubscriberProducts(field) {
                $scope.subscriber[field] = [];

                if (_.get($scope.origSubscriber, field)) {
                    _.each($scope.origSubscriber[field], (p) => {
                        $scope.subscriber[field].push($scope.productLookup[p]);
                    });
                }
                $scope.subscriber[field] = $filter('sortByName')($scope.subscriber[field]);
            }

            /**
             * Reverts any changes made to the subscriber
             */
            $scope.cancel = function() {
                $scope.origSubscriber = null;
                $scope.subscriber = null;
                $scope.newDestination = null;
            };

            $scope.$watch('subscriber', (newValue, oldValue) => {
                if (newValue && oldValue) {
                    $scope.saveEnabled = true;
                } else {
                    $scope.saveEnabled = false;
                }
            }, true);

            $rootScope.$on('subcriber: saveEnabled', () => $scope.saveEnabled = true);

            // If subscribers list provided don't fetch subscribers
            if (!$scope.subscribersList) {
                fetchSubscribers();
            }
        },
    };
}