Viewing File: /usr/local/cpanel/whostmgr/docroot/templates/gsw/initial_setup/index.cmb.js

/*
 * services/setupService.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
 */

/* eslint-env amd */

define('app/services/setupService',[
    "angular",
    "cjt/io/whm-v1-request",
    "cjt/io/whm-v1",
    "cjt/services/APIService",
    "cjt/services/whm/nvDataService",
], function(
    angular,
    WHMAPI1_REQUEST
) {

    "use strict";

    var module = angular.module("whm.initialSetup.setupService", [
        "cjt2.services.api",
        "cjt2.services.whm.nvdata"
    ]);

    module.factory("setupService", [
        "$q",
        "APIService",
        "nvDataService",
        function(
            $q,
            APIService,
            nvDataService
        ) {

            var NO_MODULE = "";

            var SetupService = function() {
                this.apiService = new APIService();
            };

            angular.extend(SetupService.prototype, {

                /**
                 * Stores if the box is eligible for trial
                 */
                isEligibleForTrial: false,

                /**
                 * Records the root user's acceptance of the current legal agreements.
                 *
                 * @method recordAcceptance
                 * @return {Promise}   When resolved, the server has successfully recorded the user's acceptance.
                 */
                recordAcceptance: function() {

                    var apiCall = new WHMAPI1_REQUEST.Class();
                    apiCall.initialize(NO_MODULE, "accept_eula");

                    return this.apiService.deferred(apiCall).promise;
                },

                /**
                 * Sets the contact email and default nameservers in wwwacct.conf
                 *
                 * @param {Object} args   An object containing values for the contact email and/or default nameservers.
                 * @param {String} [args.email]         The contact email for root.
                 * @param {String} [args.nameservers]   An array, containing the hostnames of the nameservers. Currently,
                 *                                      only the first two values in the array are used.
                 */


                /**
                 * Sets the contact_email in /etc/wwwacct.conf
                 *
                 * @param {String} email   The contact email for root.
                 * @return {Promise}       Resolves once the API call is complete.
                 */
                setEmail: function(email) {
                    if (!angular.isString(email)) {
                        throw new TypeError("Developer Error: Them email argument must be a string");
                    }

                    var apiCall = new WHMAPI1_REQUEST.Class();
                    apiCall.initialize(NO_MODULE, "update_contact_email");
                    apiCall.addArgument("contact_email", email);

                    return this.apiService.deferred(apiCall).promise;
                },

                /**
                 * Sets nameservers 1 and 2 in /etc/wwwacct.conf. This method
                 * does not currently support nameservers 3 and 4.
                 *
                 * @param  {String[]} nameservers   An array of nameserver hostnames.
                 * @return {Promise}                Resolves once the API call is complete.
                 */
                setNameservers: function(nameservers) {
                    if (!angular.isArray(nameservers)) {
                        throw new TypeError("Developer Error: The nameservers argument must be an array");
                    }

                    var apiCall = new WHMAPI1_REQUEST.Class();
                    apiCall.initialize(NO_MODULE, "update_nameservers_config");

                    [
                        "nameserver",
                        "nameserver2",
                    ].forEach(function(apiKey, index) {
                        apiCall.addArgument(apiKey, nameservers[index]);
                    });

                    return this.apiService.deferred(apiCall).promise;
                },

                /**
                 * Creates NVData entries for API failures that take place during
                 * the setup process so we can create additional notices inside
                 * the product to draw users' attention.
                 *
                 * @param  {String[]} errorKeys    An array of error keys to base the NVData names on.
                 * @return {Promise}               Resolves once the API call is complete.
                 */
                saveErrors: function(errorKeys) {
                    if (!angular.isArray(errorKeys)) {
                        throw new TypeError("Developer Error: The errorKeys argument must be an array");
                    }

                    if (!errorKeys.length) {
                        return $q.resolve();
                    }

                    var nvData = {};
                    errorKeys.forEach(function(key) {
                        key = "isa:" + key + "_save_error";
                        nvData[key] = 1;
                    });

                    return nvDataService.setObject(nvData);
                },

                /**
                 * Checks whether an initial website was requested.
                 *
                 * @return {Promise}     Resolves once the API call is complete.
                 */
                initialWebsiteRequested: function() {
                    var apiCall = new WHMAPI1_REQUEST.Class();
                    apiCall.initialize(NO_MODULE, "initialwebsite_requested");

                    return this.apiService.deferred(apiCall).promise;
                },

                /**
                 * Creates the initial website if specified in a config file.
                 *
                 * @return {Promise}     Resolves once the API call is complete.
                 */
                initialWebsite: function() {
                    var apiCall = new WHMAPI1_REQUEST.Class();
                    apiCall.initialize(NO_MODULE, "initialwebsite_create");

                    return this.apiService.deferred(apiCall).promise;
                },

            });

            return new SetupService();
        }
    ]);
});

/*
 * views/infoController.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
 */

/* eslint-env amd */

