Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save ctalkington/7f31f81cb14a5251143b to your computer and use it in GitHub Desktop.
Save ctalkington/7f31f81cb14a5251143b to your computer and use it in GitHub Desktop.
Blesta - Patch for Forum Post #3279
<?php
// Errors
$lang['Plesk.!error.simplexml_required'] = "The simplexml extension is required for this module.";
$lang['Plesk.!error.api.internal'] = "An internal error occurred, or the server did not respond to the request.";
$lang['Plesk.!error.server_name.empty'] = "You must enter a Server Label.";
$lang['Plesk.!error.host_name.valid'] = "The Hostname appears to be invalid.";
$lang['Plesk.!error.ip_address.valid'] = "The IP address appears to be invalid.";
$lang['Plesk.!error.port.format'] = "The port number must be a number.";
$lang['Plesk.!error.username.empty'] = "Please enter a username.";
$lang['Plesk.!error.password.empty'] = "Please enter a password.";
$lang['Plesk.!error.panel_version.valid'] = "Please select your Plesk Panel version.";
$lang['Plesk.!error.reseller.valid'] = "Whether this account is a reseller account must be set to true or false.";
$lang['Plesk.!error.meta[plan].empty'] = "Please select a service plan.";
$lang['Plesk.!error.meta[reseller_plan].empty'] = "Please select a reseller account plan.";
$lang['Plesk.!error.meta[type].valid'] = "Account type must be either standard or reseller.";
$lang['Plesk.!error.plesk_domain.format'] = "Please enter a valid domain name, e.g. domain.com";
$lang['Plesk.!error.plesk_username.length'] = "The username must be between 1 and 60 characters in length.";
$lang['Plesk.!error.plesk_password.length'] = "The password must be between 5 and 14 characters in length.";
$lang['Plesk.!error.plesk_confirm_password.matches'] = "The passwords do not match.";
$lang['Plesk.!error.plesk_webspace_id.exists'] = "The Subscription ID given does not exist in Plesk.";
$lang['Plesk.!error.downgrade.unsupported'] = "Downgrading from a reseller account to a non-reseller account is not supported.";
$lang['Plesk.!error.api.webspace_delete_filter_missing'] = "Missing filter for deleting a specific subscription.";
$lang['Plesk.!error.api.customer_delete_filter_missing'] = "Missing filter for deleting a specific customer.";
$lang['Plesk.!error.api.reseller_delete_filter_missing'] = "Missing filter for deleting a specific reseller.";
// Common
$lang['Plesk.please_select'] = "-- Please Select --";
// Tabs
$lang['Plesk.tab_stats'] = "Statistics";
$lang['Plesk.tab_client_stats'] = "Statistics";
// Statistics
$lang['Plesk.stats.unlimited'] = "Unlimited";
$lang['Plesk.!bytes.value'] = "%1\$s %2\$s"; // %1$s is a number value, %2$s is the unit of that value (i.e., one of B, KB, MB, GB)
// Tab Stats
$lang['Plesk.tab_stats.info_title'] = "Information";
$lang['Plesk.tab_stats.bandwidth_title'] = "Bandwidth";
$lang['Plesk.tab_stats.disk_title'] = "Disk";
$lang['Plesk.tab_stats.info_heading.field'] = "Field";
$lang['Plesk.tab_stats.info_heading.value'] = "Value";
$lang['Plesk.tab_stats.bandwidth_heading.used'] = "Used";
$lang['Plesk.tab_stats.bandwidth_heading.limit'] = "Limit";
$lang['Plesk.tab_stats.disk_heading.used'] = "Used";
$lang['Plesk.tab_stats.disk_heading.limit'] = "Limit";
$lang['Plesk.tab_stats.info.domain'] = "Domain";
$lang['Plesk.tab_stats.info.ip_address'] = "IP Address";
// Tab Client Stats
$lang['Plesk.tab_client_stats.info_title'] = "Information";
$lang['Plesk.tab_client_stats.info_heading.field'] = "Field";
$lang['Plesk.tab_client_stats.info_heading.value'] = "Value";
$lang['Plesk.tab_client_stats.info.domain'] = "Domain";
$lang['Plesk.tab_client_stats.info.ip_address'] = "IP Address";
$lang['Plesk.tab_client_stats.disk_title'] = "Disk Usage";
$lang['Plesk.tab_client_stats.bandwidth_title'] = "Bandwidth Usage";
$lang['Plesk.tab_client_stats.usage'] = "(%1\$s/%2\$s)"; // %1$s is the amount of resource usage, %2$s is the resource usage limit
$lang['Plesk.tab_client_stats.not_available'] = "NA";
// Basics
$lang['Plesk.name'] = "Plesk";
$lang['Plesk.module_row'] = "Server";
$lang['Plesk.module_row_plural'] = "Servers";
$lang['Plesk.module_group'] = "Server Group";
// Service fields
$lang['Plesk.service_field.domain'] = "Domain";
$lang['Plesk.service_field.username'] = "Username";
$lang['Plesk.service_field.password'] = "Password";
$lang['Plesk.service_field.confirm_password'] = "Confirm Password";
$lang['Plesk.service_field.webspace_id'] = "Subscription (Webspace) ID";
$lang['Plesk.service_field.tooltip.username'] = "You may leave the username blank to automatically generate one.";
$lang['Plesk.service_field.tooltip.password'] = "You may leave the password blank to automatically generate one.";
$lang['Plesk.service_field.tooltip.webspace_id'] = "Only set a Subscription ID if you are not provisioning this service with the module. It may be used for certain API requests.";
$lang['Plesk.service_field.tooltip.webspace_id_edit'] = "The Subscription ID will only be changed locally. It will not be changed in Plesk.";
// Package fields
$lang['Plesk.package_fields.plan'] = "Plesk Service Plan";
$lang['Plesk.package_fields.type'] = "Account Type";
$lang['Plesk.package_fields.type_standard'] = "Standard";
$lang['Plesk.package_fields.type_reseller'] = "Reseller";
$lang['Plesk.package_fields.reseller_plan'] = "Reseller Account Plan";
// Service info
$lang['Plesk.service_info.username'] = "Username";
$lang['Plesk.service_info.password'] = "Password";
$lang['Plesk.service_info.server'] = "Server";
$lang['Plesk.service_info.options'] = "Options";
$lang['Plesk.service_info.option_login'] = "Log in";
// Add module row
$lang['Plesk.add_row.box_title'] = "Add Plesk Server";
$lang['Plesk.add_row.basic_title'] = "Basic Settings";
$lang['Plesk.add_row.add_btn'] = "Add Server";
// Edit module row
$lang['Plesk.edit_row.box_title'] = "Edit Plesk Server";
$lang['Plesk.edit_row.basic_title'] = "Basic Settings";
$lang['Plesk.edit_row.add_btn'] = "Edit Server";
// Module row meta data
$lang['Plesk.row_meta.server_name'] = "Server Label";
$lang['Plesk.row_meta.host_name'] = "Hostname";
$lang['Plesk.row_meta.ip_address'] = "IP Address";
$lang['Plesk.row_meta.port'] = "Port";
$lang['Plesk.row_meta.username'] = "Username";
$lang['Plesk.row_meta.password'] = "Password";
$lang['Plesk.row_meta.reseller'] = "Reseller Account";
$lang['Plesk.row_meta.panel_version'] = "Plesk Panel Version";
$lang['Plesk.row_meta.tooltip.reseller'] = "Check this box if this is a Plesk Reseller account. Plesk Administrator accounts may leave this box unchecked.";
// Module management
$lang['Plesk.order_options.first'] = "First non-full server";
$lang['Plesk.add_module_row'] = "Add Server";
$lang['Plesk.add_module_group'] = "Add Server Group";
$lang['Plesk.manage.module_rows_title'] = "Servers";
$lang['Plesk.manage.module_groups_title'] = "Server Groups";
$lang['Plesk.manage.module_rows_heading.name'] = "Server Label";
$lang['Plesk.manage.module_rows_heading.host_name'] = "Hostname";
$lang['Plesk.manage.module_rows_heading.ip_address'] = "IP Address";
$lang['Plesk.manage.module_rows_heading.options'] = "Options";
$lang['Plesk.manage.module_groups_heading.name'] = "Group Name";
$lang['Plesk.manage.module_groups_heading.servers'] = "Server Count";
$lang['Plesk.manage.module_groups_heading.options'] = "Options";
$lang['Plesk.manage.module_rows.edit'] = "Edit";
$lang['Plesk.manage.module_groups.edit'] = "Edit";
$lang['Plesk.manage.module_rows.delete'] = "Delete";
$lang['Plesk.manage.module_groups.delete'] = "Delete";
$lang['Plesk.manage.module_rows.confirm_delete'] = "Are you sure you want to delete this server?";
$lang['Plesk.manage.module_groups.confirm_delete'] = "Are you sure you want to delete this server group?";
$lang['Plesk.manage.module_rows_no_results'] = "There are no servers.";
$lang['Plesk.manage.module_groups_no_results'] = "There are no server groups.";
// Panel versions
$lang['Plesk.panel_version.windows'] = "Windows";
$lang['Plesk.panel_version.linux'] = "Linux/Unix";
$lang['Plesk.panel_version.plesk_type'] = "Plesk %1\$s for %2\$s"; // %1$s is the Plesk panel version number, %2$s is the OS type (i.e. Windows or Linux/Unix)
$lang['Plesk.panel_version.plesk'] = "Plesk %1\$s"; // %1$s is the Plesk panel version number
$lang['Plesk.panel_version.parallels'] = "Parallels Plesk Panel %1\$s"; // %1$s is the Plesk panel version number
?>
<?php
/**
* Plesk Module
*
* @package blesta
* @subpackage blesta.components.modules.plesk
* @copyright Copyright (c) 2013, Phillips Data, Inc.
* @license http://www.blesta.com/license/ The Blesta License Agreement
* @link http://www.blesta.com/ Blesta
*/
class Plesk extends Module {
/**
* @var string The version of this module
*/
private static $version = "2.1.0";
/**
* @var string The authors of this module
*/
private static $authors = array(array('name'=>"Phillips Data, Inc.",'url'=>"http://www.blesta.com"));
/**
* @var array A list of Plesk panel versions
*/
private $panel_versions = array();
/**
* 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("plesk", null, dirname(__FILE__) . DS . "language" . DS);
// Setup panel versions
$this->init();
}
/**
* Initializes the panel versions
*/
private function init() {
$windows = Language::_("Plesk.panel_version.windows", true);
$linux = Language::_("Plesk.panel_version.linux", true);
$versions = array(
'7.5.4' => array('name' => Language::_("Plesk.panel_version.plesk_type", true, "7.5.4", $linux), 'api_version' => "1.3.5.1", 'supported' => false),
'7.5.6' => array('name' => Language::_("Plesk.panel_version.plesk_type", true, "7.5.6", $windows), 'api_version' => "1.4.0.0", 'supported' => false),
'7.6' => array('name' => Language::_("Plesk.panel_version.plesk_type", true, "7.6", $windows), 'api_version' => "1.4.0.0", 'supported' => false),
'7.6.1' => array('name' => Language::_("Plesk.panel_version.plesk_type", true, "7.6.1", $windows), 'api_version' => "1.4.1.1", 'supported' => false),
'8.0' => array('name' => Language::_("Plesk.panel_version.plesk_type", true, "8.0", $linux), 'api_version' => "1.4.0.0", 'supported' => false),
'8.0.1' => array('name' => Language::_("Plesk.panel_version.plesk_type", true, "8.0.1", $linux), 'api_version' => "1.4.1.2", 'supported' => false),
'8.1.0' => array('name' => Language::_("Plesk.panel_version.plesk", true, "8.1.0"), 'api_version' => "1.4.2.0", 'supported' => false),
'8.1.1' => array('name' => Language::_("Plesk.panel_version.plesk", true, "8.1.1"), 'api_version' => "1.5.0.0", 'supported' => false),
'8.2' => array('name' => Language::_("Plesk.panel_version.plesk", true, "8.2"), 'api_version' => "1.5.1.0", 'supported' => false),
'8.3' => array('name' => Language::_("Plesk.panel_version.plesk", true, "8.3"), 'api_version' => "1.5.2.0", 'supported' => false),
'8.4' => array('name' => Language::_("Plesk.panel_version.plesk", true, "8.4"), 'api_version' => "1.5.2.1", 'supported' => false),
'8.6' => array('name' => Language::_("Plesk.panel_version.plesk", true, "8.6"), 'api_version' => "1.5.2.1", 'supported' => false),
'9.0.0' => array('name' => Language::_("Plesk.panel_version.parallels", true, "9.0.0"), 'api_version' => "1.6.0.0", 'supported' => false),
'9.0.1' => array('name' => Language::_("Plesk.panel_version.parallels", true, "9.0.1"), 'api_version' => "1.6.0.1", 'supported' => false),
'9.0.2' => array('name' => Language::_("Plesk.panel_version.parallels", true, "9.0.2"), 'api_version' => "1.6.0.2", 'supported' => false),
'10.0' => array('name' => Language::_("Plesk.panel_version.parallels", true, "10.0"), 'api_version' => "1.6.3.0", 'supported' => true),
'10.1' => array('name' => Language::_("Plesk.panel_version.parallels", true, "10.1"), 'api_version' => "1.6.3.1", 'supported' => true),
'10.2' => array('name' => Language::_("Plesk.panel_version.parallels", true, "10.2"), 'api_version' => "1.6.3.2", 'supported' => true),
'10.3' => array('name' => Language::_("Plesk.panel_version.parallels", true, "10.3"), 'api_version' => "1.6.3.3", 'supported' => true),
'10.4' => array('name' => Language::_("Plesk.panel_version.parallels", true, "10.4"), 'api_version' => "1.6.3.4", 'supported' => true),
'11.0' => array('name' => Language::_("Plesk.panel_version.parallels", true, "11.0"), 'api_version' => "1.6.3.5", 'supported' => true),
'11.1.0' => array('name' => Language::_("Plesk.panel_version.parallels", true, "11.1.0"), 'api_version' => "1.6.4.0", 'supported' => true),
'11.5' => array('name' => Language::_("Plesk.panel_version.parallels", true, "11.5"), 'api_version' => "1.6.5.0", 'supported' => true),
);
$this->panel_versions = array_reverse($versions);
}
/**
* Retrieves the API version based on the panel version in use
*
* @param string $panel_version The version number of the panel
* @return string The API version to use for this panel
*/
private function getApiVersion($panel_version) {
return $this->panel_versions[$panel_version]['api_version'];
}
/**
* Retrieves Plesk panel versions that are supported by this module
*
* @param boolean $format True to format the versions as name/value pairs, false for the entire array
* @return array A list of supported versions
*/
private function getSupportedPanelVersions($format = false) {
$versions = array();
foreach ($this->panel_versions as $panel_version => $panel) {
if ($panel['supported']) {
if ($format)
$versions[$panel_version] = $panel['name'];
else
$versions[$panel_version] = $panel;
}
}
return $versions;
}
/**
* Returns the name of this module
*
* @return string The common name of this module
*/
public function getName() {
return Language::_("Plesk.name", true);
}
/**
* Returns the version of this module
*
* @return string The current version of this module
*/
public function getVersion() {
return self::$version;
}
/**
* Returns the name and URL for the authors of this module
*
* @return array A numerically indexed array that contains an array with key/value pairs for 'name' and 'url', representing the name and URL of the authors of this module
*/
public function getAuthors() {
return self::$authors;
}
/**
* Returns all tabs to display to an admin 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 getAdminTabs($package) {
return array(
'tabStats' => Language::_("Plesk.tab_stats", true)
);
}
/**
* 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(
'tabClientStats' => Language::_("Plesk.tab_client_stats", true)
);
}
/**
* Performs any necessary bootstraping actions. Sets Input errors on
* failure, preventing the module from being added.
*
* @return array A numerically indexed array of meta data 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 install() {
$errors = array();
// Ensure the the system meets the requirements for this module
if (!extension_loaded("simplexml"))
$errors['simplexml']['required'] = Language::_("Plesk.!error.simplexml_required", true);
if (!empty($errors)) {
$this->Input->setErrors($errors);
return;
}
}
/**
* 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) {
foreach ($service->fields as $field) {
if ($field->key == "plesk_domain")
return $field->value;
}
return null;
}
/**
* Returns a noun used to refer to a module row (e.g. "Server", "VPS", "Reseller Account", etc.)
*
* @return string The noun used to refer to a module row
*/
public function moduleRowName() {
return Language::_("Plesk.module_row", true);
}
/**
* Returns a noun used to refer to a module row in plural form (e.g. "Servers", "VPSs", "Reseller Accounts", etc.)
*
* @return string The noun used to refer to a module row in plural form
*/
public function moduleRowNamePlural() {
return Language::_("Plesk.module_row_plural", true);
}
/**
* Returns a noun used to refer to a module group (e.g. "Server Group", "Cloud", etc.)
*
* @return string The noun used to refer to a module group
*/
public function moduleGroupName() {
return Language::_("Plesk.module_group", true);
}
/**
* Returns the key used to identify the primary field from the set of module row meta fields.
* This value can be any of the 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 "server_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 service 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($packages, array $vars=null) {
if (isset($vars['plesk_domain']))
return $vars['plesk_domain'];
return null;
}
/**
* Checks whether the given webspace ID exists in Plesk
*
* @param int $webspace_id The subscription webspace ID to check
* @param stdClass $package An stdClass object representing the package
* @return boolean True if the webspace exists, false otherwise
*/
public function validateWebspaceExists($webspace_id, $package) {
// Get module row and API
$module_row = $this->getModuleRowByServer((isset($package->module_group) ? $package->module_group : 0), (isset($package->module_group) ? $package->module_group : ""));
$api = $this->getApi($module_row->meta->ip_address, $module_row->meta->username, $module_row->meta->password, $module_row->meta->port);
$api_version = $this->getApiVersion($module_row->meta->panel_version);
// Fetch the webspace/domain
try {
$subscription = $api->loadCommand("plesk_subscriptions", array($api_version));
$data = array('id' => $webspace_id);
$this->log($module_row->meta->ip_address . "|webspace:get", serialize($data), "input", true);
$response = $this->parseResponse($subscription->get($data), $module_row, true);
if ($response && $response->result->status == "ok")
return true;
}
catch (Exception $e) {
// API request failed
$this->Input->setErrors(array('api' => array('internal' => Language::_("Plesk.!error.api.internal", true))));
}
return false;
}
/**
* Checks whether the given plan ID exists in Plesk
*
* @param int $plan_id The service plan ID
* @param stdClass $package An stdClass object representing the package
* @param boolean $reseller True if the plan is a reseller plan, false for a hosting plan (optional, default false)
* @return boolean True if the plan exists, false otherwise
*/
public function validatePlanExists($plan_id, $package, $reseller=false) {
// Get module row and API
$module_row = $this->getModuleRowByServer((isset($package->module_group) ? $package->module_group : 0), (isset($package->module_group) ? $package->module_group : ""));
// Fetch the plans
$plans = $this->getPleskPlans($module_row, $reseller);
return (isset($plans[$plan_id]));
}
/**
* 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 editing the service, 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) {
// Set rules
$rules = array(
'plesk_domain' => array(
'format' => array(
'rule' => array(array($this, "validateHostName")),
'message' => Language::_("Plesk.!error.plesk_domain.format", true)
)
),
'plesk_username' => array(
'length' => array(
'if_set' => true,
'rule' => array("betweenLength", 1, 60),
'message' => Language::_("Plesk.!error.plesk_username.length", true)
)
),
'plesk_password' => array(
'length' => array(
'if_set' => true,
'rule' => array("betweenLength", 5, 14),
'message' => Language::_("Plesk.!error.plesk_password.length", true)
)
),
'plesk_confirm_password' => array(
'matches' => array(
'if_set' => true,
'rule' => array("compares", "==", (isset($vars['plesk_password']) ? $vars['plesk_password'] : "")),
'message' => Language::_("Plesk.!error.plesk_confirm_password.matches", true)
)
),
'plesk_webspace_id' => array(
'exists' => array(
'if_set' => true,
'rule' => array(array($this, "validateWebspaceExists"), $package),
'message' => Language::_("Plesk.!error.plesk_webspace_id.exists", true)
)
)
);
// Set the values that may be empty
$empty_values = array("plesk_username", "plesk_password", "plesk_confirm_password");
if (!$edit)
$empty_values[] = "plesk_webspace_id";
else {
// On edit, domain is optional
$rules['plesk_domain']['format']['if_set'] = true;
}
// Remove rules on empty fields
foreach ($empty_values as $value) {
// Confirm password must be given if password is too
if ($value == "plesk_confirm_password" && !empty($vars['plesk_password']))
continue;
if (empty($vars[$value]))
unset($rules[$value]);
}
$this->Input->setRules($rules);
return $this->Input->validates($vars);
}
/**
* 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") {
// Get module row and API
$module_row = $this->getModuleRow();
$api = $this->getApi($module_row->meta->ip_address, $module_row->meta->username, $module_row->meta->password, $module_row->meta->port);
$client_id = $vars['client_id'];
// If no username or password given, generate them
if (empty($vars['plesk_username']))
$vars['plesk_username'] = $this->generateUsername((isset($vars['plesk_domain']) ? $vars['plesk_domain'] : ""), $client_id);
if (empty($vars['plesk_password'])) {
$vars['plesk_password'] = $this->generatePassword();
$vars['plesk_confirm_password'] = $vars['plesk_password'];
}
$params = $this->getFieldsFromInput((array)$vars, $package);
$this->validateService($package, $vars);
if ($this->Input->errors())
return;
// Only provision the service if 'use_module' is true
if ($vars['use_module'] == "true") {
$api_version = $this->getApiVersion($module_row->meta->panel_version);
// Create a reseller account
if ($package->meta->type == "reseller") {
$response = $this->createResellerAccount($module_row, $package, $client_id, $params);
}
else {
// Create a user account
$response = $this->createCustomerAccount($module_row, $package, $client_id, $params);
}
if ($this->Input->errors())
return;
// Create the webspace/domain subscription service
try {
$subscription = $api->loadCommand("plesk_subscriptions", array($api_version));
$plan = array('id' => $package->meta->plan);
$data = array(
'general' => array(
'name' => $params['domain'],
'ip_address' => $module_row->meta->ip_address,
'owner_login' => $params['username'],
'htype' => "vrt_hst",
'status' => "0"
),
'hosting' => array(
'properties' => array(
'ftp_login' => $params['username'],
'ftp_password' => $params['password']
),
'ipv4' => $module_row->meta->ip_address
)
);
// Set the plan on the subscription only for non-resellers;
// The reseller has the plan associated with their account
if ($package->meta->type != "reseller")
$data['plan'] = $plan;
$masked_data = $data;
$masked_data['hosting']['properties']['ftp_password'] = "***";
$this->log($module_row->meta->ip_address . "|webspace:add", serialize($masked_data), "input", true);
$response = $this->parseResponse($subscription->add($data), $module_row);
// Set the webspace ID
if (property_exists($response->result, "id"))
$params['webspace_id'] = $response->result->id;
}
catch (Exception $e) {
// API request failed
$this->Input->setErrors(array('api' => array('internal' => Language::_("Plesk.!error.api.internal", true))));
return;
}
}
// Return service fields
return array(
array(
'key' => "plesk_domain",
'value' => $params['domain'],
'encrypted' => 0
),
array(
'key' => "plesk_username",
'value' => $params['username'],
'encrypted' => 0
),
array(
'key' => "plesk_password",
'value' => $params['password'],
'encrypted' => 1
),
array(
'key' => "plesk_webspace_id",
'value' => (isset($response) && property_exists($response->result, "id") ? $response->result->id : null),
'encrypted' => 0
)
);
}
/**
* 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=null, $parent_package=null, $parent_service=null) {
// Get module row and API
$module_row = $this->getModuleRow();
$api = $this->getApi($module_row->meta->ip_address, $module_row->meta->username, $module_row->meta->password, $module_row->meta->port);
$client_id = $service->client_id;
// If no username or password given, generate them
if (isset($vars['plesk_username']) && $vars['plesk_username'] == "")
$vars['plesk_username'] = $this->generateUsername((isset($vars['plesk_domain']) ? $vars['plesk_domain'] : ""), $client_id);
if (isset($vars['plesk_password']) && $vars['plesk_password'] == "") {
$vars['plesk_password'] = $this->generatePassword();
$vars['plesk_confirm_password'] = $vars['plesk_password'];
}
$params = $this->getFieldsFromInput((array)$vars, $package);
$this->validateService($package, $vars, true);
if ($this->Input->errors())
return;
// Get the service fields
$service_fields = $this->serviceFieldsToObject($service->fields);
// Only use the module to update the service if 'use_module' is true
if ($vars['use_module'] == "true") {
$api_version = $this->getApiVersion($module_row->meta->panel_version);
// Update the reseller account
if ($package->meta->type == "reseller") {
$response = $this->updateResellerAccount($module_row, $service_fields, $params);
}
else {
// Update the user account
$response = $this->updateCustomerAccount($module_row, $service_fields, $params);
}
if ($this->Input->errors())
return;
// Set updated fields
if ($response && $response->result->status == "ok") {
$service_fields->plesk_username = $params['username'];
$service_fields->plesk_password = $params['password'];
}
// Update the webspace/domain
try {
$subscription = $api->loadCommand("plesk_subscriptions", array($api_version));
// Set the information to update
$data = array(
'filter' => array(),
'general' => array('name' => $params['domain'])
);
// Identify the subscription to change by name (domain), subscription ID, or by the customer login user
if (!empty($service_fields->plesk_domain))
$data['filter']['name'] = $service_fields->plesk_domain;
elseif (!empty($service_fields->plesk_webspace_id))
$data['filter']['id'] = $service_fields->plesk_webspace_id;
elseif (!empty($service_fields->plesk_username))
$data['filter']['owner_login'] = $service_fields->plesk_username;
$this->log($module_row->meta->ip_address . "|webspace:set", serialize($data), "input", true);
$response = $this->parseResponse($subscription->set($data), $module_row);
// Set updated fields
if ($response && $response->result->status == "ok") {
$service_fields->plesk_domain = $params['domain'];
}
}
catch (Exception $e) {
// API request failed
$this->Input->setErrors(array('api' => array('internal' => Language::_("Plesk.!error.api.internal", true))));
}
if ($this->Input->errors())
return;
}
// Set fields to update locally
$fields = array("plesk_username", "plesk_password", "plesk_domain", "plesk_webspace_id");
foreach ($fields as $field) {
if (property_exists($service_fields, $field) && isset($vars[$field]))
$service_fields->{$field} = $vars[$field];
}
// Return all the service fields
$fields = array();
$encrypted_fields = array("plesk_password");
foreach ($service_fields as $key => $value)
$fields[] = array('key' => $key, 'value' => $value, 'encrypted' => (in_array($key, $encrypted_fields) ? 1 : 0));
return $fields;
}
/**
* 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 (($module_row = $this->getModuleRow())) {
$api = $this->getApi($module_row->meta->ip_address, $module_row->meta->username, $module_row->meta->password, $module_row->meta->port);
$api_version = $this->getApiVersion($module_row->meta->panel_version);
$service_fields = $this->serviceFieldsToObject($service->fields);
// Cancel (delete) the service (webspace subscription)
try {
$subscription = $api->loadCommand("plesk_subscriptions", array($api_version));
// Identify the subscription by name (domain) or by the subscription webspace ID
$data = array();
if (!empty($service_fields->plesk_domain))
$data['names'] = array($service_fields->plesk_domain);
elseif (!empty($service_fields->plesk_webspace_id))
$data['ids'] = array($service_fields->plesk_webspace_id);
// Some filter options must be set to avoid Plesk deleting everything
if (empty($data['names']) && empty($data['ids'])) {
$this->Input->setErrors(array('api' => array('filter-missing' => Language::_("Plesk.!error.api.webspace_delete_filter_missing", true))));
return;
}
$this->log($module_row->meta->ip_address . "|webspace:del", serialize($data), "input", true);
$response = $this->parseResponse($subscription->delete($data), $module_row);
}
catch (Exception $e) {
// API request failed
$this->Input->setErrors(array('api' => array('internal' => Language::_("Plesk.!error.api.internal", true))));
}
if ($this->Input->errors())
return;
// Delete the customer/reseller account
if ($package->meta->type == "reseller")
$this->deleteResellerAccount($module_row, $service_fields);
else
$this->deleteCustomerAccount($module_row, $service_fields);
}
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) {
// Suspend the subscription
$this->changeSubscriptionStatus($package, $service, $parent_package, $parent_service, true);
if ($this->Input->errors())
return;
// Suspend the customer/reseller account
$this->changeAccountStatus($package, $service, $parent_package, $parent_service, true);
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) {
// Unsuspend the subscription
$this->changeSubscriptionStatus($package, $service, $parent_package, $parent_service, false);
if ($this->Input->errors())
return;
// Unsuspends the customer/reseller account
$this->changeAccountStatus($package, $service, $parent_package, $parent_service, false);
return null;
}
/**
* Suspends or unsuspends a subscription. Sets Input errors on failure,
* preventing the service from being (un)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 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)
* @param $suspend True to suspend, false to unsuspend (optional, default true)
* @see Plesk::suspendService(), Plesk::unsuspendService()
*/
private function changeSubscriptionStatus($package, $service, $parent_package=null, $parent_service=null, $suspend=true) {
if (($module_row = $this->getModuleRow())) {
$api = $this->getApi($module_row->meta->ip_address, $module_row->meta->username, $module_row->meta->password, $module_row->meta->port);
$service_fields = $this->serviceFieldsToObject($service->fields);
$reseller = (isset($module_row->meta->reseller) && $module_row->meta->reseller == "true");
// Suspend/unsuspend the service (webspace subscription)
try {
$subscription = $api->loadCommand("plesk_subscriptions", array($this->getApiVersion($module_row->meta->panel_version)));
// Change the general information status
$data = array('filter' => array(), 'general' => array('status' => ($suspend ? ($reseller ? "32" : "16") : "0")));
// Identify the subscription to update by name (domain), subscription ID, or by the customer login user
if (!empty($service_fields->plesk_domain))
$data['filter']['name'] = $service_fields->plesk_domain;
elseif (!empty($service_fields->plesk_webspace_id))
$data['filter']['id'] = $service_fields->plesk_webspace_id;
elseif (!empty($service_fields->plesk_username))
$data['filter']['owner_login'] = $service_fields->plesk_username;
$this->log($module_row->meta->ip_address . "|webspace:set", serialize($data), "input", true);
$response = $this->parseResponse($subscription->set($data), $module_row);
}
catch (Exception $e) {
// API request failed
$this->Input->setErrors(array('api' => array('internal' => Language::_("Plesk.!error.api.internal", true))));
}
}
}
/**
* Suspends or unsuspends a customer. Sets Input errors on failure,
* preventing the service from being (un)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 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)
* @param $suspend True to suspend, false to unsuspend (optional, default true)
* @see Plesk::suspendService(), Plesk::unsuspendService()
*/
private function changeAccountStatus($package, $service, $parent_package=null, $parent_service=null, $suspend=true) {
if (($module_row = $this->getModuleRow())) {
$api = $this->getApi($module_row->meta->ip_address, $module_row->meta->username, $module_row->meta->password, $module_row->meta->port);
$service_fields = $this->serviceFieldsToObject($service->fields);
$reseller_account = (isset($module_row->meta->reseller) && $module_row->meta->reseller == "true");
// Suspend/unsuspend the account
try {
if ($package->meta->type == "reseller") {
// Update reseller account
$reseller = $api->loadCommand("plesk_reseller_accounts", array($this->getApiVersion($module_row->meta->panel_version)));
$data = array('filter' => array('login' => $service_fields->plesk_username), 'general' => array('status' => ($suspend ? ($reseller_account ? "32" : "16") : "0")));
$this->log($module_row->meta->ip_address . "|reseller:set", serialize($data), "input", true);
$response = $this->parseResponse($reseller->set($data), $module_row, true);
}
else {
// Update customer account
$customer = $api->loadCommand("plesk_customer_accounts", array($this->getApiVersion($module_row->meta->panel_version)));
$data = array('filter' => array('login' => $service_fields->plesk_username), 'general' => array('status' => ($suspend ? ($reseller_account ? "32" : "16") : "0")));
$this->log($module_row->meta->ip_address . "|customer:set", serialize($data), "input", true);
$response = $this->parseResponse($customer->set($data), $module_row, true);
}
}
catch (Exception $e) {
// API request failed
$this->Input->setErrors(array('api' => array('internal' => Language::_("Plesk.!error.api.internal", true))));
}
}
}
/**
* 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) {
// Nothing to do
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 (($module_row = $this->getModuleRow())) {
if (!isset($this->DataStructure))
Loader::loadHelpers($this, array("DataStructure"));
if (!isset($this->ArrayHelper))
$this->ArrayHelper = $this->DataStructure->create("Array");
$api = $this->getApi($module_row->meta->ip_address, $module_row->meta->username, $module_row->meta->password, $module_row->meta->port);
// Set the plan/type to update
$update_plan = array('reseller' => false, 'to_plan' => $package_to->meta->plan, 'from_plan' => $package_from->meta->plan);
// Set whether a reseller plan is being changed
$from_reseller_plan = (isset($package_from->meta->reseller_plan) ? $package_from->meta->reseller_plan : null);
$to_reseller_plan = (isset($package_to->meta->reseller_plan) ? $package_to->meta->reseller_plan : null);
// Reseller plan changed, upgrade the customer and set the reseller plan to update
if ($from_reseller_plan != $to_reseller_plan) {
// Changing reseller plans
$update_plan['reseller'] = true;
$update_plan['to_plan'] = $to_reseller_plan;
$update_plan['from_plan'] = $from_reseller_plan;
// Cannot downgrade from reseller account to customer account
if (!empty($from_reseller_plan) && empty($to_reseller_plan)) {
$this->Input->setErrors(array('downgrade' => array('unsupported' => Language::_("Plesk.!error.downgrade.unsupported", true))));
}
elseif (empty($from_reseller_plan) && !empty($to_reseller_plan)) {
// Upgrade the customer account to a reseller account
$this->upgradeCustomerToReseller($module_row, $service);
}
}
// Do not continue if there are errors
if ($this->Input->errors())
return;
// Only change a plan change if it has changed; a customer account plan or a reseller plan
if ($update_plan['from_plan'] != $update_plan['to_plan']) {
$service_fields = $this->serviceFieldsToObject($service->fields);
// Fetch all of the plans
$plans = $this->getPleskPlans($module_row, $update_plan['reseller'], false);
// Determine the plan's GUID based on the plan ID we currently have
$plans = $this->ArrayHelper->numericToKey($plans, "id", "guid");
$plan_guid = "";
if (isset($plans[$update_plan['to_plan']]))
$plan_guid = $plans[$update_plan['to_plan']];
$api_version = $this->getApiVersion($module_row->meta->panel_version);
// Switch reseller plan
if ($update_plan['reseller']) {
try {
// Change customer account subscription plan
$reseller = $api->loadCommand("plesk_reseller_accounts", array($api_version));
// Set the new plan to switch to using the plan's GUID
$data = array('filter' => array('login' => $service_fields->plesk_username), 'plan' => array('guid' => $plan_guid));
$this->log($module_row->meta->ip_address . "|reseller:switch-subscription", serialize($data), "input", true);
$response = $this->parseResponse($reseller->changePlan($data), $module_row);
}
catch (Exception $e) {
// API request failed
$this->Input->setErrors(array('api' => array('internal' => Language::_("Plesk.!error.api.internal", true))));
}
}
if ($this->Input->errors())
return;
// Also switch the subscription plan if it has changed
if ($package_from->meta->plan != $package_to->meta->plan) {
// Since the reseller plan was update, we also now need to fetch the subscription plans
if ($update_plan['reseller']) {
// Fetch subscription plans
$plans = $this->getPleskPlans($module_row, false, false);
// Determine the plan's GUID based on the plan ID we currently have
$plans = $this->ArrayHelper->numericToKey($plans, "id", "guid");
$plan_guid = "";
if (isset($plans[$update_plan['to_plan']]))
$plan_guid = $plans[$update_plan['to_plan']];
}
try {
// Change customer account subscription plan
$subscription = $api->loadCommand("plesk_subscriptions", array($api_version));
// Set the new plan to switch to using the plan's GUID
$data = array('filter' => array(), 'plan' => array('guid' => $plan_guid));
// Identify the subscription to update by name (domain), subscription ID, or by the customer login user
if (!empty($service_fields->plesk_domain))
$data['filter']['name'] = $service_fields->plesk_domain;
elseif (!empty($service_fields->plesk_webspace_id))
$data['filter']['id'] = $service_fields->plesk_webspace_id;
elseif (!empty($service_fields->plesk_username))
$data['filter']['owner_login'] = $service_fields->plesk_username;
$this->log($module_row->meta->ip_address . "|webspace:switch-subscription", serialize($data), "input", true);
$response = $this->parseResponse($subscription->changePlan($data), $module_row);
}
catch (Exception $e) {
// API request failed
$this->Input->setErrors(array('api' => array('internal' => Language::_("Plesk.!error.api.internal", true))));
}
}
}
}
// Nothing to do
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) {
// Set rules to validate input data
$this->Input->setRules($this->getPackageRules($vars));
// Build meta data to return
$meta = array();
if ($this->Input->validates($vars)) {
// Return all package meta fields
foreach ($vars['meta'] as $key => $value) {
$meta[] = array(
'key' => $key,
'value' => $value,
'encrypted' => 0
);
}
}
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) {
// Set rules to validate input data
$this->Input->setRules($this->getPackageRules($vars));
// Build meta data to return
$meta = array();
if ($this->Input->validates($vars)) {
// Return all package meta fields
foreach ($vars['meta'] as $key => $value) {
$meta[] = array(
'key' => $key,
'value' => $value,
'encrypted' => 0
);
}
}
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 manage 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 . "plesk" . 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 . "plesk" . DS);
// Load the helpers required for this view
Loader::loadHelpers($this, array("Form", "Html", "Widget"));
// Set default port
if (empty($vars))
$vars['port'] = "8443";
$this->view->set("vars", (object)$vars);
$this->view->set("panel_versions", $this->getSupportedPanelVersions(true));
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 . "plesk" . DS);
// Load the helpers required for this view
Loader::loadHelpers($this, array("Form", "Html", "Widget"));
if (empty($vars))
$vars = $module_row->meta;
$this->view->set("vars", (object)$vars);
$this->view->set("panel_versions", $this->getSupportedPanelVersions(true));
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) {
$meta_fields = array("server_name", "host_name", "ip_address", "port", "username", "password", "panel_version", "reseller");
$encrypted_fields = array("username", "password");
// Set checkbox value for whether this user is a reseller
$vars['reseller'] = (isset($vars['reseller']) && $vars['reseller'] == "true" ? "true" : "false");
$this->Input->setRules($this->getRowRules($vars));
// Validate module row
if ($this->Input->validates($vars)) {
// Build the meta data for this row
$meta = array();
foreach ($vars as $key => $value) {
if (in_array($key, $meta_fields)) {
$meta[] = array(
'key' => $key,
'value' => $value,
'encrypted' => in_array($key, $encrypted_fields) ? 1 : 0
);
}
}
return $meta;
}
}
/**
* 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) {
// Same as adding
return $this->addModuleRow($vars);
}
/**
* Deletes the module row on the remote server. Sets Input errors on failure,
* preventing the row from being deleted.
*
* @param stdClass $module_row The stdClass representation of the existing module row
*/
public function deleteModuleRow($module_row) {
// Nothing to do
return null;
}
/**
* Returns an array of available service delegation order methods. The module
* will determine how each method is defined. For example, the method "first"
* may be implemented such that it returns the module row with the least number
* of services assigned to it.
*
* @return array An array of order methods in key/value pairs where the key is the type to be stored for the group and value is the name for that option
* @see Module::selectModuleRow()
*/
public function getGroupOrderOptions() {
return array('first'=>Language::_("Plesk.order_options.first", true));
}
/**
* Determines which module row should be attempted when a service is provisioned
* for the given group based upon the order method set for that group.
*
* @return int The module row ID to attempt to add the service with
* @see Module::getGroupOrderOptions()
*/
public function selectModuleRow($module_group_id) {
if (!isset($this->ModuleManager))
Loader::loadModels($this, array("ModuleManager"));
$group = $this->ModuleManager->getGroup($module_group_id);
if ($group) {
switch ($group->add_order) {
default:
case "first":
foreach ($group->rows as $row) {
return $row->id;
}
break;
}
}
return 0;
}
/**
* 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, containing the fields to render as well as any additional HTML markup to include
*/
public function getPackageFields($vars=null) {
Loader::loadHelpers($this, array("Html"));
$fields = new ModuleFields();
$fields->setHtml("
<script type=\"text/javascript\">
$(document).ready(function() {
$('input[name=\"meta[type]\"]').change(function() {
fetchModuleOptions();
});
});
</script>
");
// Fetch all packages available for the given server or server group
$module_row = null;
if (isset($vars->module_group) && $vars->module_group == "") {
if (isset($vars->module_row) && $vars->module_row > 0) {
$module_row = $this->getModuleRow($vars->module_row);
}
else {
$rows = $this->getModuleRows();
if (isset($rows[0]))
$module_row = $rows[0];
unset($rows);
}
}
else {
// Fetch the 1st server from the list of servers in the selected group
$rows = $this->getModuleRows($vars->module_group);
if (isset($rows[0]))
$module_row = $rows[0];
unset($rows);
}
// Fetch plans
$plans = array('' => Language::_("Plesk.please_select", true));
if ($module_row) {
$plans += $this->getPleskPlans($module_row);
}
// Set the type of account (standard or reseller)
$type = $fields->label(Language::_("Plesk.package_fields.type", true), "plesk_type");
$type_standard = $fields->label(Language::_("Plesk.package_fields.type_standard", true), "plesk_type_standard");
$type_reseller = $fields->label(Language::_("Plesk.package_fields.type_reseller", true), "plesk_type_reseller");
$type->attach($fields->fieldRadio("meta[type]", "standard",
$this->Html->ifSet($vars->meta['type'], "standard") == "standard", array('id'=>"plesk_type_standard"), $type_standard));
$type->attach($fields->fieldRadio("meta[type]", "reseller",
$this->Html->ifSet($vars->meta['type']) == "reseller", array('id'=>"plesk_type_reseller"), $type_reseller));
$fields->setField($type);
// Set the Plesk plans as selectable options
$package = $fields->label(Language::_("Plesk.package_fields.plan", true), "plesk_plan");
$package->attach($fields->fieldSelect("meta[plan]", $plans,
$this->Html->ifSet($vars->meta['plan']), array('id'=>"plesk_plan")));
$fields->setField($package);
// Set the reseller account plan
if (isset($vars->meta['type']) && $vars->meta['type'] == "reseller") {
// Fetch the reseller plans
$reseller_plans = array('' => Language::_("Plesk.please_select", true));
$reseller_plans += $this->getPleskPlans($module_row, true);
// Set the Plesk reseller account plans as selectable options
$package = $fields->label(Language::_("Plesk.package_fields.reseller_plan", true), "plesk_reseller_plan");
$package->attach($fields->fieldSelect("meta[reseller_plan]", $reseller_plans,
$this->Html->ifSet($vars->meta['reseller_plan']), array('id'=>"plesk_reseller_plan")));
$fields->setField($package);
}
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("host_name", "ip_address", "port"),
'package' => array("type", "plan", "reseller_plan"),
'service' => array("plesk_domain", "plesk_username", "plesk_password", "plesk_webspace_id")
);
}
/**
* 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) {
Loader::loadHelpers($this, array("Html"));
$fields = new ModuleFields();
// Create domain label
$domain = $fields->label(Language::_("Plesk.service_field.domain", true), "plesk_domain");
// Create domain field and attach to domain label
$domain->attach($fields->fieldText("plesk_domain", $this->Html->ifSet($vars->plesk_domain), array('id'=>"plesk_domain")));
// Set the label as a field
$fields->setField($domain);
// Create username label
$username = $fields->label(Language::_("Plesk.service_field.username", true), "plesk_username");
// Create username field and attach to username label
$username->attach($fields->fieldText("plesk_username", $this->Html->ifSet($vars->plesk_username), array('id'=>"plesk_username")));
// Add tooltip
$tooltip = $fields->tooltip(Language::_("Plesk.service_field.tooltip.username", true));
$username->attach($tooltip);
// Set the label as a field
$fields->setField($username);
// Create password label
$password = $fields->label(Language::_("Plesk.service_field.password", true), "plesk_password");
// Create password field and attach to password label
$password->attach($fields->fieldPassword("plesk_password", array('id'=>"plesk_password", 'value'=>$this->Html->ifSet($vars->plesk_password))));
// Add tooltip
$tooltip = $fields->tooltip(Language::_("Plesk.service_field.tooltip.password", true));
$password->attach($tooltip);
// Set the label as a field
$fields->setField($password);
// Confirm password label
$confirm_password = $fields->label(Language::_("Plesk.service_field.confirm_password", true), "plesk_confirm_password");
// Create confirm password field and attach to password label
$confirm_password->attach($fields->fieldPassword("plesk_confirm_password", array('id'=>"plesk_confirm_password", 'value'=>$this->Html->ifSet($vars->plesk_password))));
// Add tooltip
$confirm_password->attach($tooltip);
// Set the label as a field
$fields->setField($confirm_password);
$webspace_id = $fields->label(Language::_("Plesk.service_field.webspace_id", true), "plesk_webspace_id");
// Create confirm password field and attach to password label
$webspace_id->attach($fields->fieldText("plesk_webspace_id", $this->Html->ifSet($vars->plesk_webspace_id), array('id'=>"plesk_webspace_id")));
// Add tooltip
$tooltip = $fields->tooltip(Language::_("Plesk.service_field.tooltip.webspace_id", true));
$webspace_id->attach($tooltip);
// Set the label as a field
$fields->setField($webspace_id);
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) {
Loader::loadHelpers($this, array("Html"));
$fields = new ModuleFields();
// Create domain label
$domain = $fields->label(Language::_("Plesk.service_field.domain", true), "plesk_domain");
// Create domain field and attach to domain label
$domain->attach($fields->fieldText("plesk_domain", $this->Html->ifSet($vars->plesk_domain, $this->Html->ifSet($vars->domain)), array('id'=>"plesk_domain")));
// Set the label as a field
$fields->setField($domain);
return $fields;
}
/**
* 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) {
Loader::loadHelpers($this, array("Html"));
$fields = new ModuleFields();
// Create domain label
$domain = $fields->label(Language::_("Plesk.service_field.domain", true), "plesk_domain");
// Create domain field and attach to domain label
$domain->attach($fields->fieldText("plesk_domain", $this->Html->ifSet($vars->plesk_domain), array('id'=>"plesk_domain")));
// Set the label as a field
$fields->setField($domain);
// Create username label
$username = $fields->label(Language::_("Plesk.service_field.username", true), "plesk_username");
// Create username field and attach to username label
$username->attach($fields->fieldText("plesk_username", $this->Html->ifSet($vars->plesk_username), array('id'=>"plesk_username")));
// Add tooltip
$tooltip = $fields->tooltip(Language::_("Plesk.service_field.tooltip.username", true));
$username->attach($tooltip);
// Set the label as a field
$fields->setField($username);
// Create password label
$password = $fields->label(Language::_("Plesk.service_field.password", true), "plesk_password");
// Create password field and attach to password label
$password->attach($fields->fieldPassword("plesk_password", array('id'=>"plesk_password", 'value'=>$this->Html->ifSet($vars->plesk_password))));
// Add tooltip
$tooltip = $fields->tooltip(Language::_("Plesk.service_field.tooltip.password", true));
$password->attach($tooltip);
// Set the label as a field
$fields->setField($password);
// Confirm password label
$confirm_password = $fields->label(Language::_("Plesk.service_field.confirm_password", true), "plesk_confirm_password");
// Create confirm password field and attach to password label
$confirm_password->attach($fields->fieldPassword("plesk_confirm_password", array('id'=>"plesk_confirm_password", 'value'=>$this->Html->ifSet($vars->plesk_password))));
// Add tooltip
$confirm_password->attach($tooltip);
// Set the label as a field
$fields->setField($confirm_password);
$webspace_id = $fields->label(Language::_("Plesk.service_field.webspace_id", true), "plesk_webspace_id");
// Create confirm password field and attach to password label
$webspace_id->attach($fields->fieldText("plesk_webspace_id", $this->Html->ifSet($vars->plesk_webspace_id), array('id'=>"plesk_webspace_id")));
// Add tooltip
$tooltip = $fields->tooltip(Language::_("Plesk.service_field.tooltip.webspace_id_edit", true));
$webspace_id->attach($tooltip);
// Set the label as a field
$fields->setField($webspace_id);
return $fields;
}
/**
* 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) {
$row = $this->getModuleRow();
// Load the view into this object, so helpers can be automatically added to the view
$this->view = new View("admin_service_info", "default");
$this->view->base_uri = $this->base_uri;
$this->view->setDefaultView("components" . DS . "modules" . DS . "plesk" . DS);
// Load the helpers required for this view
Loader::loadHelpers($this, array("Form", "Html"));
$this->view->set("module_row", $row);
$this->view->set("package", $package);
$this->view->set("service", $service);
$this->view->set("service_fields", $this->serviceFieldsToObject($service->fields));
return $this->view->fetch();
}
/**
* 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) {
$row = $this->getModuleRow();
// Load the view into this object, so helpers can be automatically added to the view
$this->view = new View("client_service_info", "default");
$this->view->base_uri = $this->base_uri;
$this->view->setDefaultView("components" . DS . "modules" . DS . "plesk" . DS);
// Load the helpers required for this view
Loader::loadHelpers($this, array("Form", "Html"));
$this->view->set("module_row", $row);
$this->view->set("package", $package);
$this->view->set("service", $service);
$this->view->set("service_fields", $this->serviceFieldsToObject($service->fields));
return $this->view->fetch();
}
/**
* Statistics 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 tabStats($package, $service, array $get=null, array $post=null, array $files=null) {
$this->view = new View("tab_stats", "default");
// Load the helpers required for this view
Loader::loadHelpers($this, array("Form", "Html"));
$stats = $this->getStats($package, $service);
$this->view->set("stats", $stats);
#$this->view->set("user_type", $package->meta->type);
$this->view->setDefaultView("components" . DS . "modules" . DS . "plesk" . DS);
return $this->view->fetch();
}
/**
* Client Statistics 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 tabClientStats($package, $service, array $get=null, array $post=null, array $files=null) {
$this->view = new View("tab_client_stats", "default");
// Load the helpers required for this view
Loader::loadHelpers($this, array("Form", "Html"));
$stats = $this->getStats($package, $service);
$this->view->set("stats", $stats);
#$this->view->set("user_type", $package->meta->type);
$this->view->setDefaultView("components" . DS . "modules" . DS . "plesk" . DS);
return $this->view->fetch();
}
/**
* Fetches all status for a given subscription service
*
* @param stdClass $package A stdClass object representing the current package
* @param stdClass $service A stdClass object representing the current service
* @return stdClass A stdClass object representing all of the stats for the account
*/
private function getStats($package, $service) {
$module_row = $this->getModuleRow();
$api = $this->getApi($module_row->meta->ip_address, $module_row->meta->username, $module_row->meta->password, $module_row->meta->port);
$service_fields = $this->serviceFieldsToObject($service->fields);
$stats = new stdClass();
$stats->account_info = array(
'domain' => $service_fields->plesk_domain,
'ip_address' => $module_row->meta->ip_address
);
$stats->disk_usage = array(
'used' => null,
'used_formatted' => null,
'limit' => null,
'limit_formatted' => null,
'unused' => null,
'unused_formatted' => Language::_("Plesk.stats.unlimited", true)
);
$stats->bandwidth_usage = array(
'used' => null,
'used_formatted' => null,
'limit' => null,
'limit_formatted' => null,
'unused' => null,
'unused_formatted' => Language::_("Plesk.stats.unlimited", true)
);
$response = false;
try {
$subscription = $api->loadCommand("plesk_subscriptions", array($this->getApiVersion($module_row->meta->panel_version)));
// Fetch these stats
$options = array("gen_info", "hosting", "limits", "stat", "prefs", "disk_usage",
"performance", "subscriptions", "permissions", "plan-items", "php-settings");
$data = array(
'id' => $service_fields->plesk_webspace_id,
'settings' => array()
);
// Set the stats we want to fetch
foreach ($options as $option) {
$data['settings'][$option] = true;
}
$this->log($module_row->meta->ip_address . "|webspace:get", serialize($data), "input", true);
$response = $this->parseResponse($subscription->get($data), $module_row);
}
catch (Exception $e) {
// API request failed
$this->Input->setErrors(array('api' => array('internal' => Language::_("Plesk.!error.api.internal", true))));
}
// Format the results for the stats we will display
if ($response && isset($response->result->data)) {
$data = $response->result->data;
// Set account info
$stats->account_info['domain'] = $data->gen_info->name;
$stats->account_info['ip_address'] = $data->gen_info->dns_ip_address;
// Fetch account limits
$totals = array();
foreach ($data->limits->limit as $item) {
$totals[$item->name] = $item->value;
}
// Set bandwidth usage
$stats->bandwidth_usage['used'] = $data->stat->traffic;
$stats->bandwidth_usage['limit'] = (isset($totals['max_traffic']) ? $totals['max_traffic'] : null);
// Set disk usage
$stats->disk_usage['limit'] = (isset($totals['disk_space']) ? $totals['disk_space'] : null);
$total_disk_usage = 0;
$disk_usage_options = array("httpdocs", "httpsdocs", "subdomains", "web_users", "anonftp", "logs", "dbases", "mailboxes",
"webapps", "maillists", "domaindumps", "configs", "chroot");
foreach ($disk_usage_options as $option) {
if (property_exists($data->disk_usage, $option))
$total_disk_usage += $data->disk_usage->{$option};
}
$stats->disk_usage['used'] = $total_disk_usage;
// Format the values
if ($stats->disk_usage['limit'] == "-1")
$stats->disk_usage['limit_formatted'] = Language::_("Plesk.stats.unlimited", true);
else {
$stats->disk_usage['limit_formatted'] = $this->convertBytesToString($stats->disk_usage['limit']);
// Set unused
$stats->disk_usage['unused'] = abs($stats->disk_usage['limit']-$stats->disk_usage['used']);
$stats->disk_usage['unused_formatted'] = $this->convertBytesToString($stats->disk_usage['unused']);
}
if ($stats->bandwidth_usage['limit'] == "-1")
$stats->bandwidth_usage['limit_formatted'] = Language::_("Plesk.stats.unlimited", true);
else {
$stats->bandwidth_usage['limit_formatted'] = $this->convertBytesToString($stats->bandwidth_usage['limit']);
// Set unused
$stats->bandwidth_usage['unused'] = abs($stats->bandwidth_usage['limit']-$stats->bandwidth_usage['used']);
$stats->bandwidth_usage['unused_formatted'] = $this->convertBytesToString($stats->bandwidth_usage['unused']);
}
$stats->disk_usage['used_formatted'] = $this->convertBytesToString($stats->disk_usage['used']);
$stats->bandwidth_usage['used_formatted'] = $this->convertBytesToString($stats->bandwidth_usage['used']);
}
return $stats;
}
/**
* Converts bytes to a string representation including the type
*
* @param int $bytes The number of bytes
* @return string A formatted amount including the type (B, KB, MB, GB)
*/
private function convertBytesToString($bytes) {
$step = 1024;
$unit = "B";
if (($value = number_format($bytes/($step*$step*$step), 2)) >= 1)
$unit = "GB";
elseif (($value = number_format($bytes/($step*$step), 2)) >= 1)
$unit = "MB";
elseif (($value = number_format($bytes/($step), 2)) >= 1)
$unit = "KB";
else
$value = $bytes;
return Language::_("Plesk.!bytes.value", true, $value, $unit);
}
/**
* Returns an array of service fields to set for the service using the given input
*
* @param array $vars An array of key/value input pairs
* @param stdClass $package A stdClass object representing the package for the service
* @return array An array of key/value pairs representing service fields
*/
private function getFieldsFromInput(array $vars, $package) {
$fields = array(
'domain' => isset($vars['plesk_domain']) ? $vars['plesk_domain'] : null,
'username' => isset($vars['plesk_username']) ? $vars['plesk_username']: null,
'password' => isset($vars['plesk_password']) ? $vars['plesk_password'] : null,
'webspace_id' => !empty($vars['plesk_webspace_id']) ? $vars['plesk_webspace_id'] : null
);
return $fields;
}
/**
* Retrieves the module row given the server or server group
*
* @param string $module_row The module row ID
* @param string $module_group The module group (optional, default "")
* @return mixed An stdClass object representing the module row, or null if it could not be determined
*/
private function getModuleRowByServer($module_row, $module_group = "") {
// Fetch the module row available for this package
$row = null;
if ($module_group == "") {
if ($module_row > 0) {
$row = $this->getModuleRow($module_row);
}
else {
$rows = $this->getModuleRows();
if (isset($rows[0]))
$row = $rows[0];
unset($rows);
}
}
else {
// Fetch the 1st server from the list of servers in the selected group
$rows = $this->getModuleRows($module_group);
if (isset($rows[0]))
$row = $rows[0];
unset($rows);
}
return $row;
}
/**
* Fetches a listing of all service plans configured in Plesk for the given server
*
* @param stdClass $module_row A stdClass object representing a single server
* @param boolean $reseller True to fetch reseller plans, false for user/hosting plans (optional, default false)
* @param boolean $format True to format the response as a key/value pair (id => name), false to fetch all data (optional, default true)
* @return array An array of packages in key/value pairs
*/
private function getPleskPlans($module_row, $reseller = false, $format = true) {
if (!isset($this->DataStructure))
Loader::loadHelpers($this, array("DataStructure"));
if (!isset($this->ArrayHelper))
$this->ArrayHelper = $this->DataStructure->create("Array");
$api = $this->getApi($module_row->meta->ip_address, $module_row->meta->username, $module_row->meta->password, $module_row->meta->port);
// Fetch the plans
try {
$api_version = $this->getApiVersion($module_row->meta->panel_version);
// Fetch reseller plans
if ($reseller) {
$service_plans = $api->loadCommand("plesk_reseller_plans", array($api_version));
// Fetch all reseller plans
$data = array('filter' => array('all' => true));
$this->log($module_row->meta->ip_address . "|reseller-plan:get", serialize($data), "input", true);
$response = $this->parseResponse($service_plans->get($data), $module_row);
}
else {
// Fetch user/hosting plans
$service_plans = $api->loadCommand("plesk_service_plans", array($api_version));
// Fetch all reseller plans
$data = array('filter' => array());
$this->log($module_row->meta->ip_address . "|service-plan:get", serialize($data), "input", true);
$response = $this->parseResponse($service_plans->get($data), $module_row);
}
// Response is only an array if there is more than 1 result returned
if (is_array($response->result)) {
$result = $response->result;
if ($format)
$result = $this->ArrayHelper->numericToKey($response->result, "id", "name");
}
else {
// Only 1 result
$result = array($response->result);
if ($format) {
$result = array();
if (property_exists($response->result, "id") && property_exists($response->result, "name"))
$result = array($response->result->id => $response->result->name);
}
}
return $result;
}
catch (Exception $e) {
// API request failed
$this->Input->setErrors(array('api' => array('internal' => Language::_("Plesk.!error.api.internal", true))));
}
return array();
}
/**
* Upgrades a customer account to a reseller account. Sets Input errors on failure
*
* @param stdClass $module_row An stdClass object representing a single server
* @param stdClass $service An stdClass object representing the service to upgrade
*/
private function upgradeCustomerToReseller($module_row, $service) {
$api = $this->getApi($module_row->meta->ip_address, $module_row->meta->username, $module_row->meta->password, $module_row->meta->port);
$service_fields = $this->serviceFieldsToObject($service->fields);
// Upgrade the account
try {
$customer = $api->loadCommand("plesk_customer_accounts", array($this->getApiVersion($module_row->meta->panel_version)));
// Upgrade this customer account
$data = array('filter' => array('login' => $service_fields->plesk_username));
$this->log($module_row->meta->ip_address . "|customer:convert-to-reseller", serialize($data), "input", true);
$response = $this->parseResponse($customer->upgrade($data), $module_row);
}
catch (Exception $e) {
// API request failed
$this->Input->setErrors(array('api' => array('internal' => Language::_("Plesk.!error.api.internal", true))));
}
}
/**
* Creates a reseller account. Sets Input errors on failure
*
* @param stdClass $module_row A stdClass object representing a single server
* @param stdClass $package A stdClass object representing the selected package
* @param int $client_id The ID of the client this customer account is being created on behalf of
* @param array $params A list of data to pass into the reseller account
* - username The account username
* - password The account password
* @return stdClass An stdClass object representing the response
*/
private function createResellerAccount($module_row, $package, $client_id, $params) {
// Fetch the client fields
$client_params = $this->getClientAccountFields($client_id);
$api = $this->getApi($module_row->meta->ip_address, $module_row->meta->username, $module_row->meta->password, $module_row->meta->port);
try {
$reseller = $api->loadCommand("plesk_reseller_accounts", array($this->getApiVersion($module_row->meta->panel_version)));
// Create the customer account
$data = array_merge($client_params, array('login' => $params['username'], 'password' => $params['password'], 'plan' => array('id' => $package->meta->reseller_plan)));
$masked_data = $data;
$masked_data['password'] = "***";
$this->log($module_row->meta->ip_address . "|reseller:add", serialize($masked_data), "input", true);
$response = $this->parseResponse($reseller->add($data), $module_row);
}
catch (Exception $e) {
// API request failed
$this->Input->setErrors(array('api' => array('internal' => Language::_("Plesk.!error.api.internal", true))));
}
return (isset($response) ? $response : new stdClass());
}
/**
* Updates a reseller account. Sets Input errors on failure
*
* @param stdClass $module_row A stdClass object representing a single server
* @param stdClass $service_fields An stdClass object representing the service fields
* @param array $params A list of data to pass into the reseller account
* - username The account username
* - password The account password
* @return stdClass An stdClass object representing the response
*/
private function updateResellerAccount($module_row, $service_fields, $params) {
$api = $this->getApi($module_row->meta->ip_address, $module_row->meta->username, $module_row->meta->password, $module_row->meta->port);
// Update the customer
try {
$reseller = $api->loadCommand("plesk_reseller_accounts", array($this->getApiVersion($module_row->meta->panel_version)));
// Set the information to update
$data = array(
// Update this user
'filter' => array('login' => $service_fields->plesk_username),
// with this information
'general' => array(
'login' => $params['username'],
'password' => $params['password']
)
);
// Mask sensitive data
$masked_data = $data;
$masked_data['general']['password'] = "***";
$this->log($module_row->meta->ip_address . "|reseller:set", serialize($masked_data), "input", true);
$response = $this->parseResponse($reseller->set($data), $module_row);
}
catch (Exception $e) {
// API request failed
$this->Input->setErrors(array('api' => array('internal' => Language::_("Plesk.!error.api.internal", true))));
}
return (isset($response) ? $response : new stdClass());
}
/**
* Deletes a reseller account. Sets Input errors on failure
*
* @param stdClass $module_row A stdClass object representing a single server
* @param stdClass $service_fields An stdClass object representing the service fields
* @return stdClass An stdClass object representing the response
*/
private function deleteResellerAccount($module_row, $service_fields) {
$api = $this->getApi($module_row->meta->ip_address, $module_row->meta->username, $module_row->meta->password, $module_row->meta->port);
// Delete the reseller account
try {
$reseller = $api->loadCommand("plesk_reseller_accounts", array($this->getApiVersion($module_row->meta->panel_version)));
// Delete the account
$data = array('filter' => array('login' => $service_fields->plesk_username));
// Some filter options must be set to avoid Plesk deleting everything
if (empty($data['filter']['login'])) {
$this->Input->setErrors(array('api' => array('filter-missing' => Language::_("Plesk.!error.api.reseller_delete_filter_missing", true))));
return;
}
$this->log($module_row->meta->ip_address . "|reseller:del", serialize($data), "input", true);
$response = $this->parseResponse($reseller->delete($data), $module_row);
}
catch (Exception $e) {
// API request failed
$this->Input->setErrors(array('api' => array('internal' => Language::_("Plesk.!error.api.internal", true))));
}
return (isset($response) ? $response : new stdClass());
}
/**
* Creates a customer account. Sets Input errors on failure
*
* @param stdClass $module_row A stdClass object representing a single server
* @param stdClass $package A stdClass object representing the selected package
* @param int $client_id The ID of the client this customer account is being created on behalf of
* @param array $params A list of data to pass into the customer account
* - username The account username
* - password The account password
* @return stdClass An stdClass object representing the response
*/
private function createCustomerAccount($module_row, $package, $client_id, $params) {
// Fetch the client fields
$client_params = $this->getClientAccountFields($client_id);
$api = $this->getApi($module_row->meta->ip_address, $module_row->meta->username, $module_row->meta->password, $module_row->meta->port);
try {
$customer_accounts = $api->loadCommand("plesk_customer_accounts", array($this->getApiVersion($module_row->meta->panel_version)));
// Create the customer account
$data = array_merge($client_params, array('login' => $params['username'], 'password' => $params['password']));
$masked_data = $data;
$masked_data['password'] = "***";
$this->log($module_row->meta->ip_address . "|customer:add", serialize($masked_data), "input", true);
$response = $this->parseResponse($customer_accounts->add($data), $module_row);
}
catch (Exception $e) {
// API request failed
$this->Input->setErrors(array('api' => array('internal' => Language::_("Plesk.!error.api.internal", true))));
}
return (isset($response) ? $response : new stdClass());
}
/**
* Updates a customer account. Sets Input errors on failure
*
* @param stdClass $module_row A stdClass object representing a single server
* @param stdClass $service_fields An stdClass object representing the service fields
* @param array $params A list of data to pass into the customer account
* - username The account username
* - password The account password
* @return stdClass An stdClass object representing the response
*/
private function updateCustomerAccount($module_row, $service_fields, $params) {
$api = $this->getApi($module_row->meta->ip_address, $module_row->meta->username, $module_row->meta->password, $module_row->meta->port);
// Update the customer
try {
$customer = $api->loadCommand("plesk_customer_accounts", array($this->getApiVersion($module_row->meta->panel_version)));
// Set the information to update
$data = array(
// Update this user
'filter' => array('login' => $service_fields->plesk_username),
// with this information
'general' => array(
'login' => $params['username'],
'password' => $params['password']
)
);
// Mask sensitive data
$masked_data = $data;
$masked_data['general']['password'] = "***";
$this->log($module_row->meta->ip_address . "|customer:set", serialize($masked_data), "input", true);
$response = $this->parseResponse($customer->set($data), $module_row);
}
catch (Exception $e) {
// API request failed
$this->Input->setErrors(array('api' => array('internal' => Language::_("Plesk.!error.api.internal", true))));
}
return (isset($response) ? $response : new stdClass());
}
/**
* Deletes a customer account. Sets Input errors on failure
*
* @param stdClass $module_row A stdClass object representing a single server
* @param stdClass $service_fields An stdClass object representing the service fields
* @return stdClass An stdClass object representing the response
*/
private function deleteCustomerAccount($module_row, $service_fields) {
$api = $this->getApi($module_row->meta->ip_address, $module_row->meta->username, $module_row->meta->password, $module_row->meta->port);
// Delete the customer account
try {
$customer_accounts = $api->loadCommand("plesk_customer_accounts", array($this->getApiVersion($module_row->meta->panel_version)));
// Delete the account
$data = array('filter' => array('login' => $service_fields->plesk_username));
// Some filter options must be set to avoid Plesk deleting everything
if (empty($data['filter']['login'])) {
$this->Input->setErrors(array('api' => array('filter-missing' => Language::_("Plesk.!error.api.reseller_delete_filter_missing", true))));
return;
}
$this->log($module_row->meta->ip_address . "|customer:del", serialize($data), "input", true);
$response = $this->parseResponse($customer_accounts->delete($data), $module_row);
}
catch (Exception $e) {
// API request failed
$this->Input->setErrors(array('api' => array('internal' => Language::_("Plesk.!error.api.internal", true))));
}
return (isset($response) ? $response : new stdClass());
}
/**
* Retrieves a list of fields for creating a customer/reseller account
*
* @param int $client_id The ID of the client whose fields to fetch
* @return array An array of client fields
* @see Plesk::createCustomerAccount(), Plesk::createResellerAccount()
*/
private function getClientAccountFields($client_id) {
// Fetch the client to set additional client fields
Loader::loadModels($this, array("Clients"));
$client_params = array();
if (($client = $this->Clients->get($client_id, false))) {
$country = (!empty($client->country) ? $client->country : null);
$client_params = array(
'name' => $client->first_name . " " . $client->last_name,
'email' => $client->email,
'company' => (!empty($client->company) ? $client->company : null),
'status' => "0",
'address' => (empty($client->address1) ? null : ($client->address1 . (!empty($client->address2) ? " " . $client->address2 : ""))),
'city' => (!empty($client->city) ? $client->city : null),
'state' => (!empty($client->state) && $country == "US" ? $client->state : null),
'country' => $country,
'zipcode' => (!empty($client->zip) && $country == "US" ? $client->zip : null)
);
}
return $client_params;
}
/**
* Parses the response from SolusVM into an stdClass object
*
* @param SolusvmResponse $response The response from the API
* @param string $xml_container_path The path to the XML container where the results reside
* @param stdClass $module_row A stdClass object representing a single server (optional, required when Module::getModuleRow() is unavailable)
* @param boolean $ignore_error Ignores any response error and returns the response anyway; useful when a response is expected to fail (e.g. check client exists) (optional, default false)
* @return stdClass A stdClass object representing the response, void if the response was an error
*/
private function parseResponse(PleskResponse $response, $module_row = null, $ignore_error = false) {
Loader::loadHelpers($this, array("Html"));
// Set the module row
if (!$module_row)
$module_row = $this->getModuleRow();
$success = false;
switch ($response->status()) {
case "ok":
$success = true;
break;
case "error":
$success = false;
// Ignore generating the error
if ($ignore_error)
break;
// Set errors
$errors = $response->errors();
$error = "";
if (isset($errors->errcode) && isset($errors->errtext))
$error = $errors->errcode . " " . $errors->errtext;
$this->Input->setErrors(array('api' => array('response' => $this->Html->safe($error))));
break;
default:
// Invalid response
$success = false;
// Ignore generating the error
if ($ignore_error)
break;
$this->Input->setErrors(array('api' => array('internal' => Language::_("Plesk.!error.api.internal", true))));
break;
}
// Replace sensitive fields
$masked_params = array();
$output = $response->response();
$raw_output = $response->raw();
foreach ($masked_params as $masked_param) {
if (property_exists($output, $masked_param))
$raw_output = preg_replace("/<" . $masked_param . ">(.*)<\/" . $masked_param . ">/", "<" . $masked_param . ">***</" . $masked_param . ">", $raw_output);
}
// Log the response
$this->log($module_row->meta->ip_address, $raw_output, "output", $success);
if (!$success && !$ignore_error)
return;
return $output;
}
/**
* Initializes the CpanelApi and returns an instance of that object with the given $host, $user, and $pass set
*
* @param string $host The host to the Plesk server
* @param string $user The user to connect as
* @param string $pass The password to authenticate with
* @param string $port The port on the host to connect on
* @return PleskApi The PleskApi instance
*/
private function getApi($host, $user, $pass, $port) {
Loader::load(dirname(__FILE__) . DS . "apis" . DS . "plesk_api.php");
return new PleskApi($user, $pass, $host, $port);
}
/**
* Generates a username based on the given domain
*
* @param string $domain The domain name
* @param int $client_id The ID of the client
* @return string The FTP login username
*/
private function generateUsername($domain, $client_id) {
// Remove everything except letters and numbers from the domain
// ensure no number appears in the beginning
$username = ltrim(preg_replace('/[^a-z0-9]/i', '', $domain), '0123456789');
$length = strlen($username);
$pool = "abcdefghijklmnopqrstuvwxyz0123456789";
$pool_size = strlen($pool);
if ($length < 5) {
for ($i=$length; $i<8; $i++) {
$username .= substr($pool, mt_rand(0, $pool_size-1), 1);
}
$length = strlen($username);
}
return (substr($username, 0, min($length, 8)) . $client_id);
}
/**
* Generates a password
*
* @param int $min_length The minimum character length for the password (5 or larger)
* @param int $max_length The maximum character length for the password (14 or fewer)
* @return string The generated password
*/
private function generatePassword($min_length=10, $max_length=14) {
$pool = "abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()";
$pool_size = strlen($pool);
$length = mt_rand(max($min_length, 5), min($max_length, 14));
$password = "";
for ($i=0; $i<$length; $i++) {
$password .= substr($pool, mt_rand(0, $pool_size-1), 1);
}
return $password;
}
/**
* Builds and returns the rules required to add/edit a module row (e.g. server)
*
* @param array $vars An array of key/value data pairs
* @return array An array of Input rules suitable for Input::setRules()
*/
private function getRowRules(&$vars) {
return array(
'server_name' => array(
'empty' => array(
'rule' => "isEmpty",
'negate' => true,
'message' => Language::_("Plesk.!error.server_name.empty", true)
)
),
'host_name' => array(
'valid' => array(
'rule' => array(array($this, "validateHostName")),
'message' => Language::_("Plesk.!error.host_name.valid", true)
)
),
'ip_address' => array(
'valid' => array(
'rule' => array(array($this, "validateIpAddress")),
'message' => Language::_("Plesk.!error.ip_address.valid", true)
)
),
'port' => array(
'format' => array(
'rule' => array("matches", "/^[0-9]+$/"),
'message' => Language::_("Plesk.!error.port.format", true)
)
),
'username' => array(
'empty' => array(
'rule' => "isEmpty",
'negate' => true,
'message' => Language::_("Plesk.!error.username.empty", true)
)
),
'password' => array(
'empty' => array(
'rule' => "isEmpty",
'negate' => true,
'message' => Language::_("Plesk.!error.password.empty", true)
)
),
'panel_version' => array(
'valid' => array(
'rule' => array(array($this, "validatePanelVersions")),
'message' => Language::_("Plesk.!error.panel_version.valid", true)
)
),
'reseller' => array(
'valid' => array(
'rule' => array("in_array", array("true", "false")),
'message' => Language::_("Plesk.!error.reseller.valid", true)
)
)
);
}
/**
* Builds and returns rules required to be validated when adding/editing a package
*
* @param array $vars An array of key/value data pairs
* @return array An array of Input rules suitable for Input::setRules()
*/
private function getPackageRules($vars) {
$rules = array(
'meta[type]' => array(
'valid' => array(
'rule' => array("matches", "/^(standard|reseller)$/"),
'message' => Language::_("Plesk.!error.meta[type].valid", true), // type must be standard or reseller
)
),
'meta[plan]' => array(
'empty' => array(
'rule' => "isEmpty",
'negate' => true,
'message' => Language::_("Plesk.!error.meta[plan].empty", true)
)
),
'meta[reseller_plan]' => array(
'empty' => array(
'if_set' => true,
'rule' => "isEmpty",
'negate' => true,
'message' => Language::_("Plesk.!error.meta[reseller_plan].empty", true)
)
)
);
return $rules;
}
/**
* Validates that the given hostname is valid
*
* @param string $host_name The host name to validate
* @return boolean True if the hostname is valid, false otherwise
*/
public function validateHostName($host_name) {
if (strlen($host_name) > 255)
return false;
return $this->Input->matches($host_name, "/^([a-z0-9]|[a-z0-9][a-z0-9\-]{0,61}[a-z0-9])(\.([a-z0-9]|[a-z0-9][a-z0-9\-]{0,61}[a-z0-9]))+$/");
}
/**
* Validates that the given ip address is valid
*
* @param string $ip_address The ip address to validate
* @return boolean True if the ip address is valid, false otherwise
*/
public function validateIpAddress($ip_address) {
$range = "(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])";
return $this->Input->matches($ip_address, "/^(?:" . $range . "\." . $range . "\." . $range . "\." . $range . ")$/");
}
/**
* Validates that the given panel version is valid
*
* @param string $version The version to validate
* @return boolean True if the version validates, false otherwise
*/
public function validatePanelVersions($version) {
return array_key_exists($version, $this->panel_versions);
}
}
?>
<?php
$this->Widget->clear();
$this->Widget->setLinkButtons(array());
$this->Widget->create($this->_("Plesk.add_row.box_title", true));
?>
<div class="inner">
<?php
$this->Form->create();
?>
<div class="title_row first">
<h3><?php $this->_("Plesk.add_row.basic_title");?></h3>
</div>
<div class="pad">
<ul>
<li>
<?php
$this->Form->label($this->_("Plesk.row_meta.server_name", true), "server_name");
$this->Form->fieldText("server_name", $this->Html->ifSet($vars->server_name), array('id' => "server_name"));
?>
</li>
<li>
<?php
$this->Form->label($this->_("Plesk.row_meta.ip_address", true), "ip_address");
$this->Form->fieldText("ip_address", $this->Html->ifSet($vars->ip_address), array('id' => "ip_address"));
?>
</li>
<li>
<?php
$this->Form->label($this->_("Plesk.row_meta.port", true), "port");
$this->Form->fieldText("port", $this->Html->ifSet($vars->port), array('id' => "port"));
?>
</li>
<li>
<?php
$this->Form->label($this->_("Plesk.row_meta.username", true), "username");
$this->Form->fieldText("username", $this->Html->ifSet($vars->username), array('id' => "username"));
?>
</li>
<li>
<?php
$this->Form->label($this->_("Plesk.row_meta.password", true), "password");
$this->Form->fieldPassword("password", array('id' => "password", 'value' => $this->Html->ifSet($vars->password)));
?>
</li>
<li>
<?php
$this->Form->fieldCheckbox("reseller", "true", ($this->Html->ifSet($vars->reseller) == "true"), array('id' => "reseller"));
$this->Form->label($this->_("Plesk.row_meta.reseller", true), "reseller", array('class' => "inline"));
?>
<span class="tooltip"><?php $this->_("AppController.tooltip.text");?><div><?php $this->_("Plesk.row_meta.tooltip.reseller");?></div></span>
</li>
<li>
<?php
$this->Form->label($this->_("Plesk.row_meta.panel_version", true), "panel_version");
$this->Form->fieldSelect("panel_version", $this->Html->ifSet($panel_versions), $this->Html->ifSet($vars->panel_version), array('id' => "panel_version"));
?>
</li>
</ul>
</div>
<div class="button_row">
<a class="btn_right submit" href="#"><?php $this->_("Plesk.add_row.add_btn");?></a>
</div>
<?php
$this->Form->end();
?>
</div>
<?php
$this->Widget->end();
?>
<table class="table">
<tr class="heading_row">
<td class="fixed_small center border_none"><span class="paymnt_arrow"></span></td>
<td class="border_left"><?php $this->_("Plesk.service_info.username");?></td>
<td><?php $this->_("Plesk.service_info.password");?></td>
<td class="last"><?php $this->_("Plesk.service_info.server");?></td>
<td class="last"><?php $this->_("Plesk.service_info.options");?></td>
</tr>
<tr>
<td></td>
<td><?php $this->Html->_($service_fields->plesk_username);?></td>
<td><?php $this->Html->_($service_fields->plesk_password);?></td>
<td><?php $this->Html->_($module_row->meta->host_name);?></td>
<td>
<?php
$this->Form->setCsrfOptions(array('set_on_create' => false));
$this->Form->create($this->Html->safe("https://" . $this->Html->ifSet($module_row->meta->host_name) . ":8443/login_up.php3"), array('target' => "_blank"));
$this->Form->fieldHidden("login_name", $this->Html->ifSet($service_fields->plesk_username));
$this->Form->fieldHidden("passwd", $this->Html->ifSet($service_fields->plesk_password));
?>
<a id="plesk_login<?php $this->Html->_($service->id);?>" href="#"><?php $this->_("Plesk.service_info.option_login");?></a>
<?php
$this->Form->end();
$this->Form->setCsrfOptions(array('set_on_create' => true));
?>
</td>
</tr>
</table>
<script type="text/javascript">
$(document).ready(function() {
$('#plesk_login<?php $this->Html->_($service->id);?>').click(function(e) {
e.preventDefault();
$(this).closest('form').submit();
});
});
</script>
<div class="table-responsive">
<table class="table table-curved table-striped">
<thead>
<tr>
<th><i class="fa fa-share fa-flip-vertical"></i></th>
<th><?php $this->_("Plesk.service_info.username");?></th>
<th><?php $this->_("Plesk.service_info.password");?></th>
<th><?php $this->_("Plesk.service_info.server");?></th>
<th><?php $this->_("Plesk.service_info.options");?></th>
</tr>
</thead>