function StubModalInstanceCtrl()

in public/components/stub-modal/stub-modal.js [27:472]


function StubModalInstanceCtrl($rootScope, $scope, $modalInstance, $window, config, stub, mode,
     sections, statusLabels, articleFormatService, legalStatesService, pictureDeskStatesService, wfComposerService, wfProdOfficeService, wfContentService,
     wfPreferencesService, wfFiltersService, sectionsInDesks, wfCapiAtomService, wfTelemetryService) {

    wfContentService.getTypes().then( (types) => {
        $scope.contentName =
            (wfContentService.getAtomTypes())[stub.contentType] ?
            "Atom" : (types[stub.contentType] || "News item");
            
        $scope.stubFormat = getArticleFormatLabel(stub.contentType);
 
        $scope.$watch('stub.articleFormat', (newValue) => {
            $scope.stubFormat = newValue;
        })

        wfPreferencesService.getPreference('featureSwitches').then((data) => { $scope.showFormatDropdown = data;})
        
        $scope.modalTitle = ({
            'create': `Create ${$scope.contentName}`,
            'edit': `Edit ${$scope.contentName}`,
            'import': 'Import Existing Content'
        })[mode];
    });

    $scope.stubFormatIsCorrectlyPopulated = function() {     
        return isFormatLabel($scope.stubFormat)
    }

    $scope.loadingTemplates = true;

    wfComposerService.loadTemplates().then(templates => {
        const sortedTemplates = _.sortBy(templates, 'title');

        $scope.templates = sortedTemplates.map(({ title, dateCreated }) => {
            // TODO MRB: Ideally Composer would give us back an opaque ID.
            // It's like this for now so we can roll Composer and Workflow
            // forward and back independently.
            return {
                id: `${title}_${dateCreated}`,
                display: `${title} - ${moment(dateCreated).format("Do MMMM YYYY")}`
            }

        });
    }).finally(() => {
        $scope.loadingTemplates = false;
    });

    function getAtomDisplayName(type) {
      switch (type) {
        case 'media':
          return 'Media';
        case 'chart':
          return 'Chart'
        default:
          return type;
      }
    }

    function getAtomDropdownData() {
      return _wfConfig.atomTypes.map(type => {
        return { value: type, displayName: getAtomDisplayName(type) };
      });
    }

    $scope.mode = mode;

    $scope.formData = {};
    $scope.disabled = !!stub.composerId;
    $scope.sections = getSectionsList(sections);
    $scope.templates = [];
    $scope.statuses = statusLabels;
    $scope.cdesks = _wfConfig.commissioningDesks;
    $scope.atomTypes = getAtomDropdownData();

    if(mode==='import') {
       $scope.statuses = statusLabels;
    }

    $scope.stub = stub;

    if ($scope.stub.section) {
        /**
         * To ensure that a modal loaded without a preference for section does not validate,
         * only set the section if a preference was found
         */
        $scope.stub.section = (function findSelectedSectionInAvailableSections (sect) {
            const filteredSections = $scope.sections ? $scope.sections.filter((el) => (el ? el.name === sect.name : false)) : [];
            if (filteredSections.length > 0) {
                return filteredSections[0];
            }
            return sect;
        })($scope.stub.section);
    }

    $scope.stub.status = 'Writers';

    /**
     * If the user currently has a desk selected then only
     * show the sections that are part of that desk in the dropdown
     * @param sections
     * @returns Filtered list of sections
     */
    function getSectionsList (sections) {
        const filtered = sections.filter(({ selected }) => selected);
        if (filtered.length === 0) {
            return sections
        }
        return filtered
    }

    $scope.articleFormats = articleFormatService.getArticleFormats();
    $scope.legalStates = legalStatesService.getLegalStates();
    $scope.pictureDeskStates = pictureDeskStatesService.getpictureDeskStates();
    $scope.prodOffices = wfProdOfficeService.getProdOffices();

    $scope.$watch('stub.section', (newValue) => {

        if (newValue) {
            wfPreferencesService.getPreference('preferredStub').then((data) => {
                data.section = newValue.name;
                wfPreferencesService.setPreference('preferredStub', data);
            }, () => {
                wfPreferencesService.setPreference('preferredStub', {
                    section: newValue.name
                });
            })
        }

    }, true);

    $scope.validImport = false;
    $scope.wfComposerState;

    $scope.warningMessages = undefined
    $scope.$watch('stub', (newStub) => {
        $scope.warningMessages = generateErrorMessages(newStub)
    }, true)

    $scope.isCommissionedLengthRequired = () => doesContentTypeRequireCommissionedLength($scope.stub.contentType);

    $scope.requiredAttrForCommissionedLength = () => doesContentTypeRequireCommissionedLength($scope.stub.contentType) && !$scope.stub.missingCommissionedLengthReason ? 'true' : null

    /* when a request is made to import an item from another tool,
     * e.g. composer or an atom editor, then we will check to see if
     * it is already being tracked by Workflow. If, this function will
     * be called with the workflow entry as it's argument.
     */
    function importHandleExisting(content) {
        if(content.visibleOnUi) {
            $scope.wfComposerState = 'visible';
            $scope.stubId = res.data.data.id;
        }
        else {
            $scope.wfComposerState = 'invisible'
        }
    }

    function importComposerContent() {
        wfComposerService.getComposerContent($scope.formData.importUrl)
            .then((response) => wfComposerService.parseComposerData(response, $scope.stub))
            .then((contentItem) => {
                const composerId = contentItem.composerId;

                if(composerId) {
                    $scope.composerUrl = config.composerViewContent + '/' + composerId;
                    $scope.stub.title = contentItem.headline;
                    // slice needed because the australian prodOffice is 'AUS' in composer and 'AU' in workflow
                    $scope.stub.prodOffice  = contentItem.composerProdOffice ? contentItem.composerProdOffice.slice(0,2) : 'UK';

                    wfContentService.getById(composerId).then(
                        (res) => importHandleExisting(res.data.data),
                        (err) => {
                            if(err.status === 404) {
                                $scope.validImport = true;
                            }
                        });
                }
            }, () => {
            $scope.actionSuccess = false;
        });
    }

    function importContentAtom(id, atomType) {
        wfCapiAtomService.getCapiAtom(id, atomType).then((response) => {
            if(response) {
                $scope.editorUrl = config.mediaAtomMakerViewAtom + id;
                const atom = wfCapiAtomService.parseCapiAtomData(response, atomType);
                $scope.stub.title = atom.title;
                $scope.stub.contentType = atomType.toLowerCase();
                $scope.stub.editorId = id;
                wfContentService.getByEditorId(id).then(
                    (res) => importHandleExisting(res.data.data),
                    (err) => {
                        if(err.status === 404) {
                            $scope.validImport = true;
                        }
                    }
                );
            }
        });
    }

    /* we can import from various different tools. Which one will be
     * determined by the URL. This list matches URL regexes to
     * functions which can handle the import. The first one that
     * matches will be applied. The default fallback is Composer,
     * which will match against everything and attempt to import. If
     * that import fails the whole thing has failed. */
    const importUrlHandlers = [
        { name: "Media Atom Maker",
          regex: "videos/([0-9a-f-]+)$",
          fn: (url, matches) => importContentAtom(matches[1], "media")
        },
        {
            name: "Atom Workshop",
            regex: /atoms\/([a-z]+)\/([0-9a-f-]+)/gi,
            fn: (url, matches) => importContentAtom(matches[1], matches[2])
        },
        { name: "Composer",
          regex: "^.*$",
          fn: importComposerContent
        }
    ];

    $scope.importUrlChanged = () => {
        const url = $scope.formData.importUrl;
        const handler = _.find(importUrlHandlers, (handlerObj) => {
            return url.search(handlerObj.regex) !== -1;
        });

        if(handler) {
            $scope.importHandler = handler;
            $scope.importHandler.fn(url, url.match(handler.regex));
        }
    };

    $scope.resetCommissionedLength = () => {
        $scope.stub.commissionedLength = null;
    }

    $scope.resetMissingCommissionedLengthReason = () => {
        $scope.stub.missingCommissionedLengthReason = null;
    }

    $scope.commissionedLengthSuggestions = [
        400,
        650,
        900,
        1200,
    ]

    $scope.sendTelemetryForSuggestion = (value, missingCommissionedLengthReason = null) => {
        const commissioningDesk = $scope.cdesks.find(desk  => desk.id.toString() === stub.commissioningDesks)?.externalName;
        const tags = {
            contentId: stub.id,
            productionOffice: stub.prodOffice,
            commissioningDesk
        }
        if (missingCommissionedLengthReason) tags['missingCommissionedLengthReason'] = missingCommissionedLengthReason;
        if(wfTelemetryService !== null && wfTelemetryService !== undefined) {
            wfTelemetryService.sendTelemetryEvent(
                "WORKFLOW_COMMISSIONED_LENGTH_SUGGESTION_PRESSED",
                tags,
                value
            )
        }
    }

    $scope.sendTelemetryForImport = (contentName) => {
        if(contentName === 'Atom') {
            return;
        }
        const tags = {
            contentId: stub.composerId,
            productionOffice: stub.prodOffice,
            commissioningDesk: stub.section?.name,
            commissionedLength: stub.commissionedLength,
            contentType: stub.contentType
        }
        if(wfTelemetryService !== null && wfTelemetryService !== undefined) {
            wfTelemetryService.sendTelemetryEvent(
                "WORKFLOW_CONTENT_IMPORTED_FROM_COMPOSER",
                tags,
                true
            )
        }
    }

    $scope.setPriorityToVeryUrgent = () => {
        $scope.stub.priority = 2;
    }

    $scope.submit = function (form) {
        if (form.$invalid) {
            useNativeFormFeedback($scope.stub)
            return;  // Form is not ready to submit
        }
        if ($scope.actionSuccess) { // Form has already been submitted successfully
            if ($scope.composerUrl) {
                window.open($scope.composerUrl, "_blank");
            }
            if ($scope.editorUrl) {
                window.open($scope.editorUrl, "_blank");
            }
            $scope.cancel()
        }
        else {
            const addToComposer = $scope.stub.status !== 'Stub' && $scope.contentName !== 'Atom';
            const addToAtomEditor = !addToComposer && $scope.contentName === 'Atom' && $scope.stub.status !== 'Stub';
            $scope.ok(addToComposer, addToAtomEditor);
        }
    };

    $scope.updateCommissionedLengthInComposer = function() {
        const commissionedLength = $scope.stub.commissionedLength;
        const missingCommissionedLengthReason = $scope.stub.missingCommissionedLengthReason;

        [null, undefined].includes(commissionedLength)
            ? wfComposerService.deleteFieldInPreviewAndLive(stub.composerId, 'commissionedLength')
            : wfComposerService.updateFieldInPreviewAndLive(stub.composerId, 'commissionedLength', commissionedLength);

        [null, undefined].includes(missingCommissionedLengthReason)
            ? wfComposerService.deleteFieldInPreviewAndLive(stub.composerId, 'missingCommissionedLengthReason')
            : wfComposerService.updateFieldInPreviewAndLive(stub.composerId, 'missingCommissionedLengthReason', missingCommissionedLengthReason);
    }

    $scope.ok = function (addToComposer, addToAtomEditor) {
        const stub = setDisplayHintForFormat ($scope.stub);
        
        function createItemPromise() {
            if ($scope.contentName === 'Atom') {
                stub.contentType = $scope.stub.contentType.toLowerCase();
                if (addToAtomEditor) {
                    return wfContentService.createInAtomEditor(stub);
                } else if (stub.id) {
                    return wfContentService.updateStub(stub);
                } else {
                    return wfContentService.createStub(stub);
                }
            } else {
                if (addToComposer) {
                    return wfContentService.createInComposer(stub);
                } else if (stub.id) {
                    return wfContentService.updateStub(stub);
                } else {
                    return wfContentService.createStub(stub);
                }
            }
        }

        $scope.actionInProgress = true;

        createItemPromise().then(() => {
            const eventName = ({
                'create': {
                    category: 'Stub',
                    action: 'Created',
                    value: {
                      'Created in Composer': stub.composerId
                    }
                },
                'edit': {
                  category: 'Stub',
                  action: 'Edited'
                },
                'import': {
                  category: 'Content',
                  action: 'Imported'
                },
            }[$scope.mode]);

            $rootScope.$broadcast('track:event', eventName.category, eventName.action, null, null, Object.assign(
                {}, {
                    'Section': stub.section,
                    'Content type': stub.contentType
                }, eventName.value ? eventName.value : {})
            );

            $rootScope.$broadcast('getContent');

            if ($scope.contentName === 'Atom') {
                if (stub.editorId && ($scope.mode !== 'import')) {
                    $scope.editorUrl = wfContentService.getEditorUrl(stub.editorId, stub.contentType);
                } else {
                    $modalInstance.close({
                        addToEditor: addToAtomEditor,
                        stub: $scope.stub
                    });
                }
            } else {
                if(stub.composerId && ($scope.mode !== 'import')) {
                    $scope.composerUrl = config.composerViewContent + '/' + stub.composerId;
                } else {
                    $modalInstance.close({
                        addToComposer: addToComposer,
                        stub: $scope.stub
                    });
                }
            }

            $scope.actionSuccess = true;
            $scope.actionInProgress = false;
        }, (err) => {
            $scope.actionSuccess = false;
            $scope.contentUpdateError = true;

            if(err.status === 409) {
                if(err.data.composerId) {
                    $scope.composerUrl = config.composerViewContent + '/' + err.data.composerId;
                }
                if(err.data.editorId) {
                    $scope.editorUrl = wfContentService.getEditorUrl(stub.editorId, stub.contentType);
                }
                if(err.data.stubId) {
                    $scope.stubId = err.data.stubId;
                }
            } else {
                $scope.actionSuccess = false;
            }

            $rootScope.$apply(() => { throw new Error('Stub ' + mode + ' failed: ' + (err.message || err)); });

            $scope.actionInProgress = false;
        });

    };

    $scope.cancel = function () {
        $modalInstance.dismiss('cancel');
    };

    $scope.delete = function () {
        wfContentService.remove($scope.stub.id)
            .then(() => {
                $scope.$emit('content.deleted');
                $scope.$emit('track:event', 'Content', 'Deleted', null, null, {
                    'Section': $scope.stub.contentItem.section,
                    'Content type': $scope.stub.contentItem.contentType
                });
                $scope.$apply();
                $modalInstance.dismiss('cancel');
            }, function (err) {
                $scope.$apply(() => { throw err; });
            });
    };
}