define('app/views/infoController',[
    "angular",
    "cjt/util/locale",
    "ngSanitize",
    "cjt/directives/validationContainerDirective",
    "cjt/directives/validationItemDirective",
    "cjt/validator/domain-validators",
    "cjt/validator/email-validator",
    "app/services/setupService",
], function(angular, LOCALE) {

    "use strict";

    function InfoController(PAGE, $location, setupService, $scope, $window, $q) {
        this.PAGE = PAGE;
        this.$location = $location;
        this.setupService = setupService;
        this.$scope = $scope;
        this.$window = $window;
        this.$q = $q;

        if (!PAGE.has_accepted_legal_agreements) {
            $location.path("/legal");
        }

        if (PAGE.has_completed_initial_setup || PAGE.is_dnsonly) {
            this.exit();
        }

        // Create copies of the initial data, for later comparisons
        this.email = PAGE.email;
        this.nameservers = PAGE.nameservers && PAGE.nameservers.slice() || [];
        this.finishButtonText = LOCALE.maketext("Finish");

        if (!PAGE.has_license && !this.setupService.isEligibleForTrial) {
            this.finishButtonText = LOCALE.maketext("Next");
        }
    }

    InfoController.$inject = [
        "PAGE",
        "$location",
        "setupService",
        "$scope",
        "$window",
        "$q",
    ];

    /**
     * Sets the provided values via the API and pushes forward to the next step.
     * @method submit
     */
    InfoController.prototype.submit = function() {
        var self = this;

        if (self.isSubmitting) {
            return;
        }

        if (self.$scope.infoForm.$invalid) {
            _validateControls(self.$scope.infoForm); // Recursively run $validate() on all ngModelControllers
            return;
        }

        self.isSubmitting = true;

        // Check whether or not anything has changed from the initial values to see if we should make an API call
        var emailHasChanged = _normalizeFalsyVals(self.PAGE.email) !== _normalizeFalsyVals(self.email);
        var nameserversHaveChanged = self.nameservers.some(function(nameserver, index) {
            return _normalizeFalsyVals(nameserver) !== _normalizeFalsyVals(self.PAGE.nameservers[index]);
        });

        // If nothing has changed, we can exit early
        if (!emailHasChanged && !nameserversHaveChanged) {
            self.exit();
            return;
        }

        // Otherwise, we need to wait on the API calls
        var promise = self.$q.resolve();
        var errorKeys = [];

        if ( emailHasChanged ) {
            promise = promise.then(function() {
                return self.setupService.setEmail(self.email);
            }).catch(function(error) {
                errorKeys.push("contact_email");
            });
        }

        if ( nameserversHaveChanged ) {
            promise = promise.then(function() {
                return self.setupService.setNameservers(self.nameservers);
            }).catch(function(error) {
                errorKeys.push("nameservers");
            });
        }

        promise.then(function() {
            if (errorKeys.length) {
                return self.setupService.saveErrors(errorKeys);
            }
        }).finally(function() {
            self.exit();
        });
    };

    /**
     * Runs $validate() on any NgModelController instances found. If the controller
     * passed in is an instance of FormController, then this function will process
     * the entire tree of FormController instances.
     *
     * @param  {Controller} controller   The FormController or NgModelController to process.
     */
    function _validateControls(controller) {
        if (controller.$validate) {
            controller.$setDirty();
            controller.$validate();
        } else {

            // Hack until we update AngularJS and get FormController.getControls()
            Object.keys(controller).forEach(function(key) {

                // Skip built-in keys
                if (key[0] === "$") {
                    return;
                }

                _validateControls( controller[key] );
            });
        }
    }

    /**
     * Sets the given nameserver index back to its initial value.
     *
     * @param  {Number} index   The index in this.nameservers/PAGE.nameservers
     */
    InfoController.prototype.resetNsInput = function(index) {
        this.nameservers[index] = this.PAGE.nameservers[index];
    };

    /**
     * Gives the text for the reset button title.
     *
     * @param  {Number} index   The index in this.nameservers
     * @return {String}         The title text.
     */
    InfoController.prototype.resetTitleText = function(index) {
        return LOCALE.maketext("Reset to the original value: [_1]", this.PAGE.nameservers[index]);
    };

    /**
     * Determines whether or not a reset button should be disabled.
     * @param  {Number} index   The index in this.nameservers
     * @return {Boolean}        True if it should be disabled. False otherwise
     */
    InfoController.prototype.shouldDisableReset = function(index) {
        return _normalizeFalsyVals( this.PAGE.nameservers[index] ) === _normalizeFalsyVals( this.nameservers[index] );
    };

    function _normalizeFalsyVals(str) {
        return !str ? "" : str;
    }

    /**
     * Exits the initial setup assistant and drops them to the next step.
     * @method exit
     */
    InfoController.prototype.exit = function() {
        if (this.PAGE.requested_initial_website) {
            this.$location.path("/initial-website");
        } else {
            this.$window.location.href = "../initial_setup_wizard1_do";
        }
    };

    angular
        .module("whm.initialSetup.infoController", [
            "ngSanitize",
            "cjt2.validate",
            "cjt2.directives.validationContainer",
            "cjt2.directives.validationItem",
            "whm.initialSetup.setupService",
        ])
        .controller("infoController", InfoController);

    return InfoController;

});

