From 47e9a3544f6c2100aeb77f6163e96f1812c83b94 Mon Sep 17 00:00:00 2001 From: Rashad Jamara Date: Thu, 1 Jul 2021 12:57:43 +0200 Subject: [PATCH] feat(zipfile): added subdirs to the zipfile --- build/HISTORY.md | 21 + build/README.md | 66 +- .../widgets}/ispapi_monitoring.php | 28 +- gulpfile.json | 34 +- modules/widgets/ispapi_monitoring.php | 743 ++++++++++++++++++ package.json | 6 +- whmcs-ispapi-widget-monitoring-latest.zip | Bin 11190 -> 11422 bytes 7 files changed, 800 insertions(+), 98 deletions(-) rename build/{ => modules/widgets}/ispapi_monitoring.php (97%) create mode 100644 modules/widgets/ispapi_monitoring.php diff --git a/build/HISTORY.md b/build/HISTORY.md index 3f54ec5..117ce0f 100644 --- a/build/HISTORY.md +++ b/build/HISTORY.md @@ -1,3 +1,24 @@ +## [1.6.7](https://github.com/hexonet/whmcs-ispapi-widget-monitoring/compare/v1.6.6...v1.6.7) (2021-03-30) + + +### Bug Fixes + +* **getactivedomainswhmcs:** fixed issue with foreach args ([ccc2031](https://github.com/hexonet/whmcs-ispapi-widget-monitoring/commit/ccc2031f6ec3bea4589a72bb7e5e34927c9a9635)) + +## [1.6.6](https://github.com/hexonet/whmcs-ispapi-widget-monitoring/compare/v1.6.5...v1.6.6) (2021-03-09) + + +### Performance Improvements + +* **getactivedomainswhmcs:** to use toJson approach for array vs. object problem ([00c032d](https://github.com/hexonet/whmcs-ispapi-widget-monitoring/commit/00c032d31d393c918e69bb4104ad115cd5ec1b69)) + +## [1.6.5](https://github.com/hexonet/whmcs-ispapi-widget-monitoring/compare/v1.6.4...v1.6.5) (2021-01-20) + + +### Bug Fixes + +* **ci:** migration from Travis CI to github actions ([c131dc7](https://github.com/hexonet/whmcs-ispapi-widget-monitoring/commit/c131dc7a85a97b8c24723907a0bc37d94cfe603c)) + ## [1.6.4](https://github.com/hexonet/whmcs-ispapi-widget-monitoring/compare/v1.6.3...v1.6.4) (2021-01-07) diff --git a/build/README.md b/build/README.md index c7878b5..6f0c49a 100644 --- a/build/README.md +++ b/build/README.md @@ -7,78 +7,18 @@ This Repository covers the WHMCS "ISPAPI" Dashboard Widget "Monitoring". It provides the following features to WHMCS: -## Supported Features ## - -Monitoring of Domain Data Issues like - -* WHOIS Privacy Service -* Transfer Lock -* Premium Renewal Cost Price (WHMCS Bug 'til v7.8) -* Standard Domains that are Premium in real -* Cleanup comments that got added by our Migration & Consolidation Tool - -... and providing buttons to get the cases fixed. - -If there's something missing, let us know and we will extend. - -## Why this Widget ## - -This widget was planned as nice to have for different purposes to show data differences between the HEXONET API and WHMCS. Don't worry, we do not have such issues in general. Whenever changes happen on domain level outside of WHMCS you might run into trouble as booked additional domain services might not correctly get invoiced to your customers (worst case!). This might happen when using another Frontend to activate or deactivate Domain Add-Ons / Services. Some Registries (e.g. DK Hostmaster) even allow Registrants to maintain domains over a registry frontend and to perform different actions directly there. This is where WHMCS modules in general might run into corner cases - Imagine that 3 systems are there then involved: Registry, HEXONET, WHMCS. Whenever underlying processes are quite special, that's where it is getting hard with WHMCS at the end and this is where we are thinking that this Widget helps! -Another reason might be that our resellers need help getting domain data fixed as of a bug in older WHMCS Versions. - ## Resources ## -* [Release Notes](https://github.com/hexonet/whmcs-ispapi-widget-monitoring/releases) - -**If you have any issue related to this module, feel free to open an github issue or to contact our support team.** - -## Minimum Requirements ## - -Having Javascript activated in Browser. -For the latest WHMCS minimum system requirements, please refer to -[https://docs.whmcs.com/System_Requirements](https://docs.whmcs.com/System_Requirements) - -This Dashboard Widget is only compatible with the [ISPAPI registrar module](https://github.com/hexonet/whmcs-ispapi-registrar). Please install that provider module in version >= v4.4.5 first. - -## Usage Guide ## +Download the ZIP archive [here](https://github.com/hexonet/whmcs-ispapi-widget-monitoring/raw/master/whmcs-ispapi-widget-monitoring-latest.zip) and follow our Documentation. -### Installation / Upgrade ### +* [Documentation](https://centralnic-reseller.github.io/centralnic-reseller/docs/hexonet/whmcs/whmcs-ispapi-widget-monitoring/) -Download the ZIP archive including the latest release version [here](https://github.com/hexonet/whmcs-ispapi-widget-monitoring/raw/master/whmcs-ispapi-widget-monitoring-latest.zip). - -Extract the `ispapi_monitoring.php` into folder `/modules/widgets` of your WHMCS instance. - -### Using this Widget ### - -This is how it looks like in case everything is fine: -![allfine](https://user-images.githubusercontent.com/229425/94283804-c45bb600-ff51-11ea-9097-89e2067cd147.png) - -Otherwise cases are listed accordingly and providing a wizard to get them fixed: -![inactivetransferlock](https://user-images.githubusercontent.com/229425/94922353-5a479180-04ba-11eb-9813-434374318552.png) -![wpissues](https://user-images.githubusercontent.com/229425/94419760-7d550700-0183-11eb-88d6-a8eab5e38f94.png) - -Click on `Details!` to get more information: -![wizard1](https://user-images.githubusercontent.com/229425/94922460-8c58f380-04ba-11eb-9cf8-399d401bb971.png) - -By clicking on `Fix this!` the widget takes care of processing the items as described: -![wizard2](https://user-images.githubusercontent.com/229425/94922508-a72b6800-04ba-11eb-9e5a-08ca63a29988.png) -![wizard3](https://user-images.githubusercontent.com/229425/94922549-b7434780-04ba-11eb-9d31-3f36f50ac167.png) - -Furthermore you can download the affected items as CSV list for your reference before processing (without results) and after processing (including results). -NOTE: columns are separated by tab delimiter. - -**Note:** This can of course take a while in case a lot of domains have to be processed on API side. - -## Contributing ## - -Please read [our contributing guide](https://github.com/hexonet/whmcs-ispapi-widget-monitoring/blob/master/CONTRIBUTING.md) for details on our code of conduct, and the process for submitting pull requests to us. +**If you have any issue related to this module, feel free to open an github issue or to contact our support team.** ## Authors ## * **Kai Schwarz** - *development* - [PapaKai](https://github.com/papakai) -See also the list of [contributors](https://github.com/hexonet/whmcs-ispapi-widget-monitoring/graphs/contributors) who participated in this project. - ## License ## This project is licensed under the MIT License - see the [LICENSE](https://github.com/hexonet/whmcs-ispapi-widget-monitoring/blob/master/LICENSE) file for details. diff --git a/build/ispapi_monitoring.php b/build/modules/widgets/ispapi_monitoring.php similarity index 97% rename from build/ispapi_monitoring.php rename to build/modules/widgets/ispapi_monitoring.php index 823a8ed..c90eb18 100644 --- a/build/ispapi_monitoring.php +++ b/build/modules/widgets/ispapi_monitoring.php @@ -34,7 +34,7 @@ class IspapiMonitoringWidget extends \WHMCS\Module\AbstractWidget protected $cache = false; protected $cacheExpiry = 120; protected $requiredPermission = ''; - const VERSION = "1.6.4"; + const VERSION = "1.6.7"; /** * add generic parameters to domain list command and request to API @@ -114,18 +114,16 @@ private static function getActiveDomainsWHMCS() if (!is_null($tmp)) { return $tmp; } - $result = DB::table("tbldomains") + $result = json_decode(DB::table("tbldomains") ->select("id", "domain", "idprotection", "additionalnotes", "is_premium") ->where([ ["registrar", "=", "ispapi"], ["status", "=", "active"] ]) - ->get(); + ->get()->toJson(), true); $tmp = []; - foreach ($result as $row) { - if (is_object($row)) { - $tmp[$row->domain] = get_object_vars($row); - } else { + if (!empty($result)) { + foreach ($result as $row) { $tmp[$row["domain"]] = $row; } } @@ -430,9 +428,11 @@ private static function getDataWPAPICASE(&$data) $domainsWHMCS = self::getActiveDomainsWHMCS(); $items = []; $casesAPI = self::getIdProtectedDomainsAPI(); - foreach ($casesAPI as $c) { - if (isset($domainsWHMCS[$c]) && empty($domainsWHMCS[$c]["is_premium"]) /* null, 0, empty str */) { - $items[] = $c; + if (!empty($casesAPI)) { + foreach ($casesAPI as $c) { + if (isset($domainsWHMCS[$c]) && empty($domainsWHMCS[$c]["is_premium"]) /* null, 0, empty str */) { + $items[] = $c; + } } } if (!empty($items)) { @@ -451,9 +451,11 @@ private static function getDataTLAPICASE(&$data) $domainsWHMCS = self::getActiveDomainsWHMCS(); $items = []; $casesAPI = self::getTransferUnlockedDomainsAPI(); - foreach ($casesAPI as $c) { - if (isset($domainsWHMCS[$c])) { - $items[] = $c; + if (!empty($casesAPI)) { + foreach ($casesAPI as $c) { + if (isset($domainsWHMCS[$c])) { + $items[] = $c; + } } } if (!empty($items)) { diff --git a/gulpfile.json b/gulpfile.json index 22768d6..1f3e5d4 100644 --- a/gulpfile.json +++ b/gulpfile.json @@ -1,20 +1,16 @@ { - "phpcsparams": "--extensions=php --ignore=node_modules -q .", - "phpcsfixcmd": "phpcbf --standard=PSR12", - "phpcschkcmd": "phpcs -s -n --colors --standard=PSR12", - "phpcomptcmd": "phpcs -s -n --colors --standard=PHPCompatibility --runtime-set testVersion \"$(php -r 'echo PHP_MAJOR_VERSION . \".\" . PHP_MINOR_VERSION;')\"", - "archiveFileName": "whmcs-ispapi-widget-monitoring", - "archiveBuildPath": "build", - "filesForArchive": [ - "README.md", - "CONTRIBUTING.md", - "HISTORY.md", - "LICENSE", - "ispapi_monitoring.php" - ], - "filesForCleanup": [ - "composer.lock", - "package-lock.json", - "tmp" - ] -} \ No newline at end of file + "phpcsparams": "--extensions=php --ignore=node_modules -q .", + "phpcsfixcmd": "phpcbf --standard=PSR12", + "phpcschkcmd": "phpcs -s -n --colors --standard=PSR12", + "phpcomptcmd": "phpcs -s -n --colors --standard=PHPCompatibility --runtime-set testVersion \"$(php -r 'echo PHP_MAJOR_VERSION . \".\" . PHP_MINOR_VERSION;')\"", + "archiveFileName": "whmcs-ispapi-widget-monitoring", + "archiveBuildPath": "build", + "filesForArchive": [ + "README.md", + "CONTRIBUTING.md", + "HISTORY.md", + "LICENSE", + "modules/**" + ], + "filesForCleanup": ["composer.lock", "package-lock.json", "tmp"] +} diff --git a/modules/widgets/ispapi_monitoring.php b/modules/widgets/ispapi_monitoring.php new file mode 100644 index 0000000..c90eb18 --- /dev/null +++ b/modules/widgets/ispapi_monitoring.php @@ -0,0 +1,743 @@ + "SELF", + "UNIQUE" => 1, + "VERSION" => 2, + "NOTOTAL" => 1 + ])); + } + + /** + * get list of domains with active whois privacy service from HEXONET API + * @static + * @return array list of domains + */ + private static function getIdProtectedDomainsAPI() + { + $r = self::requestDomainListFromAPI([ + "COMMAND" => "QueryDomainList", + "X-ACCEPT-WHOISTRUSTEE-TAC" => 1 + ]); + if ($r["CODE"] !== "200" || !$r["PROPERTY"]["COUNT"][0]) { + return []; + } + return $r["PROPERTY"]["DOMAIN"]; + } + + /** + * get list of premium domains from HEXONET API + * @static + * @return array list of premium domains + */ + private static function getPremiumDomainsAPI() + { + $r = self::requestDomainListFromAPI([ + "COMMAND" => "QueryDomainList", + "SUBCLASSREGEX" => "^PREMIUM_.+$" + ]); + if ($r["CODE"] !== "200" || !$r["PROPERTY"]["COUNT"][0]) { + return []; + } + return $r["PROPERTY"]["OBJECTID"]; + } + + /** + * get list of domains with inactive whois privacy service from HEXONET API + * @static + * @return array list of domains + */ + private static function getTransferUnlockedDomainsAPI() + { + $r = self::requestDomainListFromAPI([ + "COMMAND" => "QueryDomainList", + "TRANSFERLOCK" => 0 + ]); + if ($r["CODE"] !== "200" || !$r["PROPERTY"]["COUNT"][0]) { + return []; + } + return $r["PROPERTY"]["DOMAIN"]; + } + + /** + * get list of domains with status active + * @static + * @return array list of domains + */ + private static function getActiveDomainsWHMCS() + { + static $tmp = null; + if (!is_null($tmp)) { + return $tmp; + } + $result = json_decode(DB::table("tbldomains") + ->select("id", "domain", "idprotection", "additionalnotes", "is_premium") + ->where([ + ["registrar", "=", "ispapi"], + ["status", "=", "active"] + ]) + ->get()->toJson(), true); + $tmp = []; + if (!empty($result)) { + foreach ($result as $row) { + $tmp[$row["domain"]] = $row; + } + } + return $tmp; + } + + /** + * return html code for ok case specified by given message + * @static + * @param String $msg success message to show + * @param String $prehtml HTML to add before the success message output + * @param String $afterhtml HTML to add after the success message output + * @return String html code + */ + private static function returnOk($msg, $prehtml, $afterhtml) + { + return << + {$prehtml} +
+
$msg
+
Check Result
+
+ {$afterhtml} + +EOF; + } + + /** + * get data per given issue case + * @static + * @param String $case case id + */ + private static function getCaseData($case, $count) + { + $singular = ($count === 1); + if ($case === "wpapicase") { + $label = "Domain" . ($singular ? "" : "s"); + return [ + "label" => "{$label} found with ID Protection Service active only on Registrar-side.", + "descr" => "We found {$count} {$label} with active ID Protection in HEXONET's System, but inactive in WHMCS. Therefore, your clients are using that service, but they are not getting invoiced for it by WHMCS.

Use the button "CSV" to download the list of affected items and use the below button "Fix this!" to disable that service for the listed domain names in HEXONET's System." + ]; + } + if ($case === "tlapicase") { + $label = "Domain" . ($singular ? "" : "s"); + return [ + "label" => "{$label} found with inactive transferlock.", + "descr" => "We found {$count} {$label} with inactive transferlock in HEXONET's System. Activating it avoids domains getting transferred way in ease. Transferlock is free of charge!

Use the button "CSV" to download the list of affected items and use the below button "Fix this!" to activate transferlock for the listed domain names." + ]; + } + if ($case === "migrationcase") { + $label = "Domain" . ($singular ? "" : "s"); + return [ + "label" => "{$label} found with migration process related additional notes.", + "descr" => "We found {$count} {$label} with migration process related additional notes. Our whmcs-based migration tool uses the additional notes field for processing that can be cleaned up for domains in status active. Usually you'll find additional notes set to INIT_TRANSFER_FAIL or INIT_TRANSFER_SUCCESS.

Use the button "CSV" to download the list of affected items and use the below button "Fix this!" to process the cleanup." + ]; + } + if ($case === "registrarrenewalcostpricezerocase") { + $label = "Premium Domain" . ($singular ? "" : "s"); + return [ + "label" => "{$label} found with missing Premium Renewal Cost Price in DB.", + "descr" => "We found {$count} {$label} with missing Premium Renewal Cost Price in DB. There had been a WHMCS Core Bug that got patched around WHMCS v7.8. It also affected our High-Performance Domainchecker Add-On's Premium Domain Handling." + ]; + } + if ($case === "domain2premiumcase") { + $label = "Standard Domain" . ($singular ? "" : "s"); + return [ + "label" => "{$label} found that " . ($singular ? "is a" : "are" ) . " Premium Domains in HEXONET's System.", + "descr" => "We found {$count} {$label} in WHMCS that " . ($singular ? "is a" : "are" ) . " Premium Domains in HEXONET's System. This may happen if domains were manually added in WHMCS or the respective registry did this change." + ]; + } + return [ + "label" => "", + "descr" => "" + ]; + } + + /** + * get html block of case + * @static + * @param String $case case id + * @param array $rows data rows of case + * @return String html code + */ + private static function getCaseBlock($case, $rows) + { + $count = count($rows); + $items = implode(", ", $rows); + $data = self::getCaseData($case, $count); + $label = $data["label"]; + $descr = $data["descr"]; + return << + + {$count} {$label} + +EOF; + } + + /** + * fix single item of case `wpapicase`: domain name with active whois privacy service in API but not in WHMCS + * @static + * @param String $item punycode domain name to fix + * @return array result + */ + private static function fixWPAPICASE($item) + { + $r = Ispapi::call([ + "COMMAND" => "ModifyDomain", + "DOMAIN" => $item, + "X-ACCEPT-WHOISTRUSTEE-TAC" => 0 + ]); + if ($r["CODE"] == "200") { + Ispapi::call([ + "COMMAND" => "StatusDomain", + "DOMAIN" => $item + ]); + } + return [ + "success" => $r["CODE"] === "200", + "msg" => $r["CODE"] . " " . $r["DESCRIPTION"], + "case" => "wpapicase", + "item" => $item + ]; + } + + /** + * fix single item of case `tlapicase`: domain name with inactive transferlock in API (WHMCS does not support transferlock yet) + * @static + * @param String $item punycode domain name to fix + * @return array result + */ + private static function fixTLAPICASE($item) + { + $r = Ispapi::call([ + "COMMAND" => "ModifyDomain", + "DOMAIN" => $item, + "TRANSFERLOCK" => 1 + ]); + if ($r["CODE"] == "200") { + Ispapi::call([ + "COMMAND" => "StatusDomain", + "DOMAIN" => $item + ]); + } + return [ + "success" => $r["CODE"] === "200", + "msg" => $r["CODE"] . " " . $r["DESCRIPTION"], + "case" => "tlapicase", + "item" => $item + ]; + } + + /** + * fix single item of case `migrationcase`: WHMCS domain name with status active and additional notes related to migration tool + * @static + * @param String $item punycode domain name to fix + * @return array result + */ + private static function fixMIGRATIONCASE($item) + { + $result = DB::table("tbldomains") + ->where([ + "registrar" => "ispapi", + "domain" => $item + ]) + ->update(["additionalnotes" => ""]); + $success = ($result > 0); + return [ + "success" => $success, + "msg" => ("Case " . (($success) ? "fixed" : "still open")), + "case" => "migrationcase", + "item" => $item + ]; + } + + /** + * fix single item of case `registrarrenewalcostpricezerocase`: premium domain name with missing registrarRenewalCost in tbldomains_extra + * @static + * @param String $item punycode domain name to fix + * @return array result + */ + private static function fixREGISTRARRENEWALCOSTPRICEZEROCASE($item) + { + $params = getregistrarconfigoptions("ispapi"); + $prices = ispapi_GetPremiumPrice(array_merge($params, ["domain" => $item])); + $domain = DB::table("tbldomains")->where([ + "registrar" => "ispapi", + "domain" => $item, + "status" => "Active", + "is_premium" => 1 + ])->first(); + $id = (is_object($domain)) ? $domain->id : $domain["id"]; + $success = false; + if (!empty($prices)) { + $extraDetails = \WHMCS\Domain\Extra::firstOrNew([ + "domain_id" => $id, + "name" => "registrarRenewalCostPrice" + ]); + $extraDetails->value = $prices["renew"]; + $success = $extraDetails->save(); + } + return [ + "success" => $success, + "msg" => ("Case " . (($success) ? "fixed" : "still open")), + "case" => "registrarrenewalcostpricezerocase", + "item" => $item + ]; + } + + /** + * fix single item of case `domain2premiumcase`: standard domain being premium in real + * @static + * @param String $item punycode domain name to fix + * @return array result + */ + private static function fixDOMAIN2PREMIUMCASE($item) + { + $query = [ + "registrar" => "ispapi", + "domain" => $item, + "status" => "Active", + "is_premium" => null + ]; + $domain = DB::table("tbldomains")->where($query)->first(); + $id = (is_object($domain)) ? $domain->id : $domain["id"]; + $success = false; + + $params = getregistrarconfigoptions("ispapi"); + $prices = ispapi_GetPremiumPrice(array_merge($params, ["domain" => $item])); + + if (!empty($prices)) { + $currency = \WHMCS\Billing\Currency::where("code", $prices["CurrencyCode"])->first(); + if (!$currency) { + return [ + "success" => false, + "msg" => ("Case " . (($success) ? "fixed" : "still open (Currency " . $prices["CurrencyCode"] . " not configured)")), + "case" => "domain2premiumcase", + "item" => $item + ]; + } + $extraDetails = \WHMCS\Domain\Extra::firstOrNew([ + "domain_id" => $id, + "name" => "registrarCurrency" + ]); + $extraDetails->value = $currency->id; + $success = $extraDetails->save(); + if ($success) { + $extraDetails = \WHMCS\Domain\Extra::firstOrNew([ + "domain_id" => $id, + "name" => "registrarCostPrice" + ]); + $extraDetails->value = isset($prices["register"]) ? $prices["register"] : $prices["renew"]; + $success = $extraDetails->save(); + + if ($success) { + $extraDetails = \WHMCS\Domain\Extra::firstOrNew([ + "domain_id" => $id, + "name" => "registrarRenewalCostPrice" + ]); + $extraDetails->value = $prices["renew"]; + $success = $extraDetails->save(); + } + } + } + if ($success) { + DB::table("tbldomains")->where($query)->update(["is_premium" => 1]); + } + return [ + "success" => $success, + "msg" => ("Case " . (($success) ? "fixed" : "still open")), + "case" => "domain2premiumcase", + "item" => $item + ]; + } + + /** + * fix given single item of given case + * @static + * @param String $case case id + * @param String $item object id like domain name + * @return array result e.g. [ "success" => true, "msg" => "200 Command completed successfully, "case" => "tlwhmcscase", "item" => "100works.com" ] + */ + private static function fixCase($case, $item) + { + if (is_callable([self::class, "fix" . strtoupper($case)], true, $fn)) { + return $fn($item); + } + return []; + } + + /** + * get data for case "wpapicase": all domain names with active whois privacy service in API but not in WHMCS + * @static + * @param array $data data container + * @return array updated data container + */ + private static function getDataWPAPICASE(&$data) + { + $domainsWHMCS = self::getActiveDomainsWHMCS(); + $items = []; + $casesAPI = self::getIdProtectedDomainsAPI(); + if (!empty($casesAPI)) { + foreach ($casesAPI as $c) { + if (isset($domainsWHMCS[$c]) && empty($domainsWHMCS[$c]["is_premium"]) /* null, 0, empty str */) { + $items[] = $c; + } + } + } + if (!empty($items)) { + $data["wpapicase"] = $items; + } + } + + /** + * get data for case "tlapicase": all domain names with inactive transferlock in API (WHMCS does not support transferlock yet) + * @static + * @param array $data data container + * @return array updated data container + */ + private static function getDataTLAPICASE(&$data) + { + $domainsWHMCS = self::getActiveDomainsWHMCS(); + $items = []; + $casesAPI = self::getTransferUnlockedDomainsAPI(); + if (!empty($casesAPI)) { + foreach ($casesAPI as $c) { + if (isset($domainsWHMCS[$c])) { + $items[] = $c; + } + } + } + if (!empty($items)) { + $data["tlapicase"] = $items; + } + } + + /** + * get data for case "migrationcase": all WHMCS domain names with status active and additional notes related to migration tool + * @static + * @param array $data data container + * @return array updated data container + */ + private static function getDataMIGRATIONCASE(&$data) + { + $domainsWHMCS = self::getActiveDomainsWHMCS(); + $items = []; + foreach ($domainsWHMCS as $c => $d) { + if (preg_match("/^INIT_TRANSFER_(SUCCESS|FAIL)$/i", $d["additionalnotes"])) { + $items[] = $c; + } + } + if (!empty($items)) { + $data["migrationcase"] = $items; + } + } + + /** + * get data for case "registrarrenewalcostpricezerocase": all premium domain names with missing registrarRenewalCost in tbldomains_extra + * @static + * @param array $data data container + * @return array updated data container + */ + private static function getDataREGISTRARRENEWALCOSTPRICEZEROCASE(&$data) + { + $domainsWHMCS = self::getActiveDomainsWHMCS(); + $items = []; + foreach ($domainsWHMCS as $c => $d) { + if ($d["is_premium"] === 1) { + $recurringamount = \WHMCS\Domain\Extra::whereDomainId($d["id"])->whereName("registrarRenewalCostPrice")->value("value"); + if (is_null($recurringamount)) { + $items[] = $c; + } + } + } + if (!empty($items)) { + $data["registrarrenewalcostpricezerocase"] = $items; + } + } + + /** + * get data for case "domain2premiumcase": standard domain being premium in real + * @static + * @param array $data data container + * @return array updated data container + */ + private static function getDataDOMAIN2PREMIUMCASE(&$data) + { + $domainsWHMCS = self::getActiveDomainsWHMCS(); + $casesAPI = self::getPremiumDomainsAPI(); + $items = []; + foreach ($casesAPI as $c) { + if (isset($domainsWHMCS[$c]) && empty($domainsWHMCS[$c]["is_premium"]) /* null, 0, empty str */) { + $items[] = $c; + } + } + if (!empty($items)) { + $data["domain2premiumcase"] = $items; + } + } + + /** + * Fetch data that will be provided to generateOutput method + * @return array|null data array or null in case of an error + */ + public function getData() + { + $data = []; + // --- case `wpapicase` + self::getDataWPAPICASE($data); + + // --- case `tlapicase` + self::getDataTLAPICASE($data); + + // --- case `migrationcase` + self::getDataMIGRATIONCASE($data); + + // --- case `registrarrenewalcostpricezerocase` + self::getDataREGISTRARRENEWALCOSTPRICEZEROCASE($data); + + // --- case `domain2premiumcase` + self::getDataDOMAIN2PREMIUMCASE($data); + + return $data; + } + + private static function generateOutputJS() + { + return << +const ispapidata = {} +const ispapiresults = {} + +function refreshMyWidget(widgetName, requestString, fcase, item) { + return new Promise(function (resolve) { + WHMCS.http.jqClient.post( + WHMCS.adminUtils.getAdminRouteUrl('/widget/refresh&widget=' + widgetName + '&' + requestString), + function (data) { + resolve(JSON.parse(data.widgetOutput)) + }, + 'json' + ).fail(function () { + resolve(getErrorResult(fcase, item)); + }) + }); +} + +function getErrorResult(fcase, item) { + return { + success: false, + case: fcase, + item: item, + msg: '421 An error occurred while communicating with the server. Please try again.' + } +} + +async function processItems(fcase, items) { + if (ispapidata.hasOwnProperty(fcase)) { + return + } + $('#monitModalSubmit').prop('disabled', true); + ispapidata[fcase] = items + const max = items.length + + // prepare html + $('#monitModalPgb').css('display', '') + let processed = 0; + const pgb = $('#monitModalPgb .progress-bar') + pgb.attr('aria-valuenow', 0) + pgb.css('width', '0%') + pgb.attr('aria-valuemax', ispapidata[fcase].length) + ispapiresults[fcase] = {}; + + while (ispapidata[fcase].length) { + let item = ispapidata[fcase].shift() + let data = await refreshMyWidget( + 'IspapiMonitoringWidget', + 'fixit=' + encodeURIComponent(fcase) + '&item=' + encodeURIComponent(item), + fcase, + item + ).catch((err) => { + data = getErrorResult(fcase, item) + }); + processed++ + let percentage = Math.round((100 / max) * processed) + ispapiresults[fcase][item] = data + pgb.attr('aria-valuenow', processed) + pgb.css('width', percentage + '%') + pgb.html(percentage + '%') + } + + if (ispapidata.hasOwnProperty(fcase)) { + delete ispapidata[fcase] + } + + const csvdata = []; + const keys = Object.keys(ispapiresults[fcase]); + keys.forEach(csvitem => { + const row = ispapiresults[fcase][csvitem] + csvdata.push([csvitem, (row.success ? 'OK' : 'ERROR'), row.msg].join('\\t')) + }) + delete ispapiresults[fcase] + $('#monitModalDownload').attr( + 'href', + 'data:application/csv;charset=utf-8,' + encodeURIComponent(csvdata.join('\\r\\n')) + ) + $('#monitModalDownload').removeClass('btn-primary').addClass('btn-success') +} +$('#monitModal').off().on('show.bs.modal', function (event) { + $('#monitModalPgb').css('display', 'none') + const button = $(event.relatedTarget) + const modal = $(this) + const itemsArr = button.data('items').split(', ') + modal.find('.modal-title').html(button.data('label')) + modal.find('.modal-body p.description').html(button.data('descr')) + $('#monitModalSubmit').off().click(function () { + processItems(button.data('case'), itemsArr) + }) + $('#monitModalDownload').attr( + 'href', + 'data:application/csv;charset=utf-8,' + encodeURIComponent(itemsArr.join('\\r\\n')) + ) +}) +$('#monitModal').on('hidden.bs.modal', function (event) { + refreshWidget('IspapiMonitoringWidget', 'refresh=1') +}) +$('#statusbtn').off().on('click', function (event) { + WHMCS.http.jqClient.post( + WHMCS.adminUtils.getAdminRouteUrl('/widget/refresh&widget=IspapiMonitoringWidget&status=' + encodeURIComponent($(this).attr("value"))), + function () { + refreshWidget('IspapiMonitoringWidget', 'refresh=1') + }, + 'json' + ) +}) + +EOF; + } + + /** + * generate widget's html output + * @param array $data input data (from getData method) + * @return string html code + */ + public function generateOutput($data) + { + $status = App::getFromRequest('status'); + if ($status !== "") { + $setting = \WHMCS\Config\Setting::setValue("ispapiMonitoringWidget", $status); + $success = $setting::getValue("ispapiMonitoringWidget") === $status; + return [ + "success" => $success, + "msg" => ("Widget status " . (($success) ? "changed" : "not changed")) + ]; + } + + $status = \WHMCS\Config\Setting::getValue("ispapiMonitoringWidget"); + $jscript = self::generateOutputJS(); + + if (empty($status)) { // null or 0 + return << + + +{$jscript} +EOF; + } + $output = ''; + $case = App::getFromRequest('fixit'); + $item = App::getFromRequest('item'); + if ($case && $item) { + return self::fixCase($case, $item); + } + if (empty($data)) { + return self::returnOk("No issues detected.", $output, $jscript); + } + $output .= "

"; + foreach ($data as $key => $rows) { + $output .= self::getCaseBlock($key, $rows); + } + + return <<{$output} + +{$jscript} +EOF; + } +} diff --git a/package.json b/package.json index 0fc8fd4..546bd42 100644 --- a/package.json +++ b/package.json @@ -41,13 +41,13 @@ "application" ], "devDependencies": { - "semantic-release": "^17.1.2", "@hexonet/semantic-release-github-whmcsbase-config": "^2.0.1", "gulp": "^4.0.2", "gulp-clean": "^0.4.0", - "gulp-tar": "^3.1.0", "gulp-gzip": "^1.4.2", - "gulp-zip": "^5.0.2" + "gulp-tar": "^3.1.0", + "gulp-zip": "^5.0.2", + "semantic-release": "^17.1.2" }, "scripts": { "phpCompatibility": "./scripts/phpcompatibility.sh", diff --git a/whmcs-ispapi-widget-monitoring-latest.zip b/whmcs-ispapi-widget-monitoring-latest.zip index 83be06f03f1e76fabc46dcf5a199de361e99dbb3..998f1708aac2b575c5510e29c67b880e8a47ed79 100644 GIT binary patch delta 402 zcmdlMJ};6tz?+#xgn@yBgCR5R;YQvfHfA8bxrwa-!eHf{!UPtX!@rxUo`GRX+QT3Q zB)|b==jNxB=A;(u!;E5J_==`V07+GOW=eW$2|_go!wjJ6i>6zAe~B|N{7PqFP{pD; zv$!C!U~`d>m;}f*le@L7!1M_%QxH8#+X&1x)i%Q6MwpZTI{FJCyO@#5o*CqQ>~2Qr rDn-(T@BvIWk{>jYJOR_bq;WA8?UTE;W%<|{*cnzZGB7;Q0x1RnrYd8W delta 173 zcmbOixhq-gScEh~`r$vWDmV1A0W5tyE-ZKQ%-FHk!e gENS!?VqlnjQAkuQz?+o~B*qGaDvS&aHCiAZ07b$op8x;=