Jump to content

huangsenli

Members
  • Posts

    126
  • Joined

  • Last visited

  • Days Won

    8

Reputation Activity

  1. Like
    huangsenli reacted to Tyson in blesta Integrate css problem   
    If no one else has that problem, then it might be your computer. Have you tried clearing your web browser cache? Have you tried using a different web browser? Are you sure all of the files exist on the file system, in particular, the CSS files? Do you have any custom code that might conflict with the CSS?
  2. Like
    huangsenli got a reaction from Paul in [Module] Hetzner Cloud   
    Hetzner Cloud,Perfectly running,This is very good for my installation.

  3. Like
    huangsenli reacted to Paul in Blesta 4.5 Beta 2 Released   
    Blesta version 4.5.0-b2 (BETA 2) is now available. You can download it from right here (Client Area Login Required). Read the blog post announcement at https://www.blesta.com/2019/01/31/blesta-4.5-beta-released/
    This is a BETA release. Beta releases are not considered stable enough for production use, and are UNSUPPORTED. DO NOT INSTALL IN A PRODUCTION ENVIRONMENT.
    Please report any bugs you find in the v4.5 beta bug forum.
    Installing Blesta

    See Installing Blesta in the User Manual for instructions.

    Upgrading Blesta

    See Upgrading Blesta in the User Manual for instructions.

    Release Notes

    See Blesta Core - Version 4.5.0-b2.

    For older releases see all Change Logs.
  4. Like
    huangsenli got a reaction from activa in Perfect solution is very good.   
    这很好,非常好。
     


  5. Like
    huangsenli got a reaction from Blesta Addons in Perfect solution is very good.   
    这很好,非常好。
     


  6. Like
    huangsenli got a reaction from Paul in Perfect solution is very good.   
    这很好,非常好。
     


  7. Haha
    huangsenli reacted to Michael in BlestaForums Beta 1   
    We're almost ready for the Beta 1 of the BlestaForums. Myself and Timothy (our collaboration together) are testing everything to try and keep bugs to a minimum. We're testing everything and when it's ready for Beta 1, we will update everyone here. We will be having a trial for 14 days to try it and then you can purchase a license from either Blesta.Store or CubeData. Each has their own licensing system. We've agreed on doing what I did with the BlestaCMS in the beginning and that will be that it will be open-code minus the bits for licensing.
    We will be adding features as we go along and I'm looking into a way to integrate this forum plugin into the CMS so it can be a paid addon or free if you have the forums and the cms.
    You can view my forums alpha version if you're a customer of ours: https://blesta.store/client/plugin/blesta_forums/
    Please note if you find a bug please let us know here and I'll get us onto it to fix it.
  8. Like
    huangsenli got a reaction from mysrvstore in How to sell a dedicated server   
    After adding these, you can add dedicated server information to each order.
  9. Like
    huangsenli got a reaction from bunny in How to sell a dedicated server   
    After adding these, you can add dedicated server information to each order.
  10. Like
    huangsenli got a reaction from mysrvstore in How to sell a dedicated server   
    <?php
    /**
     * Universal Module
     *
     * A module that can be customized to request any fields and post them to any
     * URL or email address
     *
     * @package blesta
     * @subpackage blesta.components.modules.universal_module
     * @copyright Copyright (c) 2010, Phillips Data, Inc.
     * @license http://www.blesta.com/license/ The Blesta License Agreement
     * @link http://www.blesta.com/ Blesta
     */
    class UniversalModule extends Module {
        
        /**
         * @var string The version of this module
         */
        private static $version = "1.2.0";
        /**
         * @var string The authors of this module
         */
        private static $authors = array(array('name' => "Phillips Data, Inc.", 'url' => "http://www.blesta.com"));
        /**
         * @var string A set of reserved form fields that will not be wrapped in a meta[] array
         */
        private static $reserved_fields = array('qty');
        
        /**
         * Initializes the module
         */
        public function __construct() {
            // Load components required by this module
            Loader::loadComponents($this, array("Input"));
            
            // Load the language required by this module
            Language::loadLang("universal_module", null, dirname(__FILE__) . DS . "language" . DS);
        }
        
        /**
         * Returns the name of this module
         *
         * @return string The common name of this module
         */
        public function getName() {
            if ($row = $this->getModuleRow())
                return $row->meta->name;
            
            return Language::_("UniversalModule.name", true);
        }
        
        /**
         * Returns the version of this gateway
         *
         * @return string The current version of this module
         */
        public function getVersion() {
            return self::$version;
        }
        
        /**
         * Returns the name and url of the authors of this module
         *
         * @return array The name and url of the authors of this module
         */
        public function getAuthors() {
            return self::$authors;
        }
        
        /**
         * Returns the value used to identify a particular service
         *
         * @param stdClass $service A stdClass object representing the service
         * @return string A value used to identify this service amongst other similar services
         */
        public function getServiceName($service) {
            static $rows = array();
            if (!isset($rows[$service->module_row_id]))
                $row[$service->module_row_id] = $this->getModuleRow($service->module_row_id);
                
            $key = null;
            if (isset($row[$service->module_row_id]->meta->service_field_name_0))
                $key = $row[$service->module_row_id]->meta->service_field_name_0;
            
            // If key is set, attempt to return value if it is scalar
            if ($key != null) {
                $fields = $this->serviceFieldsToObject($service->fields);
                
                if (isset($fields->{$key}) && is_scalar($fields->{$key}))
                    return $fields->{$key};
            }
            // Return 1st scalar field
            foreach ($service->fields as $field) {
                if (is_scalar($field->value))
                    return $field->value;
            }
            return null;
        }
        
        /**
         * Returns a noun used to refer to a module row
         *
         * @return string The noun used to refer to a module row
         */
        public function moduleRowName() {
            return Language::_("UniversalModule.module_row", true);
        }
        
        /**
         * Returns a noun used to refer to a module row in plural form
         *
         * @return string The noun used to refer to a module row in plural form
         */
        public function moduleRowNamePlural() {
            return Language::_("UniversalModule.module_row_plural", true);
        }
        
        /**
         * Returns a noun used to refer to a module group
         *
         * @return string The noun used to refer to a module group
         */
        public function moduleGroupName() {
            return Language::_("UniversalModule.module_group", true);
        }
        
        /**
         * Returns the key used to identify the primary field from the set of module row meta fields.
         *
         * @return string The key used to identify the primary field from the set of module row meta fields
         */
        public function moduleRowMetaKey() {
            return "name";
        }
        
        /**
         * Returns the value used to identify a particular package service which has
         * not yet been made into a service. This may be used to uniquely identify
         * an uncreated services of the same package (i.e. in an order form checkout)
         *
         * @param stdClass $package A stdClass object representing the selected package
         * @param array $vars An array of user supplied info to satisfy the request
         * @return string The value used to identify this package service
         * @see Module::getServiceName()
         */
        public function getPackageServiceName($package, array $vars=null) {
            if (isset($vars['meta']) && is_array($vars['meta'])) {
                foreach ($vars['meta'] as $value) {
                    if (is_scalar($value))
                        return $value;
                }
            }
            return $package->name;
        }
        
        /**
         * Adds the service to the remote server. Sets Input errors on failure,
         * preventing the service from being added.
         *
         * @param stdClass $package A stdClass object representing the selected package
         * @param array $vars An array of user supplied info to satisfy the request
         * @param stdClass $parent_package A stdClass object representing the parent service's selected package (if the current service is an addon service)
         * @param stdClass $parent_service A stdClass object representing the parent service of the service being added (if the current service is an addon service service and parent service has already been provisioned)
         * @param string $status The status of the service being added. These include:
         *     - active
         *     - canceled
         *     - pending
         *     - suspended
         * @return array A numerically indexed array of meta fields to be stored for this service containing:
         *     - key The key for this meta field
         *     - value The value for this key
         *     - encrypted Whether or not this field should be encrypted (default 0, not encrypted)
         * @see Module::getModule()
         * @see Module::getModuleRow()
         */
        public function addService($package, array $vars=null, $parent_package=null, $parent_service=null, $status="pending") {
            $meta = $this->processService("add", $vars, $package);
            if ($this->Input->errors())
                return;
            return $meta;
        }
        
        /**
         * Edits the service on the remote server. Sets Input errors on failure,
         * preventing the service from being edited.
         *
         * @param stdClass $package A stdClass object representing the current package
         * @param stdClass $service A stdClass object representing the current service
         * @param array $vars An array of user supplied info to satisfy the request
         * @param stdClass $parent_package A stdClass object representing the parent service's selected package (if the current service is an addon service)
         * @param stdClass $parent_service A stdClass object representing the parent service of the service being edited (if the current service is an addon service)
         * @return array A numerically indexed array of meta fields to be stored for this service containing:
         *     - key The key for this meta field
         *     - value The value for this key
         *     - encrypted Whether or not this field should be encrypted (default 0, not encrypted)
         * @see Module::getModule()
         * @see Module::getModuleRow()
         */
        public function editService($package, $service, array $vars=array(), $parent_package=null, $parent_service=null) {
            $meta = $this->processService("edit", $vars, $package);
        
            if ($this->Input->errors())
                return;
            
            return $meta;
        }
        
        /**
         * Cancels the service on the remote server. Sets Input errors on failure,
         * preventing the service from being canceled.
         *
         * @param stdClass $package A stdClass object representing the current package
         * @param stdClass $service A stdClass object representing the current service
         * @param stdClass $parent_package A stdClass object representing the parent service's selected package (if the current service is an addon service)
         * @param stdClass $parent_service A stdClass object representing the parent service of the service being canceled (if the current service is an addon service)
         * @return mixed null to maintain the existing meta fields or a numerically indexed array of meta fields to be stored for this service containing:
         *     - key The key for this meta field
         *     - value The value for this key
         *     - encrypted Whether or not this field should be encrypted (default 0, not encrypted)
         * @see Module::getModule()
         * @see Module::getModuleRow()
         */
        public function cancelService($package, $service, $parent_package=null, $parent_service=null) {
            
            if (!$this->sendNotification("service_notice_cancel", $service->fields, $package->module_row, null, $package->meta)) {
                $this->Input->setErrors(array('service_notice_cancel' => array('failed' => Language::_("UniversalModule.!error.service_notice_cancel.failed", true))));
                return;
            }
            
            return null;
        }
        
        /**
         * Suspends the service on the remote server. Sets Input errors on failure,
         * preventing the service from being suspended.
         *
         * @param stdClass $package A stdClass object representing the current package
         * @param stdClass $service A stdClass object representing the current service
         * @param stdClass $parent_package A stdClass object representing the parent service's selected package (if the current service is an addon service)
         * @param stdClass $parent_service A stdClass object representing the parent service of the service being suspended (if the current service is an addon service)
         * @return mixed null to maintain the existing meta fields or a numerically indexed array of meta fields to be stored for this service containing:
         *     - key The key for this meta field
         *     - value The value for this key
         *     - encrypted Whether or not this field should be encrypted (default 0, not encrypted)
         * @see Module::getModule()
         * @see Module::getModuleRow()
         */
        public function suspendService($package, $service, $parent_package=null, $parent_service=null) {
            
            if (!$this->sendNotification("service_notice_suspend", $service->fields, $package->module_row, null, $package->meta)) {
                $this->Input->setErrors(array('service_notice_suspend' => array('failed' => Language::_("UniversalModule.!error.service_notice_suspend.failed", true))));
                return;
            }
            
            return null;
        }
        
        /**
         * Unsuspends the service on the remote server. Sets Input errors on failure,
         * preventing the service from being unsuspended.
         *
         * @param stdClass $package A stdClass object representing the current package
         * @param stdClass $service A stdClass object representing the current service
         * @param stdClass $parent_package A stdClass object representing the parent service's selected package (if the current service is an addon service)
         * @param stdClass $parent_service A stdClass object representing the parent service of the service being unsuspended (if the current service is an addon service)
         * @return mixed null to maintain the existing meta fields or a numerically indexed array of meta fields to be stored for this service containing:
         *     - key The key for this meta field
         *     - value The value for this key
         *     - encrypted Whether or not this field should be encrypted (default 0, not encrypted)
         * @see Module::getModule()
         * @see Module::getModuleRow()
         */
        public function unsuspendService($package, $service, $parent_package=null, $parent_service=null) {
            
            if (!$this->sendNotification("service_notice_unsuspend", $service->fields, $package->module_row, null, $package->meta)) {
                $this->Input->setErrors(array('service_notice_unsuspend' => array('failed' => Language::_("UniversalModule.!error.service_notice_unsuspend.failed", true))));
                return;
            }
            
            return null;
        }
        
        /**
         * Allows the module to perform an action when the service is ready to renew.
         * Sets Input errors on failure, preventing the service from renewing.
         *
         * @param stdClass $package A stdClass object representing the current package
         * @param stdClass $service A stdClass object representing the current service
         * @param stdClass $parent_package A stdClass object representing the parent service's selected package (if the current service is an addon service)
         * @param stdClass $parent_service A stdClass object representing the parent service of the service being renewed (if the current service is an addon service)
         * @return mixed null to maintain the existing meta fields or a numerically indexed array of meta fields to be stored for this service containing:
         *     - key The key for this meta field
         *     - value The value for this key
         *     - encrypted Whether or not this field should be encrypted (default 0, not encrypted)
         * @see Module::getModule()
         * @see Module::getModuleRow()
         */
        public function renewService($package, $service, $parent_package=null, $parent_service=null) {
            
            if (!$this->sendNotification("service_notice_renew", $service->fields, $package->module_row, null, $package->meta)) {
                $this->Input->setErrors(array('service_notice_renew' => array('failed' => Language::_("UniversalModule.!error.service_notice_renew.failed", true))));
                return;
            }
            
            return null;
        }
        
        /**
         * Updates the package for the service on the remote server. Sets Input
         * errors on failure, preventing the service's package from being changed.
         *
         * @param stdClass $package_from A stdClass object representing the current package
         * @param stdClass $package_to A stdClass object representing the new package
         * @param stdClass $service A stdClass object representing the current service
         * @param stdClass $parent_package A stdClass object representing the parent service's selected package (if the current service is an addon service)
         * @param stdClass $parent_service A stdClass object representing the parent service of the service being changed (if the current service is an addon service)
         * @return mixed null to maintain the existing meta fields or a numerically indexed array of meta fields to be stored for this service containing:
         *     - key The key for this meta field
         *     - value The value for this key
         *     - encrypted Whether or not this field should be encrypted (default 0, not encrypted)
         * @see Module::getModule()
         * @see Module::getModuleRow()
         */
        public function changeServicePackage($package_from, $package_to, $service, $parent_package=null, $parent_service=null) {
            
            if (!$this->sendNotification("service_notice_package_change", $service->fields, $package_to->module_row, null, $package_to->meta)) {
                $this->Input->setErrors(array('service_notice_package_change' => array('failed' => Language::_("UniversalModule.!error.service_notice_package_change.failed", true))));
                return;
            }
            
            return null;
        }
        
        /**
         * Validates input data when attempting to add a package, returns the meta
         * data to save when adding a package. Performs any action required to add
         * the package on the remote server. Sets Input errors on failure,
         * preventing the package from being added.
         *
         * @param array An array of key/value pairs used to add the package
         * @return array A numerically indexed array of meta fields to be stored for this package containing:
         *     - key The key for this meta field
         *     - value The value for this key
         *     - encrypted Whether or not this field should be encrypted (default 0, not encrypted)
         * @see Module::getModule()
         * @see Module::getModuleRow()
         */
        public function addPackage(array $vars=null) {
            $meta = $this->processPackage("add", $vars);
        
            if ($this->Input->errors())
                return;
            return $meta;
        }
        
        /**
         * Validates input data when attempting to edit a package, returns the meta
         * data to save when editing a package. Performs any action required to edit
         * the package on the remote server. Sets Input errors on failure,
         * preventing the package from being edited.
         *
         * @param stdClass $package A stdClass object representing the selected package
         * @param array An array of key/value pairs used to edit the package
         * @return array A numerically indexed array of meta fields to be stored for this package containing:
         *     - key The key for this meta field
         *     - value The value for this key
         *     - encrypted Whether or not this field should be encrypted (default 0, not encrypted)
         * @see Module::getModule()
         * @see Module::getModuleRow()
         */
        public function editPackage($package, array $vars=null) {
            $meta = $this->processPackage("edit", $vars, $package);
        
            if ($this->Input->errors())
                return;
            return $meta;
        }
        
        /**
         * Returns the rendered view of the manage module page
         *
         * @param mixed $module A stdClass object representing the module and its rows
         * @param array $vars An array of post data submitted to or on the manager module page (used to repopulate fields after an error)
         * @return string HTML content containing information to display when viewing the manager module page
         */
        public function manageModule($module, array &$vars) {
            // Load the view into this object, so helpers can be automatically added to the view
            $this->view = new View("manage", "default");
            $this->view->base_uri = $this->base_uri;
            $this->view->setDefaultView("components" . DS . "modules" . DS . "universal_module" . DS);
            
            // Load the helpers required for this view
            Loader::loadHelpers($this, array("Form", "Html", "Widget"));
            $this->view->set("module", $module);
            
            return $this->view->fetch();
        }
        
        /**
         * Returns the rendered view of the add module row page
         *
         * @param array $vars An array of post data submitted to or on the add module row page (used to repopulate fields after an error)
         * @return string HTML content containing information to display when viewing the add module row page
         */
        public function manageAddRow(array &$vars) {
            // Load the view into this object, so helpers can be automatically added to the view
            $this->view = new View("add_row", "default");
            $this->view->base_uri = $this->base_uri;
            $this->view->setDefaultView("components" . DS . "modules" . DS . "universal_module" . DS);
            
            // Load the helpers required for this view
            Loader::loadHelpers($this, array("Form", "Html", "Widget"));
            
            if (!isset($vars['package_email_html']))
                $vars['package_email_html'] = "{% debug %}";
            if (!isset($vars['package_email_text']))
                $vars['package_email_text'] = "{% debug %}";
            if (!isset($vars['service_email_html']))
                $vars['service_email_html'] = "{% debug %}";
            if (!isset($vars['service_email_text']))
                $vars['service_email_text'] = "{% debug %}";
            
            $this->view->set("required_options", array('true' => Language::_("UniversalModule.true", true), 'false' => Language::_("UniversalModule.false", true)));
            $this->view->set("encrypt_options", array('true' => Language::_("UniversalModule.true", true), 'false' => Language::_("UniversalModule.false", true)));
            $this->view->set("field_types", $this->getFieldTypes());
            $this->view->set("package_notices", $this->getPackageNotices());
            $this->view->set("service_notices", $this->getServiceNotices());
            $this->view->set("vars", (object)$vars);
            return $this->view->fetch();
        }
        
        /**
         * Returns the rendered view of the edit module row page
         *
         * @param stdClass $module_row The stdClass representation of the existing module row
         * @param array $vars An array of post data submitted to or on the edit module row page (used to repopulate fields after an error)
         * @return string HTML content containing information to display when viewing the edit module row page
         */    
        public function manageEditRow($module_row, array &$vars) {
            // Load the view into this object, so helpers can be automatically added to the view
            $this->view = new View("edit_row", "default");
            $this->view->base_uri = $this->base_uri;
            $this->view->setDefaultView("components" . DS . "modules" . DS . "universal_module" . DS);
            
            // Load the helpers required for this view
            Loader::loadHelpers($this, array("Form", "Html", "Widget"));
            
            if (empty($vars))
                $vars = $this->formatModuleRowFields($module_row->meta);
            $this->view->set("required_options", array('true' => Language::_("UniversalModule.true", true), 'false' => Language::_("UniversalModule.false", true)));
            $this->view->set("encrypt_options", array('true' => Language::_("UniversalModule.true", true), 'false' => Language::_("UniversalModule.false", true)));
            $this->view->set("field_types", $this->getFieldTypes());
            $this->view->set("package_notices", $this->getPackageNotices());
            $this->view->set("service_notices", $this->getServiceNotices());        
            $this->view->set("vars", (object)$vars);
            return $this->view->fetch();
        }
        
        /**
         * Adds the module row on the remote server. Sets Input errors on failure,
         * preventing the row from being added.
         *
         * @param array $vars An array of module info to add
         * @return array A numerically indexed array of meta fields for the module row containing:
         *     - key The key for this meta field
         *     - value The value for this key
         *     - encrypted Whether or not this field should be encrypted (default 0, not encrypted)
         */
        public function addModuleRow(array &$vars) {
            $this->Input->setRules($this->getModuleRowRules($vars));
            
            if ($this->Input->validates($vars))
                return $this->formatRowMeta($vars);
        }
        
        /**
         * Edits the module row on the remote server. Sets Input errors on failure,
         * preventing the row from being updated.
         *
         * @param stdClass $module_row The stdClass representation of the existing module row
         * @param array $vars An array of module info to update
         * @return array A numerically indexed array of meta fields for the module row containing:
         *     - key The key for this meta field
         *     - value The value for this key
         *     - encrypted Whether or not this field should be encrypted (default 0, not encrypted)
         */
        public function editModuleRow($module_row, array &$vars) {
            $this->Input->setRules($this->getModuleRowRules($vars));
            
            if ($this->Input->validates($vars))
                return $this->formatRowMeta($vars);
        }
        
        /**
         * Returns all fields used when adding/editing a package, including any
         * javascript to execute when the page is rendered with these fields.
         *
         * @param $vars stdClass A stdClass object representing a set of post fields
         * @return ModuleFields A ModuleFields object, containg the fields to render as well as any additional HTML markup to include
         */
        public function getPackageFields($vars=null) {
            $fields = new ModuleFields();
            if (isset($vars->module_row) && $vars->module_row > 0) {
                $row = $this->getModuleRow($vars->module_row);
                
                $row_fields = array();
                if ($row->meta) {
                    $row_fields = $this->formatModuleRowFields($row->meta);
                    
                    $field_data = array();
                    // Reformat package fields into a more usable format
                    foreach ($row_fields['package_fields'] as $key => $values) {
                        foreach ($values as $i => $value) {
                            $field_data[$i][$key] = $value;
                        }
                    }
                    
                    $this->setModuleFields($fields, $field_data, $vars);
                }
            }
            elseif (isset($vars->module_id)) {
                $rows = $this->getModuleRows();
                
                if (empty($rows)) {
                    $uri = WEBDIR . Configure::get("Route.admin") . "/settings/company/modules/addrow/" . $vars->module_id;
                    $fields->setHtml(Language::_("UniversalModule.getPackageFields.empty_module_row", true, $uri));
                }
                else {
                    $fields->setHtml("
                        <script type=\"text/javascript\">
                            $(document).ready(function() {
                                // Fetch initial module options
                                fetchModuleOptions();
                            });
                        </script>
                    ");
                }
            }
            else {
                $fields->setHtml("
                    <script type=\"text/javascript\">
                        $(document).ready(function() {
                            // Fetch initial module options
                            fetchModuleOptions();
                        });
                    </script>
                ");
            }
            
            return $fields;
        }
        
        /**
         * Returns an array of key values for fields stored for a module, package,
         * and service under this module, used to substitute those keys with their
         * actual module, package, or service meta values in related emails.
         *
         * @return array A multi-dimensional array of key/value pairs where each key is one of 'module', 'package', or 'service' and each value is a numerically indexed array of key values that match meta fields under that category.
         * @see Modules::addModuleRow()
         * @see Modules::editModuleRow()
         * @see Modules::addPackage()
         * @see Modules::editPackage()
         * @see Modules::addService()
         * @see Modules::editService()
         */
        public function getEmailTags() {
            return array('module' => array("*"), 'package' => array("*"), 'service' => array("*"));
        }
        
        /**
         * Returns all fields to display to an admin attempting to add a service with the module
         *
         * @param stdClass $package A stdClass object representing the selected package
         * @param $vars stdClass A stdClass object representing a set of post fields
         * @return ModuleFields A ModuleFields object, containg the fields to render as well as any additional HTML markup to include
         */
        public function getAdminAddFields($package, $vars=null) {
            $fields = new ModuleFields();
            
            if (!isset($vars->meta))
                $vars->meta = array();
            
            if (isset($package->module_row) && $package->module_row > 0) {
                $row = $this->getModuleRow($package->module_row);
                
                // Set the module row, which will allow us to reference it later when getName() is invoked
                $this->setModuleRow($row);
                
                $row_fields = array();
                if ($row->meta) {
                    $row_fields = $this->formatModuleRowFields($row->meta);
                    
                    $field_data = array();
                    // Reformat package fields into a more usable format
                    foreach ($row_fields['service_fields'] as $key => $values) {
                        foreach ($values as $i => $value) {
                            $field_data[$i][$key] = $value;
                        }
                    }
                    
                    $this->setModuleFields($fields, $field_data, $vars);
                }
            }
            return $fields;
        }
        
        /**
         * Returns all fields to display to a client attempting to add a service with the module
         *
         * @param stdClass $package A stdClass object representing the selected package
         * @param $vars stdClass A stdClass object representing a set of post fields
         * @return ModuleFields A ModuleFields object, containg the fields to render as well as any additional HTML markup to include
         */    
        public function getClientAddFields($package, $vars=null) {
            // Same as admin
            return $this->getAdminAddFields($package, $vars);
        }
        
        /**
         * Returns all fields to display to an admin attempting to edit a service with the module
         *
         * @param stdClass $package A stdClass object representing the selected package
         * @param $vars stdClass A stdClass object representing a set of post fields
         * @return ModuleFields A ModuleFields object, containg the fields to render as well as any additional HTML markup to include
         */    
        public function getAdminEditFields($package, $vars=null) {
            // Same as adding
            return $this->getAdminAddFields($package, $vars);
        }
        
        /**
         * Fetches the HTML content to display when viewing the service info in the
         * admin interface.
         *
         * @param stdClass $service A stdClass object representing the service
         * @param stdClass $package A stdClass object representing the service's package
         * @return string HTML content containing information to display when viewing the service info
         */
        public function getAdminServiceInfo($service, $package) {
            return null;
        }
        
        /**
         * Fetches the HTML content to display when viewing the service info in the
         * client interface.
         *
         * @param stdClass $service A stdClass object representing the service
         * @param stdClass $package A stdClass object representing the service's package
         * @return string HTML content containing information to display when viewing the service info
         */
        public function getClientServiceInfo($service, $package) {

            return null;
        }
        
        /**
         * Attempts to validate service info. This is the top-level error checking method. Sets Input errors on failure.
         *
         * @param stdClass $package A stdClass object representing the selected package
         * @param array $vars An array of user supplied info to satisfy the request
         * @param boolean $edit True if this is an edit, false otherwise
         * @return boolean True if the service validates, false otherwise. Sets Input errors when false.
         */
        public function validateService($package, array $vars=null, $edit=false) {
            if ($package)
                $module_row_id = $package->module_row;
            else
                $module_row_id = isset($vars['module_row']) ? $vars['module_row'] : null;
            $row = $this->getModuleRow($module_row_id);
            
            if (!array_key_exists("meta", (array)$vars))
                $vars['meta'] = $vars;
            
            $rules = array();
            if ($row && $row->meta->service_rules != "" && isset($vars['meta'])) {
                Loader::loadComponents($this, array("Json"));
                $rules = $this->Json->decode($row->meta->service_rules, true);
            }
            $fields = $this->formatModuleRowFields($row->meta);
            
            // Set required rules
            if (isset($fields['service_fields']['required'])) {
                foreach ($fields['service_fields']['required'] as $i => $required) {
                    $name = $fields['service_fields']['name'][$i];
                    if ($required == "true") {
                        $is_array = (isset($vars['meta'][$name]) && is_array($vars['meta'][$name]));
                        $rules[$name]['required'] = array(
                            'rule' => $is_array ? "count" : "isEmpty",
                            'negate' => !$is_array,
                            'message' => Language::_("UniversalModule.!error.service_field.required", true, $fields['service_fields']['label'][$i])
                        );
                    }
                }
            }
            
            if (!isset($vars['meta']))
                $vars['meta'] = array();
            
            $this->Input->setRules($rules);
            $validation_fields = array_merge($vars['meta'], array_intersect_key($vars, array_flip(self::$reserved_fields)));
            return $this->Input->validates($validation_fields);
        }
        
        /**
         * Process Packages add/edit
         *
         * @param string $type The type of process (add/edit)
         * @param array $vars An array of key/value pairs
         * @return array A numerically indexed array of meta fields to be stored for this package containing:
         *     - key The key for this meta field
         *     - value The value for this key
         *     - encrypted Whether or not this field should be encrypted (default 0, not encrypted)
         */
        private function processPackage($type, array $vars, $package = null) {
            $module_row_id = null;
            if (isset($vars['module_row']) && $vars['module_row'])
                $module_row_id = $vars['module_row'];
            elseif ($package)
                $module_row_id = $package->module_row;
            $row = $this->getModuleRow($module_row_id);
            if (!$row) {
                $this->Input->setErrors(array(
                    'module_row' => array(
                        'invalid' => Language::_("UniversalModule.!error.module_row.invalid", true)
                    )
                ));
                return;
            }
            
            $rules = array();
            if (isset($row->meta->package_rules) && $row->meta->package_rules != "" && isset($vars['meta'])) {
                Loader::loadComponents($this, array("Json"));
                $rules = $this->Json->decode($row->meta->package_rules, true);
            }
            $fields = $this->formatModuleRowFields($row->meta);
            
            // Set required rules
            if (isset($fields['package_fields']['required'])) {
                foreach ($fields['package_fields']['required'] as $i => $required) {
                    $name = $fields['package_fields']['name'][$i];
                    if ($required == "true") {
                        $is_array = (isset($vars['meta'][$name]) && is_array($vars['meta'][$name]));
                        $rules[$name]['required'] = array(
                            'rule' => $is_array ? "count" : "isEmpty",
                            'negate' => !$is_array,
                            'message' => Language::_("UniversalModule.!error.package_field.required", true, $fields['package_fields']['label'][$i])
                        );
                    }
                }
            }
            
            $this->Input->setRules($rules);
            if (!$this->Input->validates($vars['meta']))
                return;
            
            $meta = array();
            if (isset($fields['package_fields']['name'])) {
                foreach ($fields['package_fields']['name'] as $i => $value) {
                    if ($fields['package_fields']['type'][$i] == "secret")
                        continue;
                    
                    $meta[] = array(
                        'key' => $value,
                        'value' => isset($vars['meta'][$value]) ? $vars['meta'][$value] : "",
                        'encrypted' => $fields['package_fields']['encrypt'][$i] == "true" ? 1 : 0
                    );
                }
            }
            
            if (!$this->sendNotification("package_notice_" . $type, $meta, $module_row_id, $vars)) {
                $this->Input->setErrors(array('package_notice_' . $type => array('failed' => Language::_("UniversalModule.!error.package_notice_" . $type . ".failed", true))));
                return;
            }
            
            return $meta;
        }
        
        /**
         * Process Services add/edit
         *
         * @param string $type The type of process (add/edit)
         * @param array $vars An array of key/value pairs
         * @return array A numerically indexed array of meta fields to be stored for this service containing:
         *     - key The key for this meta field
         *     - value The value for this key
         *     - encrypted Whether or not this field should be encrypted (default 0, not encrypted)
         */
        private function processService($type, array $vars, $package = null) {
            if ($package)
                $module_row_id = $package->module_row;
            else
                $module_row_id = isset($vars['module_row']) ? $vars['module_row'] : null;
            $this->validateService($package, $vars, $type == "edit");
            
            if ($this->Input->errors())
                return;
            
            $row = $this->getModuleRow($module_row_id);
            $fields = $this->formatModuleRowFields($row->meta);
            
            $meta = null;
            if (isset($fields['service_fields']['name'])) {
                foreach ($fields['service_fields']['name'] as $i => $value) {
                    if ($fields['service_fields']['type'][$i] == "secret")
                        continue;
        
                    if (isset($vars['meta'][$value]) || isset($vars[$value])) {
                        if (!$meta)
                            $meta = array();
                            
                        $meta[] = array(
                            'key' => $value,
                            'value' => isset($vars['meta'][$value]) ? $vars['meta'][$value] : $vars[$value],
                            'encrypted' => $fields['service_fields']['encrypt'][$i] == "true" ? 1 : 0
                        );
                    }
                }
            }
            
            if (isset($vars['use_module']) && $vars['use_module'] == "true") {
                if (!$this->sendNotification("service_notice_" . $type, $meta, $module_row_id, $vars, $package->meta)) {
                    $this->Input->setErrors(array('service_notice_' . $type => array('failed' => Language::_("UniversalModule.!error.service_notice_" . $type . ".failed", true))));
                    return;
                }
            }
            
            return $meta;
        }
        
        /**
         * Sets fields into the ModuleFields object according to $field_data
         *
         * @param ModuleFields $fields The ModuleFields object to set fields to
         * @param array $field_data A numerically indexed array of field data including:
         *     - type
         *     - label
         *     - name
         *     - values
         * @param stdClass $vars A stdClass object representing input fields
         */
        private function setModuleFields(ModuleFields $fields, array $field_data, $vars=null) {
            Loader::loadHelpers($this, array("Html"));
            foreach ($field_data as $field) {
                $options = $this->unserializeMetaValues($field['values']);
                $field_type = "field" . ucfirst($field['type']);
                $field_name = "meta[" . $field['name'] . "]";
                $field_value = $this->Html->ifSet($vars->meta[$field['name']], $this->Html->ifSet($vars->{$field['name']}, $field['values']));
                
                if (in_array($field['name'], self::$reserved_fields)) {
                    $field_name = $field['name'];
                    $field_value = $this->Html->ifSet($vars->{$field['name']});
                }
                
                switch ($field['type']) {
                    case "text":
                    case "hidden":
                    case "textarea":
                        $label = $fields->label($field['label'], "uni_" . $field['name']);
                        $label->attach($fields->{$field_type}($field_name,
                            $field_value, array('id'=>"uni_" . $field['name'])));
                        $fields->setField($label);
                        break;
                    case "password":
                        $label = $fields->label($field['label'], "uni_" . $field['name']);
                        $label->attach($fields->{$field_type}($field_name,
                            array('id'=>"uni_" . $field['name'], 'value' => $field_value)));
                        $fields->setField($label);
                        break;
                    case "select":
                        $label = $fields->label($field['label'], "uni_" . $field['name']);
                        $label->attach($fields->{$field_type}($field_name, $options,
                            $field_value, array('id'=>"uni_" . $field['name'])));
                        $fields->setField($label);
                        break;
                    case "radio":
                    case "checkbox":
                        $label = $fields->label($field['label'], "uni_" . $field['name']);
                        foreach ($options as $key => $value) {
                            
                            $field_label = $fields->label($value, "uni_" . $field['name'] . "_" . $key);
                            
                            $checked = in_array($key, (array)$field_value);
                            
                            $label->attach($fields->{$field_type}($field_name . ($field['type'] == "checkbox" ? "[]" : ""),
                                $key, $checked, array('id'=>"uni_" . $field['name'] . "_" . $key), $field_label));
                        }
                        $fields->setField($label);
                        break;
                }
            }
        }
        
        /**
         * Sends notification for the given action if supported by the module row
         *
         * @param string $action The action to send a notification for
         * @param array $meta A numerically indexed array of meta fields containing:
         *     - key The key for this meta field
         *     - value The value for this key
         * @param int $module_row_id The ID of the module row to send the notification for
         * @param array $additional_fields An array of key/value pairs to send in the notification
         * @param stdClass $package_meta A stdClass object of package meta data (if any)
         * @return boolean True if the notice was successful, false otherwise
         */
        private function sendNotification($action, $meta, $module_row_id = null, $additional_fields = null, $package_meta = null) {
            $row = $this->getModuleRow($module_row_id);
            
            if ($row) {
                $tags = $this->serviceFieldsToObject((array)$meta);
                
                if ($package_meta) {
                    foreach ($package_meta as $key => $value) {
                        if (!isset($tags->{$key}))
                            $tags->{$key} = $value;
                    }
                }
                
                // Look for 'secret' package fields to append
                $meta_fields = $this->formatModuleRowFields($row->meta);
                if (isset($meta_fields['package_fields']['type'])) {
                    foreach ($meta_fields['package_fields']['type'] as $i => $type) {
                        $key = $meta_fields['package_fields']['name'][$i];
                        if ($type == "secret" && !isset($tags->{$key}))
                            $tags->{$key} = $meta_fields['package_fields']['values'][$i];
                    }
                }
                
                // Look for 'secret' service fields to append if this is a service notice
                if (strpos($action, "service") !== false && isset($meta_fields['service_fields']['type'])) {
                    foreach ($meta_fields['service_fields']['type'] as $i => $type) {
                        if ($type == "secret")
                            $tags->{$meta_fields['service_fields']['name'][$i]} = $meta_fields['service_fields']['values'][$i];
                    }
                }
                $tags->_other = $additional_fields;
                
                if (isset($row->meta->{$action}) && trim($row->meta->{$action}) != "") {
                    
                    if ($this->isUrl($row->meta->{$action})) {
                        $code = str_replace("notice", "code", $action);
                        $response = str_replace("notice", "response", $action);
                        
                        return $this->sendHttpNotice($row->meta->{$action}, (array)$tags, $row->meta->{$code}, $row->meta->{$response});
                    }
                    else
                        $this->sendEmailNotice($action, (array)$tags, $row->meta);
                }
            }
            
            return true;
        }
        
        /**
         * Sends an email notification to the given address with the given tags
         *
         * @param string $action The action to send the notification for
         * @param array $tags A key/value pairs of tags and their replacement data
         * @param stdClass $meta A stdClass object of module row meta field data
         * @return boolean True if the email was successfully sent, false otherwise
         */
        private function sendEmailNotice($action, $tags, $meta) {
            
            Loader::loadModels($this, array("Emails"));
            
            $to = $meta->{$action};
            $from = null;
            $subject = null;
            $body = null;
            
            if (strpos($action, "service") !== false) {
                $from = $meta->service_email_from;
                $subject = $meta->service_email_subject;
                $body = array('text' => $meta->service_email_text, 'html' => $meta->service_email_html);
            }
            else {
                $from = $meta->package_email_from;
                $subject = $meta->package_email_subject;
                $body = array('text' => $meta->package_email_text, 'html' => $meta->package_email_html);            
            }
            
            $this->Emails->sendCustom($from, $from, $to, $subject, $body, $tags);
            
            if (($errors = $this->Emails->errors())) {
                $this->Input->setErrors($errors);
                return false;
            }
            return true;
        }
        
        /**
         * Sends an HTTP POST request to the given URL with the given arguments
         *
         * @param string $url The URL to post
         * @param array $args An array of key/value post fields
         * @param string $response_code The response code to accept for successful responses
         * @param string $response The response to expect for successful responses, may be a regular expression
         * @return boolean True on success, false on error
         */
        private function sendHttpNotice($url, $args, $response_code = null, $response = null) {
            // Log request
            $this->log($url, serialize($args), "input", true);
            
            $pass = true;
            $output = $this->httpRequest("POST", $url, $args);
            
            if ($response_code != "") {
                if (isset($this->Http)) {
                    if ($response_code != $this->Http->responseCode())
                        $pass = false;
                }
            }
            
            if ($response != "") {
                if (strpos($output, $response) === false)
                    $pass = false;
            }
            
            // Log output
            $this->log($url, $output, "output", $pass);
            return $pass;
        }
        
        /**
         * Formats module row input fields into a proper format required by Module::addModuleRow() and Module::editModuleRow().
         *
         * @param array An array of input key/value pairs
         * @return array A numerically indexed array of meta fields for the module row containing:
         *     - key The key for this meta field
         *     - value The value for this key
         *     - encrypted Whether or not this field should be encrypted (default 0, not encrypted)
         */
        private function formatRowMeta(array &$vars) {
            $meta = array();
            $meta_fields = array("name", "package_rules", "service_rules",
                "package_email_from", "package_email_subject", "package_email_html", "package_email_text",
                "service_email_from", "service_email_subject", "service_email_html", "service_email_text");
            
            foreach ($this->getPackageNotices() as $key => $value) {
                $meta_fields[] = "package_notice_" . $key;
                $meta_fields[] = "package_code_" . $key;
                $meta_fields[] = "package_response_" . $key;
            }
            
            foreach ($this->getServiceNotices() as $key => $value) {
                $meta_fields[] = "service_notice_" . $key;
                $meta_fields[] = "service_code_" . $key;
                $meta_fields[] = "service_response_" . $key;
            }
            
            foreach ($vars as $key => $value) {
                if (in_array($key, $meta_fields)) {
                    $meta[] = array(
                        'key'=>$key,
                        'value'=>$value
                    );
                }
            }
            
            if (isset($vars['package_fields'])) {
                for ($j=0, $i=0; $i<count($vars['package_fields']['label']); $i++) {
                    
                    if ($vars['package_fields']['name'][$i] == "")
                        continue;
                    
                    $meta[] = array(
                        'key' => "package_field_label_" . $j,
                        'value' => $vars['package_fields']['label'][$i]
                    );
                    $meta[] = array(
                        'key' => "package_field_name_" . $j,
                        'value' => $vars['package_fields']['name'][$i]
                    );
                    $meta[] = array(
                        'key' => "package_field_type_" . $j,
                        'value' => $vars['package_fields']['type'][$i]
                    );
                    $meta[] = array(
                        'key' => "package_field_values_" . $j,
                        'value' => $vars['package_fields']['values'][$i]
                    );
                    $meta[] = array(
                        'key' => "package_field_required_" . $j,
                        'value' => $vars['package_fields']['required'][$i]
                    );
                    $meta[] = array(
                        'key' => "package_field_encrypt_" . $j,
                        'value' => $vars['package_fields']['encrypt'][$i]
                    );
                    
                    $j++;
                }
            }
            
            if (isset($vars['service_fields'])) {
                for ($j=0, $i=0; $i<count($vars['service_fields']['label']); $i++) {
                    
                    if ($vars['service_fields']['name'][$i] == "")
                        continue;
                    
                    $meta[] = array(
                        'key' => "service_field_label_" . $j,
                        'value' => $vars['service_fields']['label'][$i]
                    );
                    $meta[] = array(
                        'key' => "service_field_name_" . $j,
                        'value' => $vars['service_fields']['name'][$i]
                    );
                    $meta[] = array(
                        'key' => "service_field_type_" . $j,
                        'value' => $vars['service_fields']['type'][$i]
                    );
                    $meta[] = array(
                        'key' => "service_field_values_" . $j,
                        'value' => $vars['service_fields']['values'][$i]
                    );
                    $meta[] = array(
                        'key' => "service_field_required_" . $j,
                        'value' => $vars['service_fields']['required'][$i]
                    );
                    $meta[] = array(
                        'key' => "service_field_encrypt_" . $j,
                        'value' => $vars['service_fields']['encrypt'][$i]
                    );
                    
                    $j++;
                }
            }
            
            return $meta;
        }
        
             /**
             * Returns all tabs to display to a client when managing a service whose
             * package uses this module
             *
             * @param stdClass $package A stdClass object representing the selected package
             * @return array An array of tabs in the format of method => title. Example: array('methodName' => "Title", 'methodName2' => "Title2")
             */
            public function getClientTabs($package) {
                    return array(
                            'moreinfo' => array('name' => "管理中心", 'icon' => "fa fa-gears")
             //   'console' => array('name' => Language::_("Multicraft.tab_client_console", true), 'icon' => "fa fa-terminal")
                    );
            }
        /**
         * The More Info tab
         *
         * @param stdClass $package A stdClass object representing the current package
             * @param stdClass $service A stdClass object representing the current service
             * @param array $get Any GET parameters
             * @param array $post Any POST parameters
             * @param array $files Any FILES parameters
             * @return string The string representing the contents of this tab
         */
        public function moreinfo($package, $service, array $get=null, array $post=null, array $files=null) {
             $row = $this->getModuleRow($package->module_row);
             $out = '';
             $servicefields = array();
             foreach ($row->meta as $key=>$value ) {
                  if (strpos($key, "service_field_name") !== false) {
                    // Here we match the service field label with their key and value
                    foreach($service->fields as $field) {
                      if($field->key == $value) {
                         $name = 'service_field_label_' . str_replace('service_field_name_', '', $key);
                         $servicefields[] = array("label" => $row->meta->$name,
                                                  "key" => $value,
                                                  "value" => $field->value); 
                      }
                    }
                  }
             }
             foreach($servicefields as $field) {
                // Filter out for showing only public fields
                if(strpos($field['key'], "public_") === 0 ) {
                  $out .= "<p><b>". $field['label'] . ":</b> " . $field['value'] . "</p>"; 
                }
             }
             return "<h4>服务器参数</h4><br />" . $out ;
      
        }
        /**
         * Converts module row meta fields from key/value pairs to array sets suitable
         * for use in forms.
         *
         * @param stdClass $module_row_meta An object of module row meta fields
         * @return array An array of formatted module row meta fields
         */
        private function formatModuleRowFields($module_row_meta) {
            $fields = array('package_fields' => array(), 'service_fields' => array());
            foreach ($module_row_meta as $key => $value) {
                $index = ltrim(strrchr($key, "_"), "_");
                if (substr($key, 0, 14) == "package_field_") {
                    $key = str_replace("_" . $index, "", str_replace("package_field_", "", $key));
                    $fields['package_fields'][$key][$index] = $value;
                }
                elseif (substr($key, 0, 14) == "service_field_") {
                    $key = str_replace("_" . $index, "", str_replace("service_field_", "", $key));
                    $fields['service_fields'][$key][$index] = $value;
                }
                else {
                    $fields[$key] = $value;
                }
            }
            return $fields;
        }
        
        /**
         * Unserialize meta values of the format key2:value|key2:value2
         *
         * @param string $values A serialized set of values
         * @return array An array of key/value pairs
         */
        private function unserializeMetaValues($values) {
            if ($values == "")
                return array();
                
            $pairs = preg_split('~(?<!\\\)' . preg_quote("|", '~') . '~', $values);
            
            $options = array();
            foreach ($pairs as $pair) {
                $pair = preg_split('~(?<!\\\)' . preg_quote(":", '~') . '~', $pair);
                //$pair = preg_split('~\\\\.(*SKIP)(*FAIL)|\:~s', $pair);
                if (count($pair) == 2)
                    $options[stripslashes($pair[0])] = stripslashes($pair[1]);
            }
            
            return $options;
        }
        
        /**
         * Returns a key/value pair of package notices, which are events that trigger
         * a HTTP POST or Email to a given location
         *
         * @return array An array of key/value pair package notices, where each key is the notice type and each value is its name
         */
        private function getPackageNotices() {
            return array(
                'add' => Language::_("UniversalModule.getpackagenotices.add", true),
                'edit' => Language::_("UniversalModule.getpackagenotices.edit", true)
            );
        }
        /**
         * Returns a key/value pair of service notices, which are events that trigger
         * a HTTP POST or Email to a given location
         *
         * @return array An array of key/value pair service notices, where each key is the notice type and each value is its name
         */    
        private function getServiceNotices() {
            return array(
                'add' => Language::_("UniversalModule.getservicenotices.add", true),
                'edit' => Language::_("UniversalModule.getservicenotices.edit", true),
                'suspend' => Language::_("UniversalModule.getservicenotices.suspend", true),
                'unsuspend' => Language::_("UniversalModule.getservicenotices.unsuspend", true),
                'cancel' => Language::_("UniversalModule.getservicenotices.cancel", true),
                'renew' => Language::_("UniversalModule.getservicenotices.renew", true),
                'package_change' => Language::_("UniversalModule.getservicenotices.package_change", true),
            );
        }
        
        /**
         * Returns a key/value pair of all input field types supported
         *
         * @return array An array of key/value pairs of input field types supported, where each key is the field type and each value it its name
         */
        private function getFieldTypes() {
            return array(
                'text' => Language::_("UniversalModule.getfieldtypes.text", true),
                'textarea' => Language::_("UniversalModule.getfieldtypes.textarea", true),
                'password' => Language::_("UniversalModule.getfieldtypes.password", true),
                'select' => Language::_("UniversalModule.getfieldtypes.select", true),
                'radio' => Language::_("UniversalModule.getfieldtypes.radio", true),
                'checkbox' => Language::_("UniversalModule.getfieldtypes.checkbox", true),
                'hidden' => Language::_("UniversalModule.getfieldtypes.hidden", true),
                'secret' => Language::_("UniversalModule.getfieldtypes.secret", true),
            );
        }
        
        /**
         * Returns all rules to validate when adding/edit a module row
         *
         * @return array An array of rules to validate when adding/editing a module row
         */
        private function getModuleRowRules(array $vars) {
            $rules = array(
                'name' => array(
                    'empty' => array(
                        'rule' => "isEmpty",
                        'negate' => true,
                        'message' => Language::_("UniversalModule.!error.name.empty", true)
                    )
                )
            );
            
            foreach ($vars as $key => $value) {
                if (strpos($key, "service_notice_") !== false && $value != "" && !$this->isUrl($value)) {
                    $rules['service_email_from']['required'] = array(
                        'rule' => "isEmail",
                        'message' => Language::_("UniversalModule.!error.service_email_from.required", true)
                    );
                }
                elseif (strpos($key, "package_notice_") !== false && $value != "" && !$this->isUrl($value)) {
                    $rules['package_email_from']['required'] = array(
                        'rule' => "isEmail",
                        'message' => Language::_("UniversalModule.!error.package_email_from.required", true)
                    );
                }
            }
            
            return $rules;
        }
        
        /**
         * Verifies whether or not the givne str is a URL
         *
         * @param string $str A string
         * @return boolean True if $str is a URL, false otherwise
         */
        private function isUrl($str) {
            return preg_match("#^\S+://\S+\.\S+.+$#", $str);
        }
    }
    ?>
     
  11. Like
    huangsenli got a reaction from Paul in How to sell a dedicated server   
    Very good. The problem of dedicated servers has been solved.
  12. Like
  13. Like
    huangsenli got a reaction from activa in reCAPTCHA帮助   
    Is the member verification code only available for Google? Google's verification code can't be used in China. China is blocking Google's website. Is there any other verification code? No verification code was swiped by 6000 members for an hour.
     
  14. Like
    huangsenli got a reaction from activa in 升级blesta 4.4.0原来如此简单   
    原来以为好复杂没有想到一下子就成功了
     
  15. Like
    huangsenli got a reaction from Paul in 升级blesta 4.4.0原来如此简单   
    原来以为好复杂没有想到一下子就成功了
     
  16. Like
    huangsenli got a reaction from Paul in 非常不错的blesta模板   
    原来还有这么漂亮的模板
    https://www.gloaug.com/

  17. Like
    huangsenli got a reaction from Blesta Addons in 非常不错的blesta模板   
    原来还有这么漂亮的模板
    https://www.gloaug.com/

  18. Thanks
    huangsenli got a reaction from Blesta Addons in 升级blesta 4.4.0原来如此简单   
    原来以为好复杂没有想到一下子就成功了
     
  19. Haha
    huangsenli reacted to Paul in Release 4.4.0   
    Version 4.4.0 is now available. You can download directly right here.

    Installing Blesta

    See Installing Blesta in the User Manual for instructions.

    Upgrading Blesta

    See Upgrading Blesta in the User Manual for instructions.

    Migrating to Blesta

    See Migrating to Blesta in the User Manual for instructions.
     
    Overview
    New config option field types: text, textarea, password Markdown editor where markdown is supported Client payment type overrides for credit card and ACH Improved addon service management New Modules: cWatch, WHMSonic New Gateway: GoCardless Upgraded TCPDF, reduced file size of invoices and added new fonts Upgraded client area and front facing pages to latest Bootstrap 3.3.7 Improvements for PHP 7.2 Release Notes

    See Blesta Core - Version 4.4.0.

    For older releases see all Change Logs.
  20. Like
    huangsenli got a reaction from Paul in How is this domain registration done?   
    感谢兄弟成功开启了域名注册功能了。
  21. Like
    huangsenli got a reaction from Paul in cPanel problem appear   
    感谢兄弟,成功了
  22. Like
    huangsenli got a reaction from Jono in cPanel problem appear   
    感谢兄弟,成功了
  23. Like
    huangsenli got a reaction from Jono in How is this domain registration done?   
    感谢兄弟成功开启了域名注册功能了。
  24. Confused
    huangsenli got a reaction from Abdy in 求助购物车到最后一步销售0元如何处理?   
    我的网站不知道怎么回事前面都好好的到了最后一步付款就出现问题了,直接显示0元就可以付款,我安装论坛上教程做也没有用。
     
    已经添加了代码还是不行怎么回事。
     
      if (!$prorate->canProrate() && !$prorate->prorateDate()) {
    continue;
     }
     // Prorate
    $item->setPrice($prorate->proratePrice($item->price()));
                $endDate = $prorate->prorateDate();
     
×
×
  • Create New...