/*
# license_purchase/services/storeService.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: false */
define(
    'shared/js/license_purchase/services/storeService',[
        "angular",
        "lodash",

        // CJT
        "cjt/util/locale",
        "cjt/util/parse",
        "cjt/io/api",
        "cjt/io/whm-v1-request",
        "cjt/io/whm-v1",

        // Angular components
        "cjt/services/APIService"
    ],
    function(
        angular,
        _,
        LOCALE,
        PARSE,
        API,
        APIREQUEST
    ) {

        "use strict";

        // Constants
        var NO_MODULE = "";
        var USE_JSON = { json: true };

        var module = angular.module("whm.storeService", [
            "cjt2.services.api"
        ]);

        function storeServiceFactory($q, APIService) {

            // Set up the service's constructor and parent
            var StoreService = function() {
                this.accessToken = "";
            };
            StoreService.prototype = new APIService();

            var isEligibleForTrialPromise;

            // Extend the prototype with any class-specific functionality
            angular.extend(StoreService.prototype, {

                /**
                 * Checks to see whether the current server is eligible for a trial license.
                 *
                 * @param {Object} args - Object containing options
                 * @param {Boolean} args.noCache - By default, this method will return a promise from any previous
                 *                                 requests. Pass true to this argument to fetch a new response.
                 * @returns {Promise<Boolean>} - When resolved, it will contain a boolean response as to whether
                 *                               the current server is eligible for trial or not.
                 */
                isEligibleForTrial: function(args) {
                    args = args || {};

                    if (isEligibleForTrialPromise && !args.noCache) {
                        return isEligibleForTrialPromise;
                    } else {
                        var apiCall = new APIREQUEST.Class();
                        apiCall.initialize(NO_MODULE, "is_eligible_for_trial");

                        isEligibleForTrialPromise = this.deferred(apiCall).promise
                            .then(function(response) {
                                if (!response || !response.data || !response.data.hasOwnProperty("is_eligible")) {
                                    return $q.reject(
                                        LOCALE.maketext("The system failed to parse the response from the API: [_1]", "is_eligible_for_trial")
                                    );
                                }

                                return PARSE.parsePerlBoolean( response.data.is_eligible );
                            });

                        return isEligibleForTrialPromise;
                    }
                },

                /**
                 * Returns the cPanel store login link
                 * @method getLoginURL
                 * @param  {String} url The url to redirect the user to after successful store login
                 * @return {Promise} Promise that will fulfill the request.
                 */
                getLoginURL: function(url) {
                    var self = this;
                    return this._getLoginURL(url).catch(function(error) {

                        // There's no point in saving an error response. Let it retry every time
                        self._getLoginURL.cache.delete(url);
                        return $q.reject(error);
                    });
                },

                _getLoginURL: _.memoize(function(url) {

                    var apiCall = new APIREQUEST.Class();
                    apiCall.initialize(NO_MODULE, "get_login_url");
                    apiCall.addArgument("provider", "cPStore");
                    apiCall.addArgument("url_after_login", url);

                    var deferred = this.deferred(apiCall);

                    // pass the promise back to the controller
                    return deferred.promise;
                }),

                /**
                 * Validates if the returned token from the store is valid
                 * @method validateLoginToken
                 * @param {String} url The url to redirect the user to after successful store login
                 * @param {String} token The token returned from cPStore
                 * @return {Promise} Promise that will fulfill the request.
                 */
                validateLoginToken: function(token, url) {
                    var apiCall = new APIREQUEST.Class();
                    apiCall.initialize(NO_MODULE, "validate_login_token");
                    apiCall.addArgument("provider", "cPStore");
                    apiCall.addArgument("url_after_login", url);
                    apiCall.addArgument("login_token", token);

                    var deferred = this.deferred(apiCall);

                    return deferred.promise;
                },

                /**
                 * Takes an authorization code and the redirect URI from the original authorization
                 * request and requests an access token from the cPStore.
                 *
                 * @async
                 * @param {string} authCode - The authorization code returned from the cPStore.
                 * @param {string} redirectUri - The URI provided to the original authorization request.
                 * @returns {Promise<string>} - Resolves with the access token.
                 * @throws {Promise<string>} - Rejects with an error message if the API indicates success but is missing the access token.
                 * @throws {Promise<string>} - Rejects with an error message from the API if there is an error.
                 */
                getAccessToken: function(authCode, redirectUri) {
                    return this.validateLoginToken(authCode, redirectUri).then(function(result) {
                        var accessToken = result && result.data && result.data[0] && result.data[0].access_token;
                        if (accessToken) {
                            return accessToken;
                        } else {
                            return $q.reject("The system failed to authenticate. Please try again");
                        }
                    });
                },

                /**
                 * Generated the order to purchase license
                 * @method generateLicenseOrder
                 * @param {String} token The token returned from cPStore
                 * @param {String} url The url to redirect the user to after checkout
                 * @return {Promise} Promise that will fulfill the request.
                 */
                generateLicenseOrder: function(token, url, isUpgrade) {
                    var apiCall = new APIREQUEST.Class();
                    apiCall.initialize(NO_MODULE, "purchase_a_license");
                    apiCall.addArgument("provider", "cPStore");
                    apiCall.addArgument("login_token", token);
                    apiCall.addArgument("url_after_checkout", url);

                    if (isUpgrade) {
                        apiCall.addArgument("upgrade", "1");
                    }

                    var deferred = this.deferred(apiCall);

                    return deferred.promise;
                },

                /**
                 * Creates and completes an order for a new trial license for the server.
                 *
                 * @async
                 * @param {Object} args
                 * @param {string} args.token - An access token used to interface with the cPStore.
                 * @param {string} args.verificationCode - The verification code that will validate the user
                 *                                         for a trial license.
                 * @param {boolean} args.sendVerification - If true and the order is rejected due to missing
                 *                                          verification, a new verification code will be sent.
                 * @returns {Promise<*>} - When resolved, a new trial license has been secured.
                 */
                acquireTrialLicense: function(args) {
                    var apiArgs = {
                        provider: "cPStore",
                        login_token: args.token,
                        checkout_args: {},
                    };

                    if (args.sendVerification) {
                        apiArgs.checkout_args.send_verification = 1;
                    }
                    if (args.verificationCode) {
                        apiArgs.checkout_args.verification_code = args.verificationCode;
                    }

                    var apiCall = new APIREQUEST.Class();
                    apiCall.initialize(NO_MODULE, "purchase_a_trial", apiArgs, null, USE_JSON);

                    var deferred = this.deferred(apiCall, this._getTransformAPIFailureOverride());
                    return deferred.promise;
                },

                /**
                 * Thrown when an operation is taking place that expects the server not to be licensed, but it already is.
                 *
                 * @typedef {Object} ServerIsLicensedError
                 * @property {boolean} serverIsLicensed - True if the server is licensed.
                 */

                /**
                 * Thrown when there is additional type information available about an API error.
                 * @typedef {Object} TypedApiError
                 * @param {boolean} isVerificationFailure - True if the error is a result of the account not being verified.
                 * @param {string} type - The type of underlying error.
                 * @param {string} email - The associated email. Only populated for verification failures.
                 * @param {string} message - The API error string.
                 */

                /**
                 * Sends a verification code to the user.
                 *
                 * @async
                 * @param {string} token - An access token used to interface with the cPStore.
                 * @returns {Promise<string>} - Resolves with the email address that the verification code has been sent to.
                 * @throws {Promise<TypedApiError>} - Rejects with a typed error object when there is an error during checkout.
                 * @throws {Promise<string>} - Rejects with an error string when there is any other API error.
                 * @throws {Promise<ServerIsLicensedError>} - Rejects with an error object when the server is already licensed.
                 */
                sendVerificationCode: function(token) {
                    var self = this;
                    return this.acquireTrialLicense({
                        token: token,
                        sendVerification: true,
                    }).then(function() {

                        /**
                         * This means that the purchase actually went through. This should not usually happen unless
                         * the user is using multiple windows to complete the initial setup. We will throw to signal
                         * to the consumer that this unintentional purchase has occurred.
                         */
                        return $q.reject({
                            serverIsLicensed: true,
                        });
                    }).catch(function(error) {
                        if (error.type === self._verificationSentErrorCode) {

                            // A new code has been sent, so we won't rethrow the error
                            return error.email;
                        } else {

                            // We have some other failure, so rethrow
                            return $q.reject(error);
                        }
                    });
                },

                _verificationSentErrorCode: "X::EmailNotVerified::EmailSent",

                /**
                 * Calls the API to run cpkeyclt to check for a valid license
                 * @method updateLicense
                 * @return {Promise} Promise that will fulfill the request.
                 */
                updateLicense: function() {
                    var apiCall = new APIREQUEST.Class();
                    apiCall.initialize(NO_MODULE, "run_cpkeyclt");

                    // force is undocumented by design to prevent users from locking out their system
                    apiCall.addArgument("force", "1");

                    var deferred = this.deferred(apiCall);

                    return deferred.promise;
                },

                /**
                 * Override for the default transformAPIFailure() handler in APIService so we
                 * can get the data object (that contains the error type information) as well.
                 */
                _getTransformAPIFailureOverride: function() {
                    var self = this;
                    return {

                        /**
                         * Transforms an API error into a typed error with additional information.
                         * @param {Object} resp - The API response object.
                         * @returns {TypedApiError}
                         */
                        transformAPIFailure: function(resp) {
                            if (!resp) {
                                return {};
                            }

                            var errorType = resp.data && resp.data.type;
                            return {
                                isVerificationFailure: errorType && self._isVerificationFailure(errorType),
                                type: errorType,
                                email: resp.data && resp.data.detail && resp.data.detail.data && resp.data.detail.data.email,
                                message: resp.error,
                            };
                        }
                    };
                },

                _verificationFailureRegex: /^X::EmailNotVerified/,
                _isVerificationFailure: function(errorType) {
                    return this._verificationFailureRegex.test(errorType);
                },
            });

            return new StoreService();
        }

        storeServiceFactory.$inject = ["$q", "APIService"];
        return module.factory("storeService", storeServiceFactory);
    });

