superdesk/superdesk-client-core

View on GitHub
scripts/apps/relations/services/RelationsService.ts

Summary

Maintainability
A
1 hr
Test Coverage
import {zipObject} from 'lodash';
import {IArticle, IVocabulary} from 'superdesk-api';
import {isPublished, isIngested} from 'apps/archive/utils';
import {gettext} from 'core/utils';

const RELATED_LINK_KEYS = 3; // links only have _id, type keys and order (and some old ones only _id)

export const isLink = (association) =>
    association != null && Object.keys(association).length <= RELATED_LINK_KEYS;

export const defaultAllowedWorkflows = {
    in_progress: true,
    published: true,
    ingested: false,
};

export function validateWorkflow(
    mediaItem: IArticle,
    allowedWorkflowsConfig: Partial<typeof defaultAllowedWorkflows>,
): {result: true} | {result: false; error: string} {
    const allowedWorkflows = {
        ...defaultAllowedWorkflows,
        ...allowedWorkflowsConfig,
    };

    if (allowedWorkflows.published !== true && isPublished(mediaItem)) {
        return {
            result: false,
            error: gettext('Adding published items as related is not allowed due to configuration options'),
        };
    }

    if (allowedWorkflows.in_progress !== true && !isPublished(mediaItem)) {
        return {
            result: false,
            error: gettext(
                'Adding related items that are not published '
                + 'is not allowed due to configuration options',
            ),
        };
    }

    if (allowedWorkflows.ingested !== true && isIngested(mediaItem)) {
        return {
            result: false,
            error: gettext('Adding ingested items as related is not allowed due to configuration options'),
        };
    }

    return {result: true};
}

RelationsService.$inject = ['api', '$q'];

export function RelationsService(api, $q) {
    this.getRelatedKeys = function(item: IArticle, fieldId: string) {
        return Object.keys(item.associations || {})
            .filter((key) => key.startsWith(fieldId) && item.associations[key] != null)
            .sort((a, b) => item.associations[a].order - item.associations[b].order);
    };

    this.getRelatedItemsForField = function(item: IArticle, fieldId: string) {
        const relatedItemsKeys = this.getRelatedKeys(item, fieldId);
        const associations = item.associations || {};

        return $q.all(relatedItemsKeys.map((key) => {
            if (isLink(associations[key])) {
                return api.find('archive', associations[key]._id)
                    .catch((response) => {
                        if (response?.status === 404) {
                            return null;
                        }

                        return Promise.reject(response);
                    });
            }

            return $q.when(associations[key]);
        })).then((values) => zipObject(relatedItemsKeys, values));
    };

    this.itemHasAllowedStatus = function(item: IArticle, field: IVocabulary) {
        return validateWorkflow(item, field?.field_options?.allowed_workflows ?? {}).result;
    };
}