Viewing File: /usr/local/cpanel/base/frontend/jupiter/domains/views/createDomain.js

/*
# domains/views/createDomain.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
*/

/* global define */

/** @namespace cpanel.domains.views.createDomain */

define(
    [
        "lodash",
        "angular",
        "cjt/util/locale",
        "cjt/services/fuzzy",
        "cjt/modules",
        "ngRoute",
        "cjt/directives/callout",
        "cjt/validator/domain-validators",
        "cjt/validator/username-validators",
        "cjt/directives/actionButtonDirective",
        "app/services/domains",
        "cjt/directives/validationContainerDirective",
        "cjt/directives/validationItemDirective",
        "cjt/directives/toggleSwitchDirective",
    ],
    function(_, angular, LOCALE, Fuzzy) {

        "use strict";

        var fuzzyService = new Fuzzy();

        var MODULE_NAMESPACE = "cpanel.domains.views.createDomain";

        var app = angular.module(MODULE_NAMESPACE, [
            "cpanel.domains.domains.service",
            "ngRoute",
            "cjt2.services.alert",
        ]);

        /**
         * Create Controller for Domains
         *
         * @module createDomain
         *
         * @param  {Object} $scope angular scope
         *
         */

        var CONTROLLER_NAME = "createDomain";
        app.controller(
            CONTROLLER_NAME,
            ["$scope", "$log", "$location", "$routeParams", "$timeout", "domains", "alertService", "domainTypes", "DOMAIN_TYPE_CONSTANTS", "PAGE", "ZONE_EDITOR_APP_OBJ",
                function($scope, $log, $location, $routeParams, $timeout, $domainsService, $alertService, domainTypes, DOMAIN_TYPE_CONSTANTS, PAGE, ZONE_EDITOR_APP_OBJ) {

                    var _domainTypesMap = {};
                    var _featureMap = {};

                    function init() {

                        domainTypes.forEach(function(domainType) {
                            _domainTypesMap[domainType.value] = domainType;
                            _featureMap[domainType.value] = PAGE.features[domainType.value];
                        });

                        $scope.resetForm();

                        if ($routeParams["domain"]) {
                            $scope.newDomain.newDomainName = $routeParams["domain"];
                            updateDomainType();
                            generateDocumentRoot();
                            generateSubdomain($scope.newDomain.newDomainName);
                        }

                        document.addEventListener('cp-alert-message', function(event) {
                            $scope.$apply(function() {
                                $alertService.add({
                                    type: event.detail.type,
                                    message: event.detail.message,
                                    dismissible: event.detail.dismissible !== undefined ? event.detail.dismissible : true,
                                    replace: event.detail.replace || false,
                                    id: event.detail.id,
                                    autoClose: event.detail.autoClose,
                                });
                            });
                        });

                        _updateFuzzyService();

                        if (!PAGE.hasWebServerRole && ZONE_EDITOR_APP_OBJ) {
                            $scope.creationMessages.push({
                                type: "info",
                                message: LOCALE.maketext("Because this server does not use the “[_1]” role, the system creates new domains as separate zones. If you only need a [asis,DNS] entry, you can add the domain as new record on an existing zone in the [output,url,_2,_3,_4] interface.", "WebServer", ZONE_EDITOR_APP_OBJ.url, ZONE_EDITOR_APP_OBJ.itemdesc, { _type: "offsite" }),
                            });
                        }
                    }

                    function _updateFuzzyService() {

                        $domainsService.get().then(function(domains) {
                            var flattenedDomains = domains.filter(function(domain) {
                                if (domain.canBeSuggested) {
                                    return true;
                                }
                                return false;
                            }).map(function(domain) {
                                return domain.domain;
                            });

                            fuzzyService.loadSet(flattenedDomains);
                        });

                        if (!PAGE.hasWebServerRole) {
                            $scope.mustInheritDocumentRoot = true;
                        }

                    }

                    function _showCreationDelayedMessage() {
                        $scope.creationDelayed = true;
                    }

                    function _getDomain(domain) {
                        return $domainsService.findDomainByName(domain);
                    }

                    function _getDomainType(domainType) {
                        return _domainTypesMap[domainType];
                    }

                    function _generateSuggestions(domainParts) {
                        var suffix = domainParts.slice(domainParts.length - 2).join(".");

                        // Remove the last part
                        domainParts.pop();
                        domainParts.pop();

                        var subdomainsOnly = !$scope.canCreateDomainType(DOMAIN_TYPE_CONSTANTS.ALIAS) && !$scope.canCreateDomainType(DOMAIN_TYPE_CONSTANTS.ADDON);
                        var domainsThreshold = !subdomainsOnly ? 4 : 10;

                        var fuzzyResults = fuzzyService.search(suffix);

                        var topResults = fuzzyResults.filter(function(fuzzyResult) {
                            return fuzzyResult.distance < domainsThreshold;
                        });


                        if (topResults.length) {
                            var topMatchDomain = domainParts.join(".") + "." + fuzzyResults[0].match;

                            $scope.newDomain.domain = $domainsService.getMainDomain().domain;
                            $scope.clearSuggestedDomains();

                            if (topMatchDomain !== $scope.newDomain.newDomainName) {

                                // Looks like a subdomain.
                                // List the top 5 domains only.
                                $scope.suggestedDomains = topResults.slice(0, 5).map(function(fuzzyResult) {
                                    var suggestedDomain = domainParts.join(".") + "." + fuzzyResult.match;
                                    return {
                                        domain: suggestedDomain,
                                        closeable: !subdomainsOnly,
                                        use: function() {
                                            useSuggestedDomain(suggestedDomain);
                                        },
                                        cancel: clearSuggestedDomains,
                                    };
                                });

                            }
                        }
                    }

                    function onUpdateNewDomainName() {

                        // Clear these on each update, so previous filled suggestions invalidate
                        $scope.subdomain = "";
                        $scope.domain = "";
                        $scope.documentRoot = "";
                        $scope.newDomain.isWildcard = false;

                        if (!$scope.newDomain.newDomainName) {
                            return;
                        }

                        if ($scope.newDomain.newDomainName.substr(0, 1) === "*") {

                            // looks like a wildcard
                            $scope.newDomain.isWildcard = true;
                        }

                        if (looksLikeSubdomain($scope.newDomain.newDomainName)) {

                            // Let's try not to make it a park, shall we?
                            $scope.newDomain.inheritDocumentRoot = false;
                        }

                        var domainParts = $scope.newDomain.newDomainName.split(".");
                        if (domainParts.length >= 3) {
                            _generateSuggestions(domainParts);
                        }

                        updateDomainType();
                        generateDocumentRoot();
                        generateSubdomain($scope.newDomain.newDomainName);
                    }

                    // Prevent doing silly things like making sub.$MAIN_DOMAIN from defaulting to an addon
                    function looksLikeSubdomain(domain) {
                        var parentDomainSplit = domain.split(".");
                        parentDomainSplit.shift();
                        var parentDomain = parentDomainSplit.join(".");
                        if (_getDomain(parentDomain)) {
                            return 1;
                        }
                        return 0;
                    }

                    function generateDocumentRoot() {

                        if (!$scope.newDomain.newDomainName) {
                            return;
                        }

                        if ($scope.newDomain.domainType === DOMAIN_TYPE_CONSTANTS.ALIAS) {

                            // alias domain uses the main domain
                            $scope.newDomain.documentRoot = $scope.mainDomain.documentRoot.replace($scope.mainDomain.homedir + "/", "");
                            $scope.newDomain.fullDocumentRoot = $scope.mainDomain.documentRoot;
                        } else {
                            var newDocRoot = $scope.newDomain.newDomainName.replace("*", "_wildcard_");
                            $scope.newDomain.documentRoot = newDocRoot;
                            $scope.newDomain.fullDocumentRoot = $domainsService.generateFullDocumentRoot(newDocRoot);
                        }

                    }

                    function generateSubdomain(from) {

                        // Instead of one part, use the whole thing
                        $scope.newDomain.subdomain = from;
                    }

                    function getFormFieldClasses(form) {
                        return form && !form.$pristine && form.$invalid ? "col-xs-12 col-md-6" : "col-xs-12";
                    }

                    function resetForm() {

                        $scope.newDomain.newDomainName = "";
                        $scope.newDomain.documentRoot =  "";
                        if ($scope.shareDocrootDefault) {
                            $scope.newDomain.inheritDocumentRoot = $scope.canCreateDomainType(DOMAIN_TYPE_CONSTANTS.ALIAS);
                        } else {
                            $scope.newDomain.inheritDocumentRoot = false;
                        }
                        updateDomainType();
                        generateDocumentRoot();
                        generateSubdomain($scope.newDomain.newDomainName);

                    }

                    function createDomain(form, domainObject, createAnotherOnCompletion, callback) {

                        $scope.submittingForm = true;

                        // If this takes too long, let them know why.
                        var $timer = $timeout(_showCreationDelayedMessage, 1000);

                        // Copying here to allow editing for creatino of another domain without affecting this one
                        var submittingDomainObj = angular.copy(domainObject);

                        if (!PAGE.hasWebServerRole) {

                            // Override type. All domains are parked (alias) domains when there is no webserver role present
                            $log.debug("Because there is no webserver role on this system, the domain will be created as an alias domain.");
                            submittingDomainObj.domainType = DOMAIN_TYPE_CONSTANTS.ALIAS;
                        }

                        return $domainsService.add(submittingDomainObj).then(function() {

                            $log.debug("submittingDomainObj.fullDocumentRoot", submittingDomainObj.fullDocumentRoot);

                            var msg;
                            if (PAGE.hasWebServerRole) {
                                msg = LOCALE.maketext("You have successfully created the new “[_1]” domain with the document root of “[_2]”.", submittingDomainObj.newDomainName, _.escape(submittingDomainObj.fullDocumentRoot));
                            } else {
                                msg = LOCALE.maketext("You have successfully created the new “[_1]” domain.", submittingDomainObj.newDomainName);
                            }

                            $alertService.add({
                                type: "success",
                                message: msg,
                            });

                            if (!createAnotherOnCompletion) {
                                if (callback) {
                                    return callback(submittingDomainObj.newDomainName);
                                }
                                $location.path("/");
                            } else {
                                _updateFuzzyService();
                                $scope.resetForm();
                                _refocus();
                                form.$setPristine();
                            }
                        }).finally(function() {
                            $scope.creationDelayed = false;
                            $timeout.cancel($timer);
                            $scope.submittingForm = false;
                        });
                    }

                    function _refocus() {
                        angular.element(document).find("input[autofocus]").focus();
                    }

                    function updateDomainType() {

                        var domain = $scope.newDomain.newDomainName = $scope.newDomain.newDomainName.toLocaleLowerCase();

                        $scope.newDomain.domainType = "";

                        if (!$scope.newDomain.newDomainName) {
                            return;
                        }

                        if ($scope.newDomain.inheritDocumentRoot) {

                            // By default, it's a parked domain if it doesn't need its own document root.
                            $scope.newDomain.domainType = DOMAIN_TYPE_CONSTANTS.ALIAS;
                        } else {
                            var domainParts = domain.split(".");
                            if (domainParts.length > 2) {

                                // Possible Subdomain
                                // Excluding the very first part, do the combination of any
                                // other parts match an existing domain
                                var suffix;
                                for (var i = 1; i < domainParts.length; i++) {
                                    suffix = domainParts.slice(i).join(".");
                                    var matchingDomain = _getDomain(suffix);
                                    if (matchingDomain) {

                                        // Matches a domain, we should do this as a subdomain
                                        // to avoid creation of the additiona subdomain
                                        $scope.newDomain.domainType = DOMAIN_TYPE_CONSTANTS.SUBDOMAIN;
                                        $scope.newDomain.domain = suffix;
                                        $scope.newDomain.subdomain = domainParts.slice(0, i).join(".");
                                        break; // We want to attach to the longest domain
                                    }
                                }
                            }
                        }

                        if (!$scope.newDomain.domainType) {

                            // Must be an addon domain bar.com or foo.com
                            // if it made it this far without being set
                            $scope.newDomain.domainType = DOMAIN_TYPE_CONSTANTS.ADDON;
                            $scope.newDomain.domain = $scope.mainDomain.domain;
                        }

                    }

                    function useSuggestedDomain(suggestedDomain) {
                        $scope.newDomain.newDomainName = suggestedDomain;
                        updateDomainType();
                        generateDocumentRoot();
                        $scope.clearSuggestedDomains();
                    }

                    function clearSuggestedDomains() {
                        $scope.suggestedDomains = [];
                    }

                    function onToggleInheritDocumentRoot() {
                        updateDomainType();
                        generateDocumentRoot();
                    }

                    function canCreateDomainType(domainType) {

                        // Don't bother checking anything else if the feature isn't enabled
                        if ( !_featureMap[domainType] ) {
                            return false;
                        }

                        var domainTypeObject = _getDomainType(domainType);

                        var domainName = $scope.newDomain.newDomainName || "";
                        if (domainName.substr(0, 2) === "*.") {

                            // parked and addon domains can't be wildcards
                            if (domainType === DOMAIN_TYPE_CONSTANTS.ADDON || domainType === DOMAIN_TYPE_CONSTANTS.ALIAS) {
                                return false;
                            }
                        }
                        return !domainTypeObject.overLimit;

                    }

                    function canCreateDomains() {
                        return $scope.canCreateDomainType(DOMAIN_TYPE_CONSTANTS.ALIAS) || $scope.canCreateDomainType(DOMAIN_TYPE_CONSTANTS.ADDON) || $scope.canCreateDomainType(DOMAIN_TYPE_CONSTANTS.SUBDOMAIN);
                    }

                    function inheritDocRootSelectionDisabled() {
                        return !$scope.canCreateDomainType(DOMAIN_TYPE_CONSTANTS.ALIAS) || (!$scope.canCreateDomainType(DOMAIN_TYPE_CONSTANTS.SUBDOMAIN) && !$scope.canCreateDomainType(DOMAIN_TYPE_CONSTANTS.ADDON));
                    }

                    function onDocumentRootUpdated() {
                        $scope.newDomain.fullDocumentRoot = $domainsService.generateFullDocumentRoot($scope.newDomain.documentRoot);
                    }

                    angular.extend($scope, {
                        creationMessages: [],
                        DOMAIN_TYPE_CONSTANTS: DOMAIN_TYPE_CONSTANTS,
                        submittingForm: false,
                        creationDelayed: false,
                        upgradeUrl: PAGE.upgradeUrl,
                        domainsConfig: PAGE.domainsConfig || {
                            showDocumentRoot: true,
                            showSubdomain: true,
                            showSubmitAnother: true,
                            returnUrl: '#/',
                            returnText: LOCALE.maketext("Return to Domains"),
                        },
                        documentRootPattern: $domainsService.getDocumentRootPattern(),
                        suggestedDomains: [],
                        domainTypes: domainTypes,
                        requirePublicHTMLSubs: PAGE.requirePublicHTMLSubs.toString() === "1",
                        shareDocrootDefault: PAGE.shareDocrootDefault.toString() === "1",
                        mainDomain: $domainsService.getMainDomain(),
                        newDomain: {},
                        getFormFieldClasses: getFormFieldClasses,
                        resetForm: resetForm,
                        createDomain: createDomain,
                        onUpdateNewDomainName: onUpdateNewDomainName,
                        useSuggestedDomain: useSuggestedDomain,
                        clearSuggestedDomains: clearSuggestedDomains,
                        onToggleInheritDocumentRoot: onToggleInheritDocumentRoot,
                        onDocumentRootUpdated: onDocumentRootUpdated,
                        canCreateDomainType: canCreateDomainType,
                        canCreateDomains: canCreateDomains,
                        inheritDocRootSelectionDisabled: inheritDocRootSelectionDisabled,
                    });

                    init();

                },
            ]
        );

        return {
            namespace: MODULE_NAMESPACE,
            controllerName: CONTROLLER_NAME,
        };
    }
);
Back to Directory File Manager