/*
 * views/introController.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
 */

/* eslint-env amd */

define('app/views/introController',[
    "angular",
    "cjt/util/locale",
    "ngSanitize",
    "cjt/directives/disableAnimations",
    "shared/js/license_purchase/services/storeService",
], function(angular, LOCALE) {

    "use strict";

    function IntroController(PAGE, $timeout, storeService) {
        this.PAGE = PAGE;
        this.$timeout = $timeout;

        this.isDone = false;

        $timeout(this.checkExpiration.bind(this));

        storeService.isEligibleForTrial();
    }

    IntroController.$inject = [
        "PAGE",
        "$timeout",
        "storeService"
    ];

    IntroController.prototype.checkExpiration = function() {
        var self = this;

        var msUntilExpiration = this.msUntilExpiration();
        self.isDone = msUntilExpiration < 0;

        if (!self.isDone) {

            // We need to wait some more
            self.$timeout(function() {
                self.isDone = true;
            }, msUntilExpiration);
        }
    };

    IntroController.prototype.msUntilExpiration = function() {
        var self = this;
        return self.PAGE.introEndTime - Date.now();
    };

    IntroController.prototype.skip = function() {
        this.isDone = true;
    };

    angular
        .module("whm.initialSetup.introController", [
            "ngSanitize",
            "cjt2.directives.disableAnimations",
            "whm.storeService"
        ])
        .controller("introController", IntroController);

    return IntroController;

});

