Viewing File: /usr/local/cpanel/base/sharedjs/zone_editor/views/manage.js

/* eslint-disable camelcase */
/*
# cpanel - base/sharedjs/zone_editor/views/manage.js
#                                                  Copyright 2022 cPanel, L.L.C.
#                                                           All rights reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited
*/

/* define: false */

/* jshint -W100 */

define(
    [
        "angular",
        "lodash",
        "cjt/core",
        "cjt/util/locale",
        "shared/js/zone_editor/models/dynamic_table",
        "shared/js/zone_editor/models/dmarc_record",
        "shared/js/zone_editor/utils/dnssec",
        "shared/js/zone_editor/utils/recordData",
        "shared/js/zone_editor/utils/recordSetIndex",
        "app/services/features",
        "app/services/recordTypes",
        "uiBootstrap",
        "cjt/directives/multiFieldEditor",
        "cjt/directives/actionButtonDirective",
        "cjt/directives/toggleSortDirective",
        "cjt/directives/searchDirective",
        "cjt/directives/pageSizeButtonDirective",
        "cjt/decorators/paginationDecorator",
        "cjt/directives/validationContainerDirective",
        "cjt/directives/validationItemDirective",
        "cjt/filters/qaSafeIDFilter",
        "cjt/validator/ip-validators",
        "cjt/validator/domain-validators",
        "cjt/validator/compare-validators",
        "cjt/validator/datatype-validators",
        "cjt/validator/email-validator",
        "cjt/services/viewNavigationApi",
        "cjt/services/cpanel/nvDataService",
        "cjt/directives/quickFiltersDirective",
        "cjt/directives/alertList",
        "cjt/services/alertService",
        "shared/js/zone_editor/directives/convert_to_full_record_name",
        "shared/js/zone_editor/directives/base_validators",
        "shared/js/zone_editor/directives/dmarc_validators",
        "shared/js/zone_editor/directives/caa_validators",
        "shared/js/zone_editor/directives/ds_validators",
        "shared/js/zone_editor/directives/naptr_validators",
    ],
    function(angular, _, CJT, LOCALE, DynamicTable, DMARCRecord, DNSSEC, RecordData, RecordSetIndex, FeaturesService, RecordTypesService) {
        "use strict";

        var MODULE_NAMESPACE = "shared.zoneEditor.views.manage";
        var app = angular.module(MODULE_NAMESPACE, []);

        var _RECORD_SET_ERR_ALERT_ID = "record-set-error";
        var _ALERT_GROUP = "zoneEditor";

        function _getRecordSetErrors(records) {
            var set;

            var index = new RecordSetIndex();

            for (var r = 0; r < records.length; r++) {
                var record = records[r];
                set = index.query(record.name, record.record_type);
                set.add(record);
            }

            var phrases = [];

            var sets = index.sets();
            for (var s = 0; s < sets.length; s++) {
                set = sets[s];

                if (set.ttlsMismatch()) {
                    var name = set.name().replace(/\.$/, "");

                    phrases.push( LOCALE.maketext("[_1]’s “[_2]” [numerate,_3,,records have] mismatched [asis,TTL] [numerate,_3,,values] ([list_and,_4]). Records of the same name and type must always have the same [asis,TTL] value.", name, set.type(), set.count(), set.ttls()) );
                }

                if (set.singletonExcess()) {
                    phrases.push( LOCALE.maketext("Only 1 “[_1]” record may exist per name. Rename or delete [_2]’s extra “[_1]” [numerate,_3,record,records].", set.type(), set.name(), set.count() - 1) );
                }
            }

            return phrases;
        }

        app.controller(
            "ManageZoneRecordsController", [
                "$scope",
                "$location",
                "$routeParams",
                "$timeout",
                "Zones",
                "viewNavigationApi",
                "$uibModal",
                FeaturesService.serviceName,
                RecordTypesService.serviceName,
                "defaultInfo",
                "nvDataService",
                "alertService",
                function(
                    $scope,
                    $location,
                    $routeParams,
                    $timeout,
                    Zones,
                    viewNavigationApi,
                    $uibModal,
                    Features,
                    $recordTypes,
                    defaultInfo,
                    nvDataService,
                    alertService) {
                    var manage = this;

                    manage.is_loading = false;
                    manage.zone_records = [];
                    manage.domain = $routeParams.domain;
                    manage.loading_error = false;
                    manage.loading_error_message = "";
                    manage.Features = Features;
                    manage.generated_domains = {};
                    manage.recordTypes = [];
                    manage.types = [];
                    manage.recordsInProgress = [];
                    manage.serial = null;
                    manage.isHostnameZone = PAGE.serverHostname === manage.domain;
                    manage.showEmailRoutingLink = PAGE.showEmailRoutingLink ? true : false;

                    manage.dsAlgorithms = DNSSEC.dsAlgorithms;

                    manage.dsDigTypes = DNSSEC.dsDigTypes;

                    manage.save_in_progress = false;

                    function Record(record, new_dmarc) {

                        // creating a new DMARC record
                        if (record && record.record_type === "DMARC" ) {
                            record.name = Zones.format_zone_name(manage.domain, "_dmarc.");
                            record.is_dmarc = true;
                            record.record_type = "TXT";

                        // loading existing DMARC record
                        } else if (record && record.txtdata) {
                            record.is_dmarc = new_dmarc.isDMARC(record.txtdata[0]);
                        } else {
                            record.is_dmarc = false;
                        }

                        var newRecord = Object.assign(
                            RecordData.createNewDefaultData(),
                            {
                                _id: "",
                                name: record.name || "",
                                record_type: record.record_type,
                                editing: record.is_new === "1",
                                is_new: record.is_new,
                                viewTemplate: manage.viewRecordTemplates(record.record_type),
                                editTemplate: manage.getRecordTemplate(record),
                                ttl: record.ttl || manage.default_ttl,
                                line_index: null,

                                is_dmarc: record.is_dmarc,
                                isEditable: true,
                                p: "",
                                sp: "",
                                adkim: "",
                                aspf: "",
                                pct: "",
                                fo: "",
                                rf: "",
                                ri: "",
                                rua: "",
                                ruf: "",
                                record: "",
                            }
                        );

                        if (record.is_new === "0") {
                            switch (record.record_type) {
                                case "A":
                                    newRecord.a_address = Zones.trimTrailingDot(record.record) || "";
                                    newRecord.record = Zones.trimTrailingDot(record.record) || "";
                                    break;
                                case "AAAA":
                                    newRecord.aaaa_address = Zones.trimTrailingDot(record.record);
                                    newRecord.record = Zones.trimTrailingDot(record.record);
                                    break;
                                case "AFSDB":
                                    newRecord.subtype = record.subtype;
                                    newRecord.hostname = record.hostname;
                                    break;
                                case "ALIAS":
                                    newRecord.alias = Zones.trimTrailingDot(record.record);
                                    newRecord.record = Zones.trimTrailingDot(record.record);
                                    break;
                                case "CAA":
                                    newRecord.flag = record.flag;
                                    newRecord.tag = record.tag;
                                    newRecord.value = record.value;
                                    break;
                                case "CNAME":
                                    newRecord.cname = Zones.trimTrailingDot(record.record);
                                    newRecord.record = Zones.trimTrailingDot(record.record);
                                    break;
                                case "DNAME":
                                    newRecord.dname = Zones.trimTrailingDot(record.record);
                                    newRecord.record = Zones.trimTrailingDot(record.record);
                                    break;
                                case "DS":
                                    newRecord.keytag = record.keytag;
                                    newRecord.algorithm = getDSAlgorithmById(parseInt(record.algorithm, 10));
                                    newRecord.digtype = getDSDigestTypeId(parseInt(record.digtype, 10));
                                    newRecord.digest = record.digest;
                                    break;
                                case "HINFO":
                                    newRecord.cpu = record.cpu;
                                    newRecord.os = record.os;
                                    break;
                                case "LOC":
                                    newRecord.latitude = record.latitude.trim();
                                    newRecord.longitude = record.longitude.trim();
                                    newRecord.altitude = record.altitude;
                                    newRecord.size = record.size;
                                    newRecord.horiz_pre = record.horiz_pre;
                                    newRecord.vert_pre = record.vert_pre;
                                    break;
                                case "MX":
                                    newRecord.priority = record.priority;
                                    newRecord.exchange = record.exchange;
                                    break;
                                case "NS":
                                    newRecord.nsdname = Zones.trimTrailingDot(record.record);
                                    newRecord.record = Zones.trimTrailingDot(record.record);
                                    break;
                                case "NAPTR":
                                    newRecord.order = parseInt(record.order, 10);
                                    newRecord.preference = parseInt(record.preference, 10);
                                    newRecord.flags = record.flags;
                                    newRecord.service = record.service;
                                    newRecord.regexp = record.regexp;
                                    newRecord.replacement = record.replacement;
                                    break;
                                case "PTR":
                                    newRecord.ptrdname = Zones.trimTrailingDot(record.record);
                                    newRecord.record = Zones.trimTrailingDot(record.record);
                                    break;
                                case "RP":
                                    newRecord.mbox = record.mbox;
                                    newRecord.txtdname = record.txtdname;
                                    break;
                                case "SRV":
                                    newRecord.priority = parseInt(record.priority, 10);
                                    newRecord.weight = parseInt(record.weight, 10);
                                    newRecord.port = parseInt(record.port, 10);
                                    newRecord.target = record.target;
                                    break;
                                case "SOA":
                                    newRecord.serial = record.serial;
                                    newRecord.mname = record.mname;
                                    newRecord.retry = parseInt(record.retry, 10);
                                    newRecord.refresh = parseInt(record.refresh, 10);
                                    newRecord.expire = parseInt(record.expire, 10);
                                    newRecord.rname = record.rname;
                                    break;
                                case "TXT":
                                    newRecord.txtdata = record.txtdata;

                                    if (record.is_dmarc) {
                                        new_dmarc.fromTXT(newRecord.txtdata[0]);
                                    }
                                    break;
                            }
                            newRecord.line_index = record.line_index;
                        }

                        newRecord.id_prefix = newRecord.record_type.toLowerCase();

                        newRecord.cache = angular.copy(newRecord);

                        newRecord.typeEditingLocked = newRecord.record_type === "SOA" || newRecord.is_dmarc;

                        newRecord.getSetRName = manage.getSetRName.bind(this, "rname");
                        newRecord.getSetMBOX = manage.getSetRName.bind(this, "mbox");

                        Object.assign(
                            this,
                            newRecord,
                            new_dmarc,
                            DMARCRecord.prototype
                        );
                    }

                    manage.getSetRName = function getSetRName(property, newValue) {
                        if (angular.isDefined(newValue)) {
                            this[property] = manage.convertEmailToRName(newValue);
                        }
                        return manage.convertRNameToEmail(this[property]);
                    };

                    manage.convertRNameToEmail = function(rName) {
                        var email = rName;

                        // Separate the parts at escaped dots
                        // We will reassemble below
                        email = email.split(/\\\./g);

                        // Find the first unescaped dot and convert it
                        for (var i = 0; i < email.length; i++) {
                            if (email[i].indexOf(".") !== -1) {
                                email[i] = email[i].replace(".", "@");
                                break;
                            }
                        }

                        // Reassemble with unescaped dots
                        email = email.join(".");
                        return email;
                    };
                    manage.convertEmailToRName = function(email) {
                        var rName = email;

                        // Split the email at the "@"
                        rName = rName.split("@");

                        // Escape dots before the "@"
                        rName[0] = rName[0].replace(/\./g, "\\.");

                        // Reassemble the parts with a dot
                        rName = rName.join(".");

                        return rName;
                    };

                    manage.selectDMARCTab = function(zone_rec, tab) {
                        if (tab === "RAW") {
                            zone_rec.rawTabSelected = true;
                            manage.updateTXTFromDMARCRecord(zone_rec);
                        } else {
                            manage.updateDMARCRecordFromTXT(zone_rec);
                            zone_rec.rawTabSelected = false;
                        }
                    };

                    manage.updateDMARCRecordFromTXT = function(record) {
                        record.fromTXT(record.txtdata);
                    };

                    manage.updateTXTFromDMARCRecord = function(record) {
                        record.txtdata = record.toString();
                    };

                    manage.isActionBtnVisible = function() {
                        return Features.whmOnly || Features.advanced;
                    };

                    manage.isFormEditing = function() {
                        var record;
                        for (var i = 0, len = manage.filteredList.length; i < len; i++) {
                            record = manage.filteredList[i];
                            if (record.editing) {
                                return true;
                            }
                        }
                        return false;
                    };

                    manage.viewRawZone = function viewRawZone() {
                        viewNavigationApi.loadView("/manage/copyzone", { domain: this.domain } );
                    };

                    var table = new DynamicTable();

                    function searchByNameOrData(item, searchText) {

                        if (item.name) {
                            if (item.name.indexOf(searchText) !== -1) {
                                return true;
                            }
                        } else if (item.is_new === "1") {
                            return true;
                        }

                        return RecordData.searchByType[item.record_type](item, searchText);
                    }

                    function searchByType(item, type) {
                        return item.record_type === type || item.is_new === "1";
                    }

                    function filterListFilter() {

                        // Return if manage.types already exist.
                        if (manage.types && manage.types.length > 0) {
                            return;
                        }

                        var types = _.sortBy(_.uniq(_.map(manage.zone_records, function(record) {
                            return record.record_type;
                        })));
                        manage.types = _.filter(types, function(type) {
                            return manage._featureAllowed(type);
                        });
                        revertToAllFilter();
                    }

                    function updateFilterListFilter(record, action) {
                        var typeGiven = record.record_type;
                        if (action === "add") {
                            if (!_.includes(manage.types, typeGiven)) {
                                manage.types = _.sortBy(_.concat(manage.types, typeGiven));
                            }
                        } else if (action === "remove") {

                            // Check if there exist any other records of the same type as the record which we removed.
                            // If not, then remove the type from manage.types.
                            var recordsOfGivenType = _.filter(manage.zone_records, function(recItem) {
                                if (recItem._id !== record._id && recItem.record_type === typeGiven) {
                                    return record;
                                }
                            });
                            if (recordsOfGivenType.length === 0) {
                                manage.types = _.sortBy(_.pull(manage.types, typeGiven));
                            }
                        }
                        revertToAllFilter();
                    }

                    function revertToAllFilter() {
                        if (!(manage.types.includes(manage.meta.quickFilterValue))) {
                            manage.meta.quickFilterValue = "";
                        }
                    }

                    function getDSAlgorithmById(id) {
                        var algorithmObj =  _.find(manage.dsAlgorithms, ["algorithmId", parseInt(id)]);
                        return (algorithmObj) ? algorithmObj.algorithm : "";
                    }

                    function getDSAlgorithmByAlgo(algo) {
                        var algorithmObj = _.find(manage.dsAlgorithms, ["algorithm", algo]);
                        return algorithmObj.algorithmId;
                    }

                    function getDSDigestTypeId(id) {
                        var digestObj = _.find(manage.dsDigTypes, ["digTypeId", parseInt(id)]);
                        return (digestObj) ? digestObj.digType : "";
                    }

                    function getDSDigestTypeAlgo(algo) {
                        var digestObj = _.find(manage.dsDigTypes, ["digType", algo]);
                        return digestObj.digTypeId;
                    }


                    table.setFilterFunction(searchByNameOrData);
                    table.setQuickFilterFunction(searchByType);
                    table.meta.pageSize = defaultInfo.zones_per_page;

                    manage.meta = table.getMetadata();
                    manage.filteredList = table.getList();
                    manage.paginationMessage = table.paginationMessage;

                    manage.checkRecordSets = function() {
                        var errs = _getRecordSetErrors(this.zone_records);

                        if (errs.length) {
                            var html = errs.map( function(m) {

                                // It’s unideal to mess with HTML in a
                                // controller but more or less necessary
                                // since alertService requires HTML.
                                return "<p>" + m + "</p>";
                            } ).join("");

                            alertService.add({
                                type: "danger",
                                id: _RECORD_SET_ERR_ALERT_ID,
                                message: html,
                                closeable: true,
                                replace: true,
                                group: _ALERT_GROUP,
                            });
                        } else {
                            alertService.removeById(_RECORD_SET_ERR_ALERT_ID, _ALERT_GROUP);
                            return true;
                        }

                        return false;
                    };

                    manage.render = function() {
                        manage.filteredList = table.populate();
                    };
                    manage.sortList = function() {
                        manage.render();
                    };
                    manage.selectPage = function() {
                        manage.render();
                    };
                    manage.selectPageSize = function() {
                        manage.render();
                        if (defaultInfo.zones_per_page !== table.meta.pageSize) {
                            nvDataService.setObject(
                                {
                                    zones_per_page: table.meta.pageSize,
                                })
                                .then(function() {
                                    defaultInfo.zones_per_page = table.meta.pageSize;
                                })
                                .catch(function(error) {
                                    alertService.add({
                                        type: "danger",
                                        message: _.escape(error),
                                        closeable: true,
                                        replace: false,
                                        group: "zoneEditor",
                                    });
                                });
                        }
                    };
                    manage.searchList = function() {
                        manage.getFilteredResults();
                    };

                    manage.getFilteredResults = function() {
                        manage.filteredList = table.populate();
                    };

                    manage.dynamicPlaceholders = {
                        issue: LOCALE.maketext("Certificate Authority"),
                        iodef: LOCALE.maketext("Mail Address for Notifications"),
                    };

                    manage.dynamicTooltips = {
                        issue: LOCALE.maketext("The certificate authority’s domain name."),
                        iodef: LOCALE.maketext("The location to which the certificate authority will report exceptions. Either a [asis,mailto] or standard [asis,URL]."),
                    };

                    manage.valueTooltip = function(idx) {
                        if (manage.filteredList[idx].tag === "iodef") {
                            return manage.dynamicTooltips.iodef;
                        }

                        return manage.dynamicTooltips.issue;
                    };

                    manage.valuePlaceholder = function(idx) {
                        if (manage.filteredList[idx].tag === "iodef") {
                            return manage.dynamicPlaceholders.iodef;
                        }

                        return manage.dynamicPlaceholders.issue;
                    };

                    function RemoveRecordModalController($uibModalInstance, record) {
                        var ctrl = this;
                        ctrl.record = record;

                        ctrl.cancel = function() {
                            $uibModalInstance.dismiss("cancel");
                        };
                        ctrl.confirm = function() {
                            var lineIdx = [record.line_index];
                            return Zones.remove_zone_record(manage.domain, lineIdx, manage.serial)
                                .then(function() {
                                    if (record.record_type === "MX" && record.name === manage.domain + ".") {
                                        alertService.add({
                                            type: "success",
                                            message: LOCALE.maketext("You successfully deleted the [_1] record.", _.escape(record.record_type)),
                                            closeable: true,
                                            replace: false,
                                            autoClose: 10000,
                                            group: "zoneEditor",
                                        });
                                    } else {
                                        alertService.add({
                                            type: "success",
                                            message: LOCALE.maketext("You successfully deleted the [_1] record: [_2]", record.record_type, _.escape(record.name)),
                                            closeable: true,
                                            replace: false,
                                            autoClose: 10000,
                                            group: "zoneEditor",
                                        });
                                    }
                                    updateFilterListFilter(record, "remove");
                                    manage.refresh();
                                })
                                .catch(function(error) {
                                    alertService.add({
                                        type: "danger",
                                        message: _.escape(error),
                                        closeable: true,
                                        replace: false,
                                        group: "zoneEditor",
                                    });
                                })
                                .finally(function() {
                                    $uibModalInstance.close();
                                });
                        };
                    }

                    RemoveRecordModalController.$inject = [ "$uibModalInstance", "record" ];

                    function ResetZoneModalController($uibModalInstance) {
                        var ctrl = this;
                        manage.recordsInProgress = [];

                        ctrl.cancel = function() {
                            $uibModalInstance.dismiss("cancel");
                        };
                        ctrl.confirm = function() {
                            return Zones.reset_zone(manage.domain)
                                .then(function() {
                                    alertService.add({
                                        type: "success",
                                        message: LOCALE.maketext("You successfully reset the zone for “[_1]”.", _.escape(manage.domain)),
                                        closeable: true,
                                        replace: false,
                                        autoClose: 10000,
                                        group: "zoneEditor",
                                    });
                                    manage.refresh();
                                })
                                .catch(function(error) {
                                    alertService.add({
                                        type: "danger",
                                        message: _.escape(error),
                                        closeable: true,
                                        replace: false,
                                        group: "zoneEditor",
                                    });
                                })
                                .finally(function() {
                                    $uibModalInstance.close();
                                });
                        };
                    }

                    ResetZoneModalController.$inject = [ "$uibModalInstance" ];

                    manage.emailRoutingConfigLink = function() {
                        var link;
                        if (Features.whmOnly) {
                            link = CJT.protocol + "//" + CJT.domain + ":" + CJT.port + CJT.securityToken + "/scripts/doeditmx?domainselect=" + manage.domain;
                        } else {
                            link = location.origin + PAGE.securityToken + "/frontend/" + PAGE.theme + "/mail/email_routing.html";
                        }
                        return link;
                    };

                    manage.copyTextToClipboard = function() {
                        var textarea = document.createElement("textarea");
                        var copyText = document.getElementById("zoneFileText").textContent;
                        textarea.value = copyText;
                        document.body.appendChild(textarea);
                        textarea.select();
                        var copyResult = document.execCommand("copy");
                        if (copyResult) {
                            alertService.add({
                                type: "success",
                                message: LOCALE.maketext("Successfully copied to the clipboard."),
                                closeable: true,
                                autoClose: 10000,
                                group: "zoneEditor",
                            });

                        } else {
                            alertService.add({
                                type: "danger",
                                message: LOCALE.maketext("Copy failed."),
                                closeable: true,
                                replace: false,
                                group: "zoneEditor",
                            });
                        }
                        document.body.removeChild(textarea);
                    };

                    manage.copy_zone_file = function() {
                        manage.copyMode = true;
                    };

                    manage.returnToEditor = function() {
                        manage.copyMode = false;
                    };


                    manage.createNewRecord = function(recordType) {
                        var type = recordType || "";
                        var record = {
                            record_type: recordType,
                            editing: true,
                            is_new: "1",
                        };

                        if (!type) {
                            if (Features.mx && !Features.simple && !Features.advanced) {
                                record.record_type = "MX";
                            } else {
                                record.record_type = "A";
                            }
                        }
                        var new_dmarc = new DMARCRecord();

                        var parsedRecord = new Record(record, new_dmarc);

                        manage.zone_records.push(parsedRecord);
                    };

                    manage.cancelRecordEdit = function(record, idx) {

                        // user cancels editing of existing record
                        if (record && record.is_new === "0") {
                            var cache = record.cache;
                            for (var key in cache) {
                                if (key) {
                                    record[key] = cache[key];
                                }
                            }
                            record.cache = cache;
                            record.editing = false;

                        // user cancels editing of new record
                        } else if (record && record.is_new === "1") {
                            manage.zone_records.splice(idx, 1);
                        } else {

                            // all records are cancelled
                            manage.zone_records.forEach(function(record) {
                                record.editing = false;
                            });
                        }
                    };

                    function formatSubmitObj(records) {
                        var submitObjs = records.map(function(record) {
                            var parsedRecord = {
                                dname: record.name,
                                ttl: record.ttl,
                                record_type: record.record_type,
                                line_index: record.line_index,
                                data: [],
                                is_new: record.is_new === "1",
                            };

                            // WARNING: THE ORDER OF EACH .push() IS SPECIFIC AND CAN NOT CHANGE
                            // It is the order of zone file data columns for the specific record type
                            switch (record.record_type) {
                                case "SOA":
                                    parsedRecord.data.push(record.mname);
                                    parsedRecord.data.push(record.rname);
                                    parsedRecord.data.push(parseInt(record.serial, 10));
                                    parsedRecord.data.push(parseInt(record.refresh));
                                    parsedRecord.data.push(parseInt(record.retry, 10));
                                    parsedRecord.data.push(parseInt(record.expire, 10));
                                    parsedRecord.data.push(parseInt(record.ttl, 10));
                                    break;
                                case "A":
                                    parsedRecord.data.push(record.a_address);
                                    break;
                                case "AAAA":
                                    parsedRecord.data.push(record.aaaa_address);
                                    break;
                                case "AFSDB":
                                    parsedRecord.data.push(record.subtype);
                                    parsedRecord.data.push(record.hostname);
                                    break;
                                case "ALIAS":
                                    parsedRecord.data.push(record.alias);
                                    break;
                                case "CAA":
                                    parsedRecord.data.push(record.flag);
                                    parsedRecord.data.push(record.tag);
                                    parsedRecord.data.push(record.value);
                                    break;
                                case "CNAME":
                                    parsedRecord.data.push(record.cname);
                                    break;
                                case "DNAME":
                                    parsedRecord.data.push(record.dname);
                                    break;
                                case "DS":
                                    parsedRecord.data.push(parseInt(record.keytag, 10));
                                    parsedRecord.data.push(getDSAlgorithmByAlgo(record.algorithm));
                                    parsedRecord.data.push(getDSDigestTypeAlgo(record.digtype));
                                    parsedRecord.data.push(record.digest);
                                    break;
                                case "HINFO":
                                    parsedRecord.data.push(record.cpu);
                                    parsedRecord.data.push(record.os);
                                    break;
                                case "LOC":
                                    parsedRecord.data.push(record.latitude);
                                    parsedRecord.data.push(record.longitude);
                                    parsedRecord.data.push(record.altitude + "m");
                                    parsedRecord.data.push(record.size + "m");
                                    parsedRecord.data.push(record.horiz_pre + "m");
                                    parsedRecord.data.push(record.vert_pre + "m");
                                    break;
                                case "MX":
                                    parsedRecord.data.push(parseInt(record.priority, 10));
                                    parsedRecord.data.push(record.exchange);
                                    break;
                                case "NS":
                                    parsedRecord.data.push(record.nsdname);
                                    break;
                                case "NAPTR":
                                    parsedRecord.data.push(parseInt(record.order, 10));
                                    parsedRecord.data.push(parseInt(record.preference, 10));
                                    parsedRecord.data.push(record.flags);
                                    parsedRecord.data.push(record.service);
                                    parsedRecord.data.push(record.regexp);
                                    parsedRecord.data.push(record.replacement);
                                    break;
                                case "PTR":
                                    parsedRecord.data.push(record.ptrdname);
                                    break;
                                case "RP":
                                    parsedRecord.data.push(record.mbox || ".");
                                    parsedRecord.data.push(record.txtdname || ".");
                                    break;
                                case "SRV":
                                    parsedRecord.data.push(parseInt(record.priority, 10));
                                    parsedRecord.data.push(parseInt(record.weight, 10));
                                    parsedRecord.data.push(parseInt(record.port, 10));
                                    parsedRecord.data.push(record.target);
                                    break;
                                case "TXT":
                                    if (!record.is_dmarc) {
                                        parsedRecord.data = record.txtdata;
                                    } else {
                                        if (!record.rawTabSelected) {
                                            manage.updateTXTFromDMARCRecord(record);
                                        }
                                        parsedRecord.data.push(record.txtdata);
                                    }
                                    break;
                            }
                            return parsedRecord;
                        });
                        return submitObjs;
                    }

                    manage.getAddFormState = function() {
                        return manage.add_zr_form.$invalid ? "invalid" : "valid";
                    };

                    manage.isEditingRecords = function() {
                        var record;
                        for (var i = 0, len = manage.zone_records.length; i < len; i++) {
                            record = manage.zone_records[i];
                            if (record.editing) {
                                return true;
                            }
                        }
                        return false;
                    };

                    manage.handleRowKeypress = function handleRowKeypress(event, zone_rec) {

                        // cf. https://www.tjvantoll.com/2013/01/01/enter-should-submit-forms-stop-messing-with-that/
                        if (zone_rec.editing && (event.keyCode === 13)) {

                            // Don’t click() the form’s first submit button:
                            event.preventDefault();

                            // Don’t submit() the form:
                            event.stopPropagation();

                            var submitter = document.getElementById("inline_add_record_button_" + zone_rec._id);

                            // Defer the record-submitter’s click() button
                            $timeout(function() {
                                submitter.click();
                            }, 0);
                        }
                    };

                    manage.saveRecords = function(record) {
                        var saveArgs;

                        if (manage.add_zr_form.$invalid) {

                            // if the user click 'Save All' set all controls to dirty
                            if (!record) {
                                for (var key in manage.add_zr_form) {
                                    if (manage.add_zr_form[key] && manage.add_zr_form[key].$setDirty) {
                                        manage.add_zr_form[key].$setDirty();
                                    }
                                }

                            // if user clicks 'Save Record' from a specific row check if any of the specific controls are invalid
                            // save the records if they are valid
                            } else {
                                var ctrlRegex = new RegExp("_" + record._id + "$");
                                var ctrls = [];
                                for (var formKey in manage.add_zr_form) {
                                    if (formKey) {
                                        var isCtrl;
                                        isCtrl = ctrlRegex.test(formKey);
                                        if (isCtrl) {
                                            ctrls.push(manage.add_zr_form[formKey]);
                                        }
                                    }
                                }
                                var invalidCtrls = ctrls.filter(function(ctrl) {
                                    return ctrl.$invalid;
                                });
                                if (invalidCtrls.length) {
                                    invalidCtrls.forEach(function(ctrl) {
                                        ctrl.$setDirty();
                                    });
                                } else {
                                    saveArgs = [record];
                                }
                            }
                        } else {
                            saveArgs = record ? [record] : [];
                        }

                        if (saveArgs && this.checkRecordSets()) {
                            return manage._saveRecords.apply(manage, saveArgs);
                        }
                    };

                    manage._saveRecords = function(record) {
                        var recordsToSubmit = [];
                        manage.recordsInProgress = [];
                        var filteredRecords = _.filter(manage.zone_records, "editing");
                        if (record) {
                            var idx = filteredRecords.indexOf(record);
                            filteredRecords.splice(idx, 1);
                            manage.recordsInProgress = filteredRecords;
                            recordsToSubmit.push(record);
                        } else {
                            recordsToSubmit = filteredRecords;
                        }


                        recordsToSubmit.forEach(function(record) {
                            if (record.is_new) {
                                updateFilterListFilter(record, "add");
                            }
                        });

                        var submitObjs = formatSubmitObj(recordsToSubmit);

                        manage.save_in_progress = true;
                        return Zones.saveRecords(manage.domain, submitObjs, manage.serial)
                            .then(function() {
                                if (recordsToSubmit.length > 1) {
                                    alertService.add({
                                        type: "success",
                                        message: LOCALE.maketext("You successfully saved [quant,_1,record,records] for “[_2]”.", recordsToSubmit.length, _.escape(manage.domain)),
                                        closeable: true,
                                        replace: false,
                                        autoClose: 10000,
                                        group: "zoneEditor",
                                    });
                                } else {
                                    var messageRecord = recordsToSubmit[0];
                                    alertService.add({
                                        type: "success",
                                        message: LOCALE.maketext("You successfully saved the following [_1] record for “[_2]”: “[_3]”.", messageRecord.record_type, _.escape(manage.domain), _.escape(Zones.trimTrailingDot(messageRecord.name))),
                                        closeable: true,
                                        replace: false,
                                        autoClose: 10000,
                                        group: "zoneEditor",
                                    });
                                }

                                return load();
                            }).catch(function(error) {
                                alertService.add({
                                    type: "danger",
                                    message: _.escape(error),
                                    closeable: true,
                                    replace: false,
                                    group: "zoneEditor",
                                });
                            }).finally(function() {
                                manage.save_in_progress = false;
                            });
                    };

                    manage.field_has_error = function(form, fieldName) {
                        return form && fieldName && form[fieldName] && form[ fieldName ].$invalid && form[ fieldName ].$dirty;
                    };

                    // sorts the list so that new record rows are added to the top
                    // can not add new record to beginning of the array because the DOM does not re-render. multiple form fields end up having the same index, which means there are not unique ids. new record must be added to end of array to guarantee unique ids for every field
                    // can not manipulate DOM directly after adding record to array, as the actual DOM has not re-rendered yet and element does not exist yet
                    $scope.$watchCollection("manage.zone_records", function(newValue) {
                        manage.zone_records = _.sortBy(newValue, [function(record) {
                            record.cache = angular.copy(record);
                            return record.is_new !== "1";
                        }]);
                        table.loadData(manage.zone_records);
                        manage.filteredList = table.populate();
                    });

                    manage.edit_record = function(zoneRecord) {
                        zoneRecord.editing = true;
                    };

                    manage.confirm_delete_record = function(record) {
                        manage.cancelRecordEdit();
                        $uibModal.open({
                            templateUrl: "confirm_delete.html",
                            controller: RemoveRecordModalController,
                            controllerAs: "ctrl",
                            resolve: {
                                record: function() {
                                    return record;
                                },
                            },
                        });
                    };

                    manage.confirm_reset_zone = function() {

                        // we do not want the user to do a reset if they are editing/adding
                        if (manage.isFormEditing()) {
                            return;
                        }

                        $uibModal.open({
                            templateUrl: "confirm_reset_zone.html",
                            controller: ResetZoneModalController,
                            controllerAs: "ctrl",
                        });
                    };

                    manage.refresh = function() {

                        // we do not want the user to refresh if they are editing/adding
                        if (manage.isFormEditing()) {
                            return;
                        }

                        return load();
                    };

                    function load() {
                        manage.is_loading = true;
                        return Zones.fetch(manage.domain)
                            .then(function(data) {
                                var recordData = data.parsedZoneData;
                                manage.default_ttl = data.defaultTTL;

                                manage.zone_records = [];
                                var dmarc_record = new DMARCRecord();
                                for (var i = 0, len = recordData.length; i < len; i++) {
                                    var zoneRecord = recordData[i];

                                    // if the user does not have the advanced feature,
                                    // do not display records that are cpanel generated/controlled
                                    if (Features.simple &&
                                    !Features.advanced &&
                                    zoneRecord.record_type !== "MX" &&
                                    manage.generated_domains[ zoneRecord.name ]) {
                                        continue;
                                    }

                                    if (
                                        ((zoneRecord.record_type === "A" || zoneRecord.record_type === "CNAME") && manage.Features.simple) ||
                                        (zoneRecord.record_type === "MX" && manage.Features.mx) ||
                                        (zoneRecord.record_type !== "MX" && manage.Features.advanced)
                                    ) {
                                        zoneRecord.is_new = "0";
                                        zoneRecord = new Record(zoneRecord, dmarc_record);
                                        zoneRecord.editing = false;
                                        manage.zone_records.push(zoneRecord);
                                    }

                                    if (zoneRecord.record_type === "ALIAS") {
                                        if (!PAGE.is_alias_available) {
                                            zoneRecord.isEditable = false;
                                            zoneRecord.alias_unsupported = true;
                                        }
                                    }
                                }
                                filterListFilter();
                                manage.cancelRecordEdit();
                                manage.recordsInProgress.forEach(function(record) {
                                    if (record.is_new === "1") {
                                        manage.zone_records.push(record);
                                    } else {
                                        var removeRecord = manage.zone_records.filter(function(rRecord) {
                                            return rRecord.line_index === record.line_index;
                                        });
                                        removeRecord = removeRecord[0];
                                        var idx = manage.zone_records.indexOf(removeRecord);
                                        manage.zone_records.splice(idx, 1, record);
                                    }
                                });
                                var soa = manage.zone_records.find(function(record) {
                                    return record.record_type === "SOA";
                                });

                                manage.serial = soa ? soa.serial : null;
                            })
                            .catch(function(error) {

                                // If we get an error at this point, we assume that the user
                                // should not be able to do anything on the page.
                                manage.loading_error = true;
                                manage.loading_error_message = _.escape(error);
                            })
                            .finally(function() {
                                manage.is_loading = false;
                                manage.add_zr_form.$setPristine();
                            });
                    }

                    manage.updateRecordTemplate = function(record) {
                        record.editTemplate = manage.getRecordTemplate(record);
                    };

                    manage._findRecordTypeByType = function(type) {
                        for (var i = 0; i < manage.recordTypes.length; i++) {
                            if (manage.recordTypes[ i ].type === type) {
                                return manage.recordTypes[ i ];
                            }
                        }
                        return null;
                    };

                    manage.viewRecordTemplates = function(type) {
                        var view = "";

                        manage.recordTypes.forEach(function(record) {
                            if (record.type === type) {
                                view = record.viewTemplate;
                            }
                        });

                        return view;
                    };


                    manage._featureAllowed = function(type) {
                        var allowed = false;
                        switch (type) {
                            case "A":
                            case "CNAME":
                                allowed = (manage.Features.simple || manage.Features.advanced);
                                break;
                            case "MX":
                                allowed = manage.Features.mx;
                                break;
                            case "SRV":
                            case "AAAA":
                            case "ALIAS":
                            case "CAA":
                            case "TXT":
                                allowed = manage.Features.advanced;
                                break;
                            case "DNAME":
                            case "HINFO":
                            case "NS":
                            case "RP":
                            case "PTR":
                            case "NAPTR":
                            case "DS":
                            case "AFSDB":
                            case "SOA":
                            case "LOC":
                                allowed = manage.Features.whmOnly;
                                break;
                        }
                        return allowed;
                    };

                    manage.filterRowRecordsDisplay = function(record) {
                        var disallowedTypes = ["SOA", "DMARC"];
                        if (!PAGE.is_alias_available) {
                            disallowedTypes.push("ALIAS");
                        }
                        return (disallowedTypes.indexOf(record.type) === -1);
                    };

                    manage.filterAddRecordDisplay = function(record) {
                        var disallowedTypes = ["SOA"];
                        if (!PAGE.is_alias_available) {
                            disallowedTypes.push("ALIAS");
                        }
                        return (disallowedTypes.indexOf(record.type) === -1);
                    };

                    manage.getRecordTemplate = function(record) {
                        var recordType = record.record_type;

                        if (record.is_dmarc) {
                            recordType = "DMARC";
                        }

                        var recordTypeObj = manage._findRecordTypeByType(recordType);
                        var template = recordTypeObj ? recordTypeObj.template : "";
                        return template;
                    };

                    manage.init = function() {
                        manage.is_loading = true;
                        if (!Features.whmOnly || (Features.whmOnly && $location.path() === "/manage/")) {
                            if (defaultInfo.otherRecordsInterface) {
                                manage.showOtherRecordTypeOption = true;
                                manage.otherRecordTypeHref = defaultInfo.otherRecordsInterface + "?domainselect=" + manage.domain;
                            }
                            $recordTypes.get().then(function _recordTypesReceived(recordTypes) {
                                manage.recordTypes = recordTypes;
                            });

                            return Zones.fetch_generated_domains(manage.domain, true)
                                .then(function(data) {
                                    manage.generated_domains = data;
                                    return load();
                                })
                                .catch(function(error) {
                                    manage.loading_error = true;
                                    manage.loading_error_message = _.escape(error);
                                });
                        } else {
                            if (Features.whmOnly) {
                                Zones.exportZoneFile(manage.domain).then(function(response) {
                                    manage.copyable_zone_file = response.trim();
                                    manage.is_loading = false;
                                });
                            }
                        }

                    };

                    manage.init();
                },
            ]);

        return {
            namespace: MODULE_NAMESPACE,
        };
    }

);
Back to Directory File Manager