/*
 * views/legalController.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
 */

/* eslint-env amd */

define('app/views/legalController',[
    "angular",
    "cjt/util/locale",
    "ngSanitize",
    "cjt/directives/actionButtonDirective",
    "cjt/services/alertService",
    "app/services/setupService",
    "shared/js/license_purchase/services/storeService",
], function(angular, LOCALE) {

    "use strict";

    function LegalController(PAGE, $anchorScroll, $location, $timeout, setupService, storeService, alertService, $window) {

        this.PAGE = PAGE;
        this.agreements = PAGE.agreements;
        this.$anchorScroll = $anchorScroll;
        this.$location = $location;
        this.$timeout = $timeout;
        this.setupService = setupService;
        this.alertService = alertService;
        this.$window = $window;
        this.storeService = storeService;

        if (PAGE.has_accepted_legal_agreements) {
            this.continueToNextStep();
            return;
        }

        this.setTopButtonMargin();
    }

    LegalController.$inject = [
        "PAGE",
        "$anchorScroll",
        "$location",
        "$timeout",
        "setupService",
        "storeService",
        "alertService",
        "$window",
    ];

    /**
     * Adds left and right margin to the floating "top" button to make sure
     * that it accounts for the scrollbar width, if any. We use left and right
     * margin so that it works for both LTR and RTL cases.
     *
     * @method setTopButtonMargin
     */
    LegalController.prototype.setTopButtonMargin = function() {
        this.$timeout(function() {
            var panelElem = angular.element(".panel-body").get(0);
            var topElem = angular.element("#top-link").get(0);

            if (!panelElem || !topElem) {
                return;
            }

            var scrollbarWidth = panelElem.offsetWidth - panelElem.clientWidth;
            topElem.style.opacity = 1;
            if (scrollbarWidth) {
                topElem.style.marginLeft = scrollbarWidth + "px";
                topElem.style.marginRight = scrollbarWidth + "px";
            }
        }, 1500);
    };

    /**
     * Prints the legal agreements.
     */
    LegalController.prototype.print = function() {
        window.print();
    };

    /**
     * Scrolls to the specified id using the location hash
     *
     * @method scrollTo
     * @param {String} id   The id of the anchor to scroll the view to
     */
    LegalController.prototype.scrollTo = function(id) {
        this.$location.hash(id);
        this.$anchorScroll();
    };

    /**
     * Records the user's acceptance of all of the legal agreements.
     *
     * @method acceptAll
     * @return {Promise}   When resolved, the server has successfully recorded the acceptance.
     */
    LegalController.prototype.acceptAll = function() {
        var self = this;
        self.isAccepting = true;
        self.alertService.clear();

        return this.setupService.recordAcceptance().then(function() {
            self.PAGE.has_accepted_legal_agreements = true;
            self.continueToNextStep();
        }).catch(function(error) {
            self.alertService.add({
                type: "danger",
                id: "eula-api-error-alert",
                message: LOCALE.maketext("The system could not process your agreement: [_1]", error),
                replace: true
            });
        }).finally(function() {
            self.isAccepting = false;
        });
    };

    LegalController.prototype.continueToNextStep = function() {
        var self = this;

        // TODO: Start using "cjt/services/viewNavigationApi" instead of $location.path() to propagate debug mode

        if (self.PAGE.has_license) {
            if (self.PAGE.has_completed_initial_setup || self.PAGE.is_dnsonly !== 0) {
                self.$window.location.href = "../initial_setup_wizard1_do";
            } else {
                self.$location.path("/info");
            }
        } else {
            self.storeService.isEligibleForTrial().then(function(isEligible) {
                if (isEligible) {
                    self.setupService.isEligibleForTrial = true;
                    self.$location.path("/trial-activation/login");
                } else {
                    if (self.PAGE.has_completed_initial_setup || self.PAGE.is_dnsonly !== 0) {
                        self.$window.location.href = "../initial_setup_wizard1_do";
                    } else {
                        self.setupService.isEligibleForTrial = false;
                        self.$location.path("/info");
                    }
                }
            }, function error() {
                if (self.PAGE.has_completed_initial_setup || self.PAGE.is_dnsonly !== 0) {
                    self.$window.location.href = "../initial_setup_wizard1_do";
                } else {
                    self.setupService.isEligibleForTrial = false;
                    self.$location.path("/info");
                }
            });
        }
    };

    angular
        .module("whm.initialSetup.legalController", [
            "ngSanitize",
            "cjt2.directives.actionButton",
            "cjt2.services.alert",
            "whm.initialSetup.setupService",
            "whm.storeService"
        ])
        .controller("legalController", LegalController);

    return LegalController;

});

/*
 * views/createAccountController.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
 */

/* eslint-env amd */

define('app/views/createAccountController',[
    "angular",
    "cjt/util/locale",
    "app/services/setupService",
], function(angular, LOCALE) {

    "use strict";

    function CreateAccountController(PAGE, $location, setupService, $scope, $window, $q) {
        this.PAGE = PAGE;
        this.$location = $location;
        this.setupService = setupService;
        this.$scope = $scope;
        this.$window = $window;
        this.$q = $q;

        if (!PAGE.has_accepted_legal_agreements) {
            $location.path("/legal");
        }

        if (PAGE.has_completed_initial_setup || PAGE.is_dnsonly || !PAGE.requested_initial_website) {
            this.exit();
        }
    }

    CreateAccountController.$inject = [
        "PAGE",
        "$location",
        "setupService",
        "$scope",
        "$window",
        "$q",
    ];

    /**
     * Creates the account via the API.
     * @method submit
     */
    CreateAccountController.prototype.create = function() {
        var self = this;

        if (self.isSubmitting) {
            return;
        }

        if (!self.PAGE.requested_initial_website) {
            self.exit();
            return;
        }

        self.isSubmitting = true;

        var errorKeys = [];

        return self.setupService.initialWebsite(self.email)
            .catch(function(error) {
                errorKeys.push("initial_website");
            })
            .then(function() {
                if (errorKeys.length) {
                    return self.setupService.saveErrors(errorKeys);
                }
            }).finally(function() {
                self.exit();
            });
    };

    /**
     * Exits the initial setup assistant and drops them to the next step.
     * @method exit
     */
    CreateAccountController.prototype.exit = function() {
        this.$window.location.href = "../initial_setup_wizard1_do";
    };

    CreateAccountController.prototype.requested = function() {
        return this.PAGE.requested_initial_website;
    };

    angular
        .module("whm.initialSetup.createAccountController", [
            "whm.initialSetup.setupService",
        ])
        .controller("createAccountController", CreateAccountController);

    return CreateAccountController;
});

/*
 * views/trialActivationController.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
 */

/* eslint-env amd */

define('app/views/trialLicenseActivationController',[
    "angular",
    "cjt/util/locale",
    "app/services/setupService",
    "shared/js/license_purchase/services/storeService",
    "cjt/services/alertService",
    "cjt/directives/actionButtonDirective",
    "cjt/directives/validationContainerDirective",
    "cjt/directives/validationItemDirective",
], function(angular, LOCALE) {

    "use strict";

    function trialActivationController(PAGE, $location, setupService, storeService, alertService, $scope, $window, $q, $timeout, $routeParams) {
        this.PAGE = PAGE;
        this.$location = $location;
        this.setupService = setupService;
        this.storeService = storeService;
        this.alertService = alertService;
        this.$scope = $scope;
        this.$window = $window;
        this.$q = $q;
        this.$timeout = $timeout;
        this.$routeParams = $routeParams;

        if (!PAGE.has_accepted_legal_agreements) {
            $location.path("/legal");
        }

        if (PAGE.has_license) {
            if (PAGE.has_completed_initial_setup || PAGE.is_dnsonly !== 0) {
                $window.location.href = "../initial_setup_wizard1_do";
            } else {
                $location.path("/info");
            }

            return;
        }

        var steps = ["login", "activation", "activation-status", "email-verification"];

        var currentStep = steps[0];

        if ($routeParams.nextStep &&
            steps.indexOf($routeParams.nextStep) !== -1) {
            currentStep = $routeParams.nextStep;
        }

        this.$scope.currentStep = currentStep;

        this.$scope.onActivationStatusView = this.$scope.currentStep === "activation-status";


        this.startTrialActivationProcess();

        // redirects to server setup page
        this.redirectToServerSetup = function() {
            $location.path("/info");
        };

        // Prefetch store URL if we haven't logged in yet.
        var queryArgs = $location.search();
        if (!queryArgs || !queryArgs.code) {
            this.prefetchLoginUrl();
        }
    }

    /**
    * Prefetches the login URL
    *
    * @method prefetchLoginUrl
    */
    trialActivationController.prototype.prefetchLoginUrl = function() {
        var returnUrl = this.getReturnURL("activation");
        this.storeService.getLoginURL(returnUrl);
    };

    /**
    * Generates return url thats passed to store
    *
    * @method getReturnURL
    * @param {string} step step key which is same as the route parameter.
    * @returns {string} return url that store will redirect to
    */
    trialActivationController.prototype.getReturnURL = function(step) {
        var self = this;
        var queryArgs = self.$location.search();

        var returnURL = self.PAGE.baseURL + self.PAGE.pageURL + "/trial-activation/" + step;
        if (queryArgs && queryArgs.debug) {
            returnURL += "?debug=1";
        }

        return returnURL;
    };

    /**
    * Redirect to the store login
    *
    * @method storeLoginRedirect
    * @returns {string} login url
    */
    trialActivationController.prototype.storeLoginRedirect = function() {
        var self = this;
        var returnURL = self.getReturnURL("activation");
        self.alertService.clear();

        return self.storeService.getLoginURL(returnURL).then(function(results) {
            if ( results.data && results.data.length ) {
                self.$window.location.href = results.data[0];
            }
        }, function(error) {
            self.alertService.add({
                type: "danger",
                id: "getLoginURL-api-error-alert",
                message: LOCALE.maketext("The system could not log in to the cPanel Store: [_1]", error),
                replace: true
            });
        });
    };

    /**
    * Switches routes and presentation and performs trial license activation
    *
    * @method startTrialActivationProcess
    */
    trialActivationController.prototype.startTrialActivationProcess = function() {

        var self = this;
        var authenticationCode = self.authenticationCode = self.$location.search().code;
        var nextStep = self.$routeParams.nextStep;

        self.activationInProgress = true;
        self.emailAddress = self.$routeParams.everythingelse;

        // Verify Login, Get Access Token and Generate Order
        if (authenticationCode && nextStep === "activation") {

            return _fetchAndStoreAccessToken(self).then(function(accessToken) {

                if (!accessToken) {

                    // _fetchAndStoreAccessToken() will already redirect them to /login on failure
                    return;
                }

                // Place the order and perform checkout
                return self.storeService.acquireTrialLicense({
                    token: accessToken,
                    sendVerification: true,
                }).then(
                    function() {
                        return self.storeService.updateLicense().then(
                            function(result) {
                                self.$location.path("/trial-activation/activation-status/");
                            },
                            function error(error) {
                                self.activationInProgress = false;
                                self.alertService.add({
                                    type: "danger",
                                    id: "updateLicense-api-error-alert",
                                    message: LOCALE.maketext("The system failed to update the license on your cPanel [output,amp] WHM server. [output,url,_1,Fix License File Errors]", "../../scripts10/license_error"),
                                    replace: true
                                });

                            }
                        );
                    }, function(error) {
                        self.activationInProgress = false;

                        if ( error.isVerificationFailure ) {
                            self.$location.path("/trial-activation/email-verification/" + error.email);
                        } else {
                            self.alertService.add({
                                type: "danger",
                                id: "purchase_a_trial-api-error-alert",
                                message: LOCALE.maketext("The system could not activate the trial license."),
                                replace: true
                            });
                        }
                    }
                );
            }, function(error) {
                self.activationInProgress = false;
                self.alertService.add({
                    type: "danger",
                    id: "validateLoginToken-api-error-alert",
                    message: LOCALE.maketext("The system failed to authenticate. Please try again"),
                    replace: true
                });

                self.$location.path("/trial-activation/login");
            });
        }

        // We need to get an access token
        if (nextStep !== "activation-status" && nextStep !== "email-verification") {
            self.$location.path("/trial-activation/login");
            return;
        }
    };

    trialActivationController.prototype.verifyEmail = function(form) {
        var self = this;

        if (form.$invalid) {
            return;
        }

        var verificationCode = self.verificationCode;
        var accessToken = self.storeService.accessToken;

        self.verificationInProgress = true;
        self.alertService.clear();

        // Place the order and perform checkout
        return self.storeService.acquireTrialLicense({
            token: accessToken,
            verificationCode: verificationCode,
        }).then(
            function() {
                return self.storeService.updateLicense().then(
                    function(result) {
                        self.alertService.clear();
                        self.$location.path("/trial-activation/activation-status/");
                    },
                    function error(error) {
                        self.activationInProgress = false;
                        self.alertService.add({
                            type: "danger",
                            id: "updateLicense-api-error-alert",
                            message: LOCALE.maketext("The system failed to update the license on your cPanel [output,amp] WHM server. [output,url,_1,Fix License File Errors]", "../../scripts10/license_error"),
                            replace: true
                        });

                    }
                );
            }, function(error) {
                self.activationInProgress = false;

                if ( error.isVerificationFailure ) {
                    self.alertService.add({
                        type: "danger",
                        id: "verify-email-api-error-alert",
                        message: LOCALE.maketext("The verification code was incorrect. Please try again."),
                        replace: true
                    });
                    return;
                }

                self.alertService.add({
                    type: "danger",
                    id: "purchase_a_trial-api-error-alert",
                    message: LOCALE.maketext("The system could not activate the trial license."),
                    replace: true
                });
            }
        ).finally(function() {
            self.verificationInProgress = false;
        });
    };

    trialActivationController.prototype.resendCode = function() {
        var self = this;
        var accessToken = self.storeService.accessToken;
        self.alertService.clear();

        return this.storeService.sendVerificationCode(accessToken).then(function(email) {
            self.alertService.add({
                type: "success",
                id: "resend-verification-api-success-alert",
                message: LOCALE.maketext("A new verification code has been sent to [_1].", email),
                replace: true
            });
        }).catch(function(error) {
            if (error.serverIsLicensed) {

                /**
                 * There service may determine that the server is already licensed, in which case we
                 * can send them to the success screen.
                 */
                self.$location.path("/trial-activation/activation-status/");
                self.activationInProgress = false;
                self.alertService.add({
                    type: "success",
                    id: "resend-verification-api-error-alert",
                    message: LOCALE.maketext("The system determined that your server is already licensed."),
                    replace: true
                });
                return;
            }

            self.alertService.add({
                type: "danger",
                id: "resend-verification-api-error-alert",
                message: LOCALE.maketext("The system failed to send a new verification code to [_1].", error.email),
                replace: true
            });
        });
    };

    /**
     * Fetches an access token for a controller instance and stores it to the storeService.
     * This method's promise return does not ever reject and relies on the resolved return
     * value instead.
     *
     * @private
     * @async
     * @param {Object} self - The controller instance. It must have an authenticationCode property
     *                        or the API call will fail.
     * @returns {Promise<string|undefined>} - The access token, if successful. Undefined, if not.
     */
    function _fetchAndStoreAccessToken(self) {
        var authenticationCode = self.authenticationCode;
        var returnUri = self.getReturnURL("activation");

        return self.storeService.getAccessToken(authenticationCode, returnUri).then(function(accessToken) {
            self.storeService.accessToken = accessToken;
            return accessToken;
        }).catch(function() {
            self.activationInProgress = false;
            self.alertService.add({
                type: "danger",
                id: "getAccessToken-api-error-alert",
                message: LOCALE.maketext("The system failed to authenticate. Please try again"),
                replace: true
            });

            self.$location.path("/trial-activation/login");

            return void 0;
        });
    }

    trialActivationController.$inject = [
        "PAGE",
        "$location",
        "setupService",
        "storeService",
        "alertService",
        "$scope",
        "$window",
        "$q",
        "$timeout",
        "$routeParams"
    ];


    angular
        .module("whm.initialSetup.trialActivationController", [
            "ngSanitize",
            "whm.initialSetup.setupService",
            "whm.storeService",
            "cjt2.services.alert"
        ])
        .controller("trialActivationController", trialActivationController);

    return trialActivationController;

});

/*
 * index.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
 */

/* eslint-env amd */

define(
    'app/index',[
        "angular",
        "cjt/modules",
        "ngRoute",
        "ngSanitize",

    ],
    function(angular, $) {

        "use strict";

        return function() {

            require(
                [
                    "cjt/bootstrap",
                    "cjt/directives/alertList",
                    "app/views/infoController",
                    "app/views/introController",
                    "app/views/legalController",
                    "app/views/createAccountController",
                    "app/views/trialLicenseActivationController"
                ], function(BOOTSTRAP) {

                    var app = angular.module("whm.initialSetup", [
                        "cjt2.config.whm.configProvider", // This needs to load before ngRoute
                        "ngRoute",
                        "cjt2.directives.alertList",
                        "whm.initialSetup.infoController",
                        "whm.initialSetup.introController",
                        "whm.initialSetup.legalController",
                        "whm.initialSetup.createAccountController",
                        "whm.initialSetup.trialActivationController"
                    ]);

                    app.config([
                        "$routeProvider",
                        function($routeProvider) {

                            $routeProvider.when("/legal", {
                                controller: "legalController",
                                controllerAs: "vm",
                                templateUrl: "gsw/initial_setup/views/legalView.ptt",
                            });

                            $routeProvider.when("/trial-activation/:nextStep?/:everythingelse?", {
                                controller: "trialActivationController",
                                controllerAs: "vm",
                                templateUrl: "gsw/initial_setup/views/trialLicenseActivationView.ptt",
                            });

                            $routeProvider.when("/info", {
                                controller: "infoController",
                                controllerAs: "vm",
                                templateUrl: "gsw/initial_setup/views/infoView.ptt",
                            });

                            $routeProvider.when("/initial-website", {
                                controller: "createAccountController",
                                controllerAs: "vm",
                                templateUrl: "gsw/initial_setup/views/createAccountView.ptt",
                            });

                            $routeProvider.otherwise({
                                "redirectTo": "/legal/"
                            });
                        }
                    ]);

                    app.value("PAGE", window.PAGE);

                    BOOTSTRAP("#content", "whm.initialSetup");

                });
        };
    }
);

Back to Directory File Manager