siteBuilder.php 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200
  1. <?php
  2. /**
  3. * WHMCS siteBuilder Provisioning Module
  4. *
  5. * Provisioning User Accounts & manage Websites on the siteBuilder Server
  6. *
  7. * @see https://centos-webpanel.com/
  8. * @copyright Copyright (c) Thurdata GmbH 2022
  9. * @license GPL
  10. */
  11. use WHMCS\Database\Capsule;
  12. require_once 'Net/DNS2.php';
  13. require_once(__DIR__ . '/api/sitebuilder.php');
  14. require_once(__DIR__ . '/api/SiteProApiClient.php');
  15. if (!defined('WHMCS')) {
  16. die('This file cannot be accessed directly');
  17. }
  18. /**
  19. * Define siteBuilder product metadata parameters.
  20. *
  21. * @see https://developers.whmcs.com/provisioning-modules/meta-data-params/
  22. *
  23. * @return array
  24. */
  25. function siteBuilder_MetaData() {
  26. return array(
  27. 'DisplayName' => 'ThurData SiteBuilder Provisioning',
  28. 'DefaultSSLPort' => '2443',
  29. 'RequiresServer' => true
  30. );
  31. }
  32. /**
  33. * Create tables if neccessary
  34. * Define siteBuilder product configuration options.
  35. *
  36. * @see https://developers.whmcs.com/provisioning-modules/config-options/
  37. *
  38. * @return array
  39. */
  40. function siteBuilder_ConfigOptions() {
  41. // check for tables and create if neccessary
  42. siteBuilderCreateTables();
  43. // return ConfigOptions
  44. return ["BuilderURL" => [
  45. "FriendlyName" => "Builder URL", # Full Builder URL (prefix//hostname:port/)
  46. "Type" => "text", # Text Box
  47. "Size" => "25", # Defines the Field Width
  48. "Description" => "Full Builder URL (prefix//hostname:port/)",
  49. "Default" => "https://builder.thurdata.ch/",
  50. ],
  51. "HostingPlanID" => [
  52. "FriendlyName" => "Hosting Plan ID",
  53. "Type" => "text", # Text Box
  54. "Size" => "25", # Defines the Field Width
  55. "Description" => "Set the hostingPlan ID for this Product",
  56. "Default" => "Free",
  57. ],
  58. "Quota" => [
  59. "FriendlyName" => "Quota in MB",
  60. "Type" => "text", # Text Box
  61. "Size" => "25", # Defines the Field Width
  62. "Description" => "Set the Quoat matching Your HostingPlan (MB)",
  63. "Default" => "512",
  64. ],
  65. "BuilderIP" => [
  66. "FriendlyName" => "Builder Public IP",
  67. "Type" => "text", # Text Box
  68. "Size" => "25", # Defines the Field Width
  69. "Description" => "Set the public IP of the Webserver for DNS handling",
  70. "Default" => "185.163.51.234",
  71. ]
  72. ];
  73. }
  74. /**
  75. * Test connection to a siteBuilder server with the given server parameters.
  76. *
  77. * Allows an admin user to verify that an API connection can be
  78. * successfully made with the given configuration parameters for a
  79. * server.
  80. *
  81. * When defined in a module, a test connection button will appear
  82. * alongside the server type dropdown when adding or editing an
  83. * existing server.
  84. *
  85. * @param array $params common module parameters
  86. *
  87. * @see https://developers.whmcs.com/provisioning-modules/module-parameters/
  88. *
  89. * @return array
  90. */
  91. function siteBuilder_Testconnection($params) {
  92. $siteBuilder = new ApiClient(getSiteBuilderApiURL($params), $params['serveraccesshash']);
  93. // ping remota API
  94. $response = $siteBuilder->ping($params['serverusername'], $params['serverpassword']);
  95. if($response['response']['answer'] == 'pong') {
  96. return array(
  97. 'success' => true,
  98. 'error' => '',
  99. );
  100. }
  101. return array(
  102. 'success' => false,
  103. 'error' => $response,
  104. );
  105. }
  106. /**
  107. * Provision a new siteBuilder account
  108. *
  109. * Attempt to provision a new siteBuilder account. This is
  110. * called any time provisioning is requested inside of WHMCS. Depending upon the
  111. * configuration, this can be any of:
  112. * * When a new order is placed
  113. * * When an invoice for a new order is paid
  114. * * Upon manual request by an admin user
  115. *
  116. * @param array $params common module parameters
  117. *
  118. * @see https://developers.whmcs.com/provisioning-modules/supported-functions/
  119. *
  120. * @return string 'success' or an error message
  121. */
  122. function siteBuilder_CreateAccount($params) {
  123. $username = strtolower(substr($params['clientsdetails']['firstname'],0,2) . substr($params['clientsdetails']['lastname'],0,3)) . $params['serviceid'];
  124. $userdomain = $params['domain'];
  125. // update service
  126. try {
  127. Capsule::table('tblhosting')
  128. ->where('id', '=', $params['serviceid'])
  129. ->update(
  130. array(
  131. 'username' => $username,
  132. 'domain' => $userdomain,
  133. )
  134. );
  135. } catch (\Exception $e) {
  136. logModuleCall(
  137. 'siteBuilder',
  138. __FUNCTION__,
  139. $params,
  140. 'Error: could save username & domain in database',
  141. $e->getMessage()
  142. );
  143. return 'Error: could save username & password in database';
  144. }
  145. // add account to database
  146. try {
  147. Capsule::table('sitePro_acc')
  148. ->insert(
  149. array(
  150. 'account' => $username,
  151. 'pid' => $params['serviceid'],
  152. 'enabled' => true,
  153. )
  154. );
  155. } catch (\Exception $e) {
  156. logModuleCall(
  157. 'siteBuilder',
  158. __FUNCTION__,
  159. $params,
  160. 'Error: could save username & serviceid in database',
  161. $e->getMessage()
  162. );
  163. return 'Error: could save username & serviceid in database';
  164. }
  165. $siteBuilder = new ApiClient(getSiteBuilderApiURL($params), $params['serveraccesshash']);
  166. // create siteBuilder account
  167. $response = $siteBuilder->create($username, $params['domain'], $params['serverusername'], $params['serverpassword']);
  168. if($response['status'] != '200') {
  169. return 'Error: ' . $response['response']['error'];
  170. }
  171. // set quota for new account
  172. $response = $siteBuilder->setQuota($username, $params['configoption3'], $params['serverusername'], $params['serverpassword']);
  173. if($response['status'] != '200') {
  174. return 'Error: ' . $response['response']['error'];
  175. }
  176. /* enable this block to get a default domain website without hostname (otherwise the customer is able to do that)
  177. // create default domain site
  178. $response = $siteBuilder->init($username, $params['domain'], $params['serverusername'], $params['serverpassword']);
  179. if($response['status'] != '200') {
  180. return 'Error: ' . $response['response']['error'];
  181. }
  182. // add default site to database
  183. try {
  184. Capsule::table('sitePro_site')
  185. ->insert(
  186. array(
  187. 'relid' => $params['serviceid'],
  188. 'name' => $params['domain'],
  189. 'enabled' => true,
  190. )
  191. );
  192. } catch (\Exception $e) {
  193. logModuleCall(
  194. 'siteBuilder',
  195. __FUNCTION__,
  196. $params,
  197. 'Error: could save site & serviceid in database',
  198. $e->getMessage()
  199. );
  200. return 'Error: could save site & serviceid in database';
  201. }
  202. */
  203. return 'success';
  204. }
  205. /**
  206. * Removes a siteBuilder account and undeploy all related sites
  207. *
  208. * Called when a termination is requested. This can be invoked automatically for
  209. * overdue products if enabled, or requested manually by an admin user.
  210. *
  211. * @param array $params common module parameters
  212. *
  213. * @see https://developers.whmcs.com/provisioning-modules/supported-functions/
  214. *
  215. * @return string 'success' or an error message
  216. */
  217. function siteBuilder_TerminateAccount($params) {
  218. // check if account is suspended
  219. try {
  220. $active = Capsule::table('sitePro_acc')
  221. ->where('account',$params['username'])
  222. ->value('enabled');
  223. } catch (\Exception $e) {
  224. logModuleCall(
  225. 'siteBuilder',
  226. __FUNCTION__,
  227. $params,
  228. 'Error: could fetch account from database',
  229. $e->getMessage()
  230. );
  231. return 'Error: could fetch account from database';
  232. }
  233. if($active == true) {
  234. return 'Error: Account is active, please suspend account first';
  235. }
  236. // undeploy all related sites
  237. $sites = getSites($params['serviceid']);
  238. $siteBuilder = new ApiClient(getSiteBuilderApiURL($params), $params['serveraccesshash']);
  239. if(!empty($sites)) {
  240. foreach($sites as $site) {
  241. $response = $siteBuilder->undeploy($params['username'], $site, $params['serverusername'], $params['serverpassword']);
  242. if($response['status'] != '200') {
  243. return 'Error: ' . $response['response'];
  244. }
  245. // remove sitebuilder session
  246. $response = siteBuilderRemoveSession($params,$site);
  247. if($response != 'success') {
  248. return 'Error: ' . $response;
  249. }
  250. }
  251. }
  252. // cleanup database
  253. try {
  254. Capsule::table('sitePro_site')
  255. ->where('relid',$params['serviceid'])
  256. ->delete();
  257. } catch (\Exception $e) {
  258. logModuleCall(
  259. 'siteBuilder',
  260. __FUNCTION__,
  261. $params,
  262. 'Error: could remove site from database',
  263. $e->getMessage()
  264. );
  265. return 'Error: could remove site from database';
  266. }
  267. // terminate account
  268. $response = $siteBuilder->terminate($params['username'], $params['domain']);
  269. if($response['status'] != '200') {
  270. return 'Error: ' . $response['response']['error'];
  271. }
  272. try {
  273. Capsule::table('sitePro_acc')
  274. ->where('account',$params['username'])
  275. ->delete();
  276. } catch (\Exception $e) {
  277. logModuleCall(
  278. 'siteBuilder',
  279. __FUNCTION__,
  280. $params,
  281. 'Error: could remove account from database',
  282. $e->getMessage()
  283. );
  284. return 'Error: could remove account from database';
  285. }
  286. return 'success';
  287. }
  288. /**
  289. * Set a siteBuilder account to status inactive.
  290. *
  291. * Called when a suspension is requested. This is invoked automatically by WHMCS
  292. * when a product becomes overdue on payment or can be called manually by admin
  293. * user.
  294. *
  295. * @param array $params common module parameters
  296. *
  297. * @see https://developers.whmcs.com/provisioning-modules/supported-functions/
  298. *
  299. * @return string 'success' or an error message
  300. */
  301. function siteBuilder_SuspendAccount($params) {
  302. // set account to disabled in database
  303. try {
  304. Capsule::table('sitePro_acc')
  305. ->where('account',$params['username'])
  306. ->update(array(
  307. 'enabled' => false,
  308. ));
  309. } catch (\Exception $e) {
  310. logModuleCall(
  311. 'siteBuilder',
  312. __FUNCTION__,
  313. $params,
  314. 'Error: could not disable account in database',
  315. $e->getMessage()
  316. );
  317. return 'Error: could not disable account in database';
  318. }
  319. // disable all sites but not change status in DB for unsuspend restoring
  320. $sites = getSites($params['serviceid']);
  321. $siteBuilder = new ApiClient(getSiteBuilderApiURL($params), $params['serveraccesshash']);
  322. if(!empty($sites)) {
  323. foreach($sites as $site) {
  324. $response = $siteBuilder->disable($params['username'], $site, $params['serverusername'], $params['serverpassword']);
  325. if($response['status'] != '200') {
  326. return 'Error: ' . $response['response']['error'];
  327. }
  328. }
  329. }
  330. return 'success';
  331. }
  332. /**
  333. * Set a siteBuilder account to status active and enable active sites
  334. *
  335. * Called when an un-suspension is requested. This is invoked
  336. * automatically upon payment of an overdue invoice for a product, or
  337. * can be called manually by admin user.
  338. *
  339. * @param array $params common module parameters
  340. *
  341. * @see https://developers.whmcs.com/provisioning-modules/supported-functions/
  342. *
  343. * @return string 'success' or an error message
  344. */
  345. function siteBuilder_UnsuspendAccount($params) {
  346. // set account to enabled in database
  347. try {
  348. Capsule::table('sitePro_acc')
  349. ->where('account',$params['username'])
  350. ->update(array(
  351. 'enabled' => true,
  352. ));
  353. } catch (\Exception $e) {
  354. logModuleCall(
  355. 'siteBuilder',
  356. __FUNCTION__,
  357. $params,
  358. 'Error: could update account in database',
  359. $e->getMessage()
  360. );
  361. return 'Error: could update account in database';
  362. }
  363. // enable active sites
  364. $sites = getSitesEnabled($params['serviceid']);
  365. $siteBuilder = new ApiClient(getSiteBuilderApiURL($params), $params['serveraccesshash']);
  366. if(!empty($sites)) {
  367. foreach($sites as $site) {
  368. $response = $siteBuilder->enable($params['username'], $site, $params['serverusername'], $params['serverpassword']);
  369. if($response['status'] != '200') {
  370. return 'Error: ' . $response['response']['error'];
  371. }
  372. }
  373. }
  374. return 'success';
  375. }
  376. /**
  377. * Client area output logic handling.
  378. *
  379. * This function is used to define module specific client area output. It should
  380. * return an array consisting of a template file and optional additional
  381. * template variables to make available to that template.
  382. *
  383. * @param array $params common module parameters
  384. *
  385. * @see https://developers.whmcs.com/provisioning-modules/client-area-output/
  386. *
  387. * @return array
  388. */
  389. function siteBuilder_ClientArea($params) {
  390. $siteBuilder = new ApiClient(getSiteBuilderApiURL($params), $params['serveraccesshash']);
  391. $clientInfo = array('moduleclientarea' => '1');
  392. $clientInfo['domain'] = $params['domain'];
  393. // Client status
  394. $accEnabled = Capsule::table('sitePro_acc')
  395. ->where('pid', $params['serviceid'])
  396. ->value('enabled');
  397. $clientInfo['account'] = ['enabled' => $accEnabled];
  398. $clientInfo['sites'] = [];
  399. // Client sites
  400. $sites = getSites($params['serviceid']);
  401. foreach($sites as $site){
  402. $response = $siteBuilder->getSSLDays($params['username'], $site);
  403. if($response['status'] == '200') {
  404. $sslSite = $response['response']['ssl_remaining'];
  405. }
  406. $response = $siteBuilder->isenabled($params['username'], $site);
  407. if($response['status'] == '200') {
  408. $enabled = $response['response']['isenabled'];
  409. }
  410. array_push($clientInfo['sites'],['name' => $site, 'sslSite' => $sslSite, 'enabled' => $enabled]);
  411. }
  412. // Client Quota
  413. $response = $siteBuilder->getQuota($params['username']);
  414. if($response['status'] != '200') {
  415. logModuleCall(
  416. 'siteBuilder',
  417. __FUNCTION__,
  418. $params,
  419. 'Error getting Quota',
  420. $response
  421. );
  422. }
  423. $clientInfo['quota'] = round($response['response']['quota'][0]['blocks']/1024);
  424. $clientInfo['limit'] = round($response['response']['quota'][0]['hard']/1024);
  425. // return template vars
  426. return array(
  427. 'tabOverviewReplacementTemplate' => 'clientarea',
  428. 'vars' => $clientInfo,
  429. );
  430. }
  431. /**
  432. * Upgrade or downgrade a siteBuilder account by package.
  433. *
  434. * Called to apply any change in product assignment or parameters. It
  435. * is called to provision upgrade or downgrade orders, as well as being
  436. * able to be invoked manually by an admin user.
  437. *
  438. * This same function is called for upgrades and downgrades of both
  439. * products and configurable options.
  440. *
  441. * @param array $params common module parameters
  442. *
  443. * @see https://developers.whmcs.com/provisioning-modules/supported-functions/
  444. *
  445. * @return string "success" or an error message
  446. */
  447. function siteBuilder_ChangePackage($params) {
  448. $siteBuilder = new ApiClient(getSiteBuilderApiURL($params), $params['serveraccesshash']);
  449. // configoption3 contains quota in MB
  450. $response = $siteBuilder->setQuota($params['username'], $params['configoption3'], $params['serverusername'], $params['serverpassword']);
  451. if($response['status'] != '200') {
  452. return 'Error: ' . $response['response']['error'];
  453. }
  454. return 'success';
  455. }
  456. /**
  457. * Usage Update
  458. *
  459. * Important: Runs daily per server not per product
  460. * Run Manually: /admin/reports.php?report=disk_usage_summary&action=updatestats
  461. * @param array $params common module parameters
  462. *
  463. * @see https://developers.whmcs.com/provisioning-modules/usage-update/
  464. */
  465. function siteBuilder_UsageUpdate($params) {
  466. $siteBuilder = new ApiClient(getSiteBuilderApiURL($params), $params['serveraccesshash']);
  467. $response = $siteBuilder->getStats();
  468. if($response['status'] != '200') {
  469. logActivity('ERROR: Unable to update sitebuilder server usage: ' . implode('#',[$response]));
  470. }
  471. $stats = $response['response']['quota'];
  472. foreach($stats as $stat){
  473. try {
  474. Capsule::table('tblhosting')
  475. ->where('server', $params['serverid'])
  476. ->where('username', $stat['user'])
  477. ->update([
  478. 'diskusage' => $stat['used']/1024,
  479. 'disklimit' => $stat['hard']/1024,
  480. 'lastupdate' => Capsule::raw('now()'),
  481. ]);
  482. } catch (\Exception $e) {
  483. logActivity('ERROR: Unable to update sitebuilder server usage: ' . $e->getMessage());
  484. }
  485. }
  486. }
  487. /**
  488. * Additional actions a client user can invoke.
  489. *
  490. * Define additional actions a client user can perform for an instance of a
  491. * product/service.
  492. *
  493. * Any actions you define here will be automatically displayed in the available
  494. * list of actions within the client area.
  495. *
  496. * @return array
  497. */
  498. function siteBuilder_ClientAreaCustomButtonArray ($params) {
  499. return array(
  500. 'Neue Webseite' => 'newSite',
  501. );
  502. }
  503. /**
  504. * Additional actions a client user can invoke.
  505. *
  506. * Define additional actions a client user is allowed to perform for an instance of a
  507. * product/service.
  508. *
  509. * @see https://developers.whmcs.com/provisioning-modules/supported-functions/
  510. *
  511. * @return array
  512. */
  513. function siteBuilder_ClientAreaAllowedFunctions() {
  514. return array(
  515. 'Add Site' => 'addSite',
  516. 'New Site' => 'newSite',
  517. 'Confirm Delete Site' => 'delSiteConfirm',
  518. 'Delete Site' => 'delSite',
  519. 'Edit Site' => 'editSite',
  520. 'Conform Revert Site' => 'revSiteConfirm',
  521. 'Revert Site' => 'revSite',
  522. 'Disable Site' => 'disableSite',
  523. 'Enable Site' => 'enableSite'
  524. );
  525. }
  526. /**
  527. * Opens a form to add a new domain.
  528. *
  529. * @param array $params common module parameters
  530. *
  531. * @see https://developers.whmcs.com/provisioning-modules/supported-functions/
  532. *
  533. * @return array template information
  534. */
  535. function siteBuilder_newSite($params) {
  536. return array(
  537. 'breadcrumb' => array(
  538. 'clientarea.php?action=productdetails&id=' . $params['serviceid'] . '&modop=custom&a=newSite' => 'Neue Webseite',
  539. ),
  540. 'templatefile' => 'siteBuilder_new_site',
  541. );
  542. }
  543. /**
  544. * Adds a new domain to a siteBuilder account.
  545. *
  546. * @param array $params common module parameters
  547. *
  548. * @see https://developers.whmcs.com/provisioning-modules/supported-functions/
  549. *
  550. * @return string "success" or an error message
  551. */
  552. function siteBuilder_addSite($params) {
  553. if(empty($_POST['d'])) {
  554. $site = $params['domain'];
  555. } else {
  556. if(!filter_var($_POST['d'], FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME)){
  557. return 'Error: invalid site name';
  558. }
  559. $site = $_POST['d'] . '.' . $params['domain'];
  560. }
  561. // check OSI-8
  562. if(in_array($site,getSites($params['serviceid']))) {
  563. return 'Error: OSI-8 (Seite existiert bereits)';
  564. }
  565. // set DNS
  566. // disabled on dev, has to be already set in test env
  567. $response = siteBuildersetDNS($params, $site);
  568. if($response != 'success') {
  569. return $response;
  570. }
  571. //
  572. $siteBuilder = new ApiClient(getSiteBuilderApiURL($params), $params['serveraccesshash']);
  573. // set up webconfig
  574. $response = $siteBuilder->init($params['username'], $site, $params['serverusername'], $params['serverpassword']);
  575. if($response['status'] != '200') {
  576. return 'Error: ' . $response['response']['error'];
  577. }
  578. // update DB
  579. try {
  580. Capsule::table('sitePro_site')
  581. ->insert(
  582. array(
  583. 'relid' => $params['serviceid'],
  584. 'name' => $site,
  585. 'enabled' => true,
  586. )
  587. );
  588. } catch (\Exception $e) {
  589. logModuleCall(
  590. 'siteBuilder',
  591. __FUNCTION__,
  592. $params,
  593. 'Error: could save site & serviceid in database',
  594. $e->getMessage()
  595. );
  596. return 'Error: could save site & serviceid in database';
  597. }
  598. return 'success';
  599. }
  600. /**
  601. * Creates a sitePro editor session and redirect on success
  602. *
  603. * @param array $params common module parameters
  604. *
  605. * @see https://developers.whmcs.com/provisioning-modules/supported-functions/
  606. *
  607. * @return string "success" or an error message
  608. */
  609. function siteBuilder_editSite($params) {
  610. if(!filter_var($_POST['s'], FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME)){
  611. return 'Error: invalid site name';
  612. }
  613. $site = $_POST['s'];
  614. $api = new SiteProApiClient('https://builder.thurdata.ch/api/', 'apikey0', '993yVHwC05TLsx2JI2XFlAhkkPUxR6JbQUYbI.a5HiRtmNV9');
  615. // use this for enterprise licenses and change 'your-bulder-domain.com' to your builder domain
  616. //$api = new SiteProApiClient('http://your-bulder-domain.com/api/', 'your_api_username', 'your_api_password');
  617. try {
  618. // this call is used to open builder, so you need to set correct parameters to represent users website you want to open
  619. // this data usually comes from your user/hosting manager system
  620. $res = $api->remoteCall('requestLogin', array(
  621. 'type' => 'internal', // (required) 'internal'
  622. 'domain' => $site, // (required) domain of the user website you want to edit
  623. 'lang' => 'de', // (optional) 2-letter language code, set language code you whant builder to open in
  624. 'apiUrl' => getSiteBuilderApiURL($params) . 'deploy/' . $params['username'] . '/' . $site, // (required) API endpoint URL
  625. 'resellerClientAccountId' => $params['serviceid'], // (required) ID of website/user in your system
  626. 'username' => $params['serverusername'], // (optional) authorization username to be used with API endpoint
  627. 'password' => 'your-secure-password', // (optional) authorization password to be used with API endpoint
  628. 'hostingPlan' => $params['configoption2'],
  629. ));
  630. if (!$res || !is_object($res)) {
  631. logModuleCall(
  632. 'siteBuilder',
  633. __FUNCTION__,
  634. $params,
  635. 'Error: Response format error',
  636. $res
  637. );
  638. return 'Error: Response format error';
  639. } else if (isset($res->url) && $res->url) {
  640. /* logModuleCall(
  641. 'siteBuilder',
  642. __FUNCTION__,
  643. $params,
  644. 'Debug',
  645. $res
  646. ); */
  647. // on success redirect to builder URL
  648. header('Location: '.$res->url, true);
  649. exit();
  650. } else {
  651. logModuleCall(
  652. 'siteBuilder',
  653. __FUNCTION__,
  654. $params,
  655. 'Error: Unknown error',
  656. $res
  657. );
  658. return 'Error: Unknown error';
  659. }
  660. } catch (\Exception $e) {
  661. logModuleCall(
  662. 'siteBuilder',
  663. __FUNCTION__,
  664. $params,
  665. 'Error: Request error',
  666. $e->getMessage()
  667. );
  668. return 'Error: Request error';
  669. }
  670. return 'success';
  671. }
  672. /**
  673. * Opens a form to delete a domain from a siteBuilder account.
  674. *
  675. * @param array $params common module parameters
  676. *
  677. * @see https://developers.whmcs.com/provisioning-modules/supported-functions/
  678. *
  679. * @return array template information
  680. */
  681. function siteBuilder_delSiteConfirm() {
  682. return array(
  683. 'templatefile' => 'siteBuilder_del_site_confirm',
  684. 'vars' => array(
  685. 'delsite' => $_POST['s'],
  686. ),
  687. );
  688. }
  689. /**
  690. * Removes a site from a siteBuilder account.
  691. *
  692. * @param array $params common module parameters
  693. *
  694. * @see https://developers.whmcs.com/provisioning-modules/supported-functions/
  695. *
  696. * @return string "success" or an error message
  697. */
  698. function siteBuilder_delSite($params) {
  699. if(!filter_var($_POST['s'], FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME)){
  700. return 'Error: invalid domain name';
  701. }
  702. $site = $_POST['s'];
  703. $siteBuilder = new ApiClient(getSiteBuilderApiURL($params), $params['serveraccesshash']);
  704. // undeploy
  705. $response = $siteBuilder->undeploy($params['username'], $site, $params['serverusername'], $params['serverpassword']);
  706. if($response['status'] != '200') {
  707. return 'Error: ' . $response['response']['error'];
  708. }
  709. // update DB
  710. try {
  711. Capsule::table('sitePro_site')
  712. ->where('name', $site)
  713. ->delete();
  714. } catch (\Exception $e) {
  715. logModuleCall(
  716. 'siteBuilder',
  717. __FUNCTION__,
  718. $params,
  719. 'Error: could not remove site from database',
  720. $e->getMessage()
  721. );
  722. return 'Error: could not remove site from database';
  723. }
  724. // unset DNS
  725. // disabled on dev, has to be already set in test env
  726. $response = siteBuilderunsetDNS($params, $site);
  727. if($response != 'success') {
  728. return $response;
  729. }
  730. //
  731. $response = siteBuilderRemoveSession($params,$site);
  732. if($response != 'success') {
  733. return 'Error: ' . $response;
  734. }
  735. return 'success';
  736. }
  737. /**
  738. * Opens a form to re-init a website.
  739. *
  740. * @param array $params common module parameters
  741. *
  742. * @see https://developers.whmcs.com/provisioning-modules/supported-functions/
  743. *
  744. * @return array template information
  745. */
  746. function siteBuilder_revSiteConfirm($params) {
  747. return array(
  748. 'templatefile' => 'siteBuilder_rev_site_confirm',
  749. 'vars' => array(
  750. 'revSite' => $_POST['s'],
  751. ),
  752. );
  753. }
  754. /**
  755. * Revert all Changes (re-init) of the Site.
  756. *
  757. * @param array $params common module parameters
  758. *
  759. * @see https://developers.whmcs.com/provisioning-modules/supported-functions/
  760. *
  761. * @return string "success" or an error message
  762. */
  763. function siteBuilder_revSite($params) {
  764. if(!filter_var($_POST['s'], FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME)){
  765. return 'Error: invalid site name';
  766. }
  767. $site = $_POST['s'];
  768. $siteBuilder = new ApiClient(getSiteBuilderApiURL($params), $params['serveraccesshash']);
  769. // re-init site on webhost
  770. $response = $siteBuilder->revert($params['username'], $site, $params['serverusername'], $params['serverpassword']);
  771. if($response['status'] != '200') {
  772. return 'Error: ' . $response['response']['error'];
  773. }
  774. // remove builder session
  775. $api = new SiteProApiClient('https://builder.thurdata.ch/api/', 'apikey0', '993yVHwC05TLsx2JI2XFlAhkkPUxR6JbQUYbI.a5HiRtmNV9');
  776. try {
  777. // this call is used to open builder, so you need to set correct parameters to represent users website you want to open
  778. // this data usually comes from your user/hosting manager system
  779. $res = $api->remoteCall('requestLogin', array(
  780. 'type' => 'internal', // (required) 'internal'
  781. 'domain' => $site, // (required) domain of the user website you want to edit
  782. 'lang' => 'de', // (optional) 2-letter language code, set language code you whant builder to open in
  783. 'apiUrl' => getSiteBuilderApiURL($params) . 'deploy/' . $params['username'] . '/' . $site, // (required) API endpoint URL
  784. 'resellerClientAccountId' => $params['serviceid'], // (required) ID of website/user in your system
  785. 'username' => $params['serverusername'], // (optional) authorization username to be used with API endpoint
  786. 'password' => 'your-secure-password', // (optional) authorization password to be used with API endpoint
  787. ));
  788. if (!$res || !is_object($res)) {
  789. logModuleCall(
  790. 'siteBuilder',
  791. __FUNCTION__,
  792. $params,
  793. 'Error: Response format error',
  794. $res
  795. );
  796. return 'Error: Response format error';
  797. } else if (isset($res->url) && $res->url) {
  798. $result = $api->remoteCall('delete-site', array(
  799. 'domain' => $site
  800. ));
  801. if (!$result || !is_object($result)) {
  802. logModuleCall(
  803. 'siteBuilder',
  804. __FUNCTION__,
  805. $params,
  806. 'Error: Response format error',
  807. $result
  808. );
  809. return 'Error: Response format error';
  810. } else if (isset($result->ok) && $res->ok) {
  811. return 'success';
  812. }
  813. } else {
  814. logModuleCall(
  815. 'siteBuilder',
  816. __FUNCTION__,
  817. $params,
  818. 'Error: Unknown error',
  819. $res
  820. );
  821. return 'Error: Unknown error';
  822. }
  823. } catch (\Exception $e) {
  824. logModuleCall(
  825. 'siteBuilder',
  826. __FUNCTION__,
  827. $params,
  828. 'Error: Request error',
  829. $e->getMessage()
  830. );
  831. return 'Error: Request error';
  832. }
  833. return 'success';
  834. }
  835. /**
  836. * Enables a website.
  837. *
  838. * @param array $params common module parameters
  839. *
  840. * @see https://developers.whmcs.com/provisioning-modules/supported-functions/
  841. *
  842. * @return string "success" or an error message
  843. */
  844. function siteBuilder_enableSite($params) {
  845. if(!filter_var($_POST['s'], FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME)){
  846. return 'Error: invalid site name';
  847. }
  848. $site = $_POST['s'];
  849. $siteBuilder = new ApiClient(getSiteBuilderApiURL($params), $params['serveraccesshash']);
  850. // enable
  851. $response = $siteBuilder->enable($params['username'], $site, $params['serverusername'], $params['serverpassword']);
  852. if($response['status'] != '200') {
  853. return 'Error: ' . $response['response']['error'];
  854. }
  855. // update DB
  856. try {
  857. Capsule::table('sitePro_site')
  858. ->where('relid',$params['serviceid'])
  859. ->where('name',$site)
  860. ->update(array(
  861. 'enabled' => true,
  862. ));
  863. } catch (\Exception $e) {
  864. logModuleCall(
  865. 'siteBuilder',
  866. __FUNCTION__,
  867. $params,
  868. 'Error: could save site status in database',
  869. $e->getMessage()
  870. );
  871. return 'Error: could save site status in database';
  872. }
  873. return 'success';
  874. }
  875. /**
  876. * Disables a website.
  877. *
  878. * @param array $params common module parameters
  879. *
  880. * @see https://developers.whmcs.com/provisioning-modules/supported-functions/
  881. *
  882. * @return string "success" or an error message
  883. */
  884. function siteBuilder_disableSite($params) {
  885. if(!filter_var($_POST['s'], FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME)){
  886. return 'Error: invalid site name';
  887. }
  888. $site = $_POST['s'];
  889. $siteBuilder = new ApiClient(getSiteBuilderApiURL($params), $params['serveraccesshash']);
  890. // disable
  891. $response = $siteBuilder->disable($params['username'], $site, $params['serverusername'], $params['serverpassword']);
  892. if($response['status'] != '200') {
  893. return 'Error: ' . $response['response']['error'];
  894. }
  895. // update DB
  896. try {
  897. Capsule::table('sitePro_site')
  898. ->where('relid',$params['serviceid'])
  899. ->where('name',$site)
  900. ->update(array(
  901. 'enabled' => false,
  902. ));
  903. } catch (\Exception $e) {
  904. logModuleCall(
  905. 'siteBuilder',
  906. __FUNCTION__,
  907. $params,
  908. 'Error: could save site status in database',
  909. $e->getMessage()
  910. );
  911. return 'Error: could save site status in database';
  912. }
  913. return 'success';
  914. }
  915. // Helpers
  916. /**
  917. * Removes the sitePro builder session for a site
  918. *
  919. * @param array $params common module parameters
  920. * @see https://developers.whmcs.com/provisioning-modules/supported-functions/
  921. * @param string $site sitename
  922. *
  923. * @return string "success" or an error message
  924. */
  925. function siteBuilderRemoveSession($params, $site) {
  926. // remove builder session
  927. $api = new SiteProApiClient('https://builder.thurdata.ch/api/', 'apikey0', '993yVHwC05TLsx2JI2XFlAhkkPUxR6JbQUYbI.a5HiRtmNV9');
  928. try {
  929. // this call is used to open builder, so you need to set correct parameters to represent users website you want to open
  930. // this data usually comes from your user/hosting manager system
  931. $res = $api->remoteCall('requestLogin', array(
  932. 'type' => 'internal', // (required) 'internal'
  933. 'domain' => $site, // (required) domain of the user website you want to edit
  934. 'lang' => 'de', // (optional) 2-letter language code, set language code you whant builder to open in
  935. 'apiUrl' => getSiteBuilderApiURL($params) . 'deploy/' . $params['username'] . '/' . $site, // (required) API endpoint URL
  936. 'resellerClientAccountId' => $params['serviceid'], // (required) ID of website/user in your system
  937. 'username' => $params['serverusername'], // (optional) authorization username to be used with API endpoint
  938. 'password' => 'your-secure-password', // (optional) authorization password to be used with API endpoint
  939. ));
  940. if (!$res || !is_object($res)) {
  941. logModuleCall(
  942. 'siteBuilder',
  943. __FUNCTION__,
  944. $params,
  945. 'Error: Response format error',
  946. $res
  947. );
  948. return 'Error: Response format error';
  949. } else if (isset($res->url) && $res->url) {
  950. $result = $api->remoteCall('delete-site', array(
  951. 'domain' => $site
  952. ));
  953. if (!$result || !is_object($result)) {
  954. logModuleCall(
  955. 'siteBuilder',
  956. __FUNCTION__,
  957. $params,
  958. 'Error: Response format error',
  959. $result
  960. );
  961. return 'Error: Response format error';
  962. } else if (isset($result->ok) && $res->ok) {
  963. return 'success';
  964. }
  965. } else {
  966. logModuleCall(
  967. 'siteBuilder',
  968. __FUNCTION__,
  969. $params,
  970. 'Error: Unknown error',
  971. $res
  972. );
  973. return 'Error: Unknown error';
  974. }
  975. } catch (\Exception $e) {
  976. logModuleCall(
  977. 'siteBuilder',
  978. __FUNCTION__,
  979. $params,
  980. 'Error: Request error',
  981. $e->getMessage()
  982. );
  983. return 'Error: Request error';
  984. }
  985. return 'success';
  986. }
  987. /**
  988. * Update a DNS zone for a domain setting a new record for a domain or subdomain of a CWP7 account.
  989. *
  990. * @param array $params common module parameters
  991. *
  992. * @see https://developers.whmcs.com/provisioning-modules/supported-functions/
  993. *
  994. * @return string "success" or an error message
  995. */
  996. function siteBuildersetDNS($params, $site) {
  997. $siteName = $site . '.';
  998. $zoneRecords = array();
  999. $domainRecord = array(
  1000. 'line' => $siteName.'|A|0',
  1001. 'name' => $siteName,
  1002. 'type' => 'A',
  1003. 'class' => 'IN',
  1004. 'data' => array(
  1005. 'address' => $params['configoption4'],
  1006. ),
  1007. );
  1008. array_push($zoneRecords, $domainRecord);
  1009. $zoneIDcollection = Capsule::table('dns_manager2_zone')
  1010. ->select('id')
  1011. ->where('name', '=', $params['domain'])
  1012. ->where('clientid', '=', $params['userid'])
  1013. ->get();
  1014. $zoneIDobj = $zoneIDcollection[0];
  1015. $zoneID = $zoneIDobj->{'id'};
  1016. if(!isset($zoneID)) {
  1017. return 'Error: Zone for domain ' . $params['domain'] . ' or not owned by client';
  1018. }
  1019. $dnsZone = localAPI('dnsmanager', array( 'dnsaction' => 'getZone', 'zone_id' => $zoneID));
  1020. foreach($dnsZone['data']->records as $record) {
  1021. if(($record->name != $siteName) || ($record->type != 'A' && $record->type != 'CNAME')) {
  1022. array_push($zoneRecords, $record);
  1023. };
  1024. }
  1025. $result = localAPI('dnsmanager' ,
  1026. array(
  1027. 'dnsaction' => 'updateZone',
  1028. 'zone_id' => $zoneID,
  1029. 'records' => $zoneRecords,
  1030. )
  1031. );
  1032. if($result['result'] != 'success') {
  1033. return 'Error: ' . $result['message'];
  1034. }
  1035. return 'success';
  1036. }
  1037. /**
  1038. * Removing a DNS record for a site of a siteBuilder account.
  1039. *
  1040. * @param array $params common module parameters
  1041. *
  1042. * @see https://developers.whmcs.com/provisioning-modules/supported-functions/
  1043. *
  1044. * @return string "success" or an error message
  1045. */
  1046. function siteBuilderunsetDNS($params, $site) {
  1047. $siteName = $site . '.';
  1048. $zoneRecords = array();
  1049. $zoneIDcollection = Capsule::table('dns_manager2_zone')
  1050. ->select('id')
  1051. ->where('name', '=', $params['domain'])
  1052. ->where('clientid', '=', $params['userid'])
  1053. ->get();
  1054. $zoneIDobj = $zoneIDcollection[0];
  1055. $zoneID = $zoneIDobj->{'id'};
  1056. if(!isset($zoneID)) {
  1057. return 'Error: Zone for domain ' . $params['domain'] . ' or not owned by client';
  1058. }
  1059. $dnsZone = localAPI('dnsmanager', array( 'dnsaction' => 'getZone', 'zone_id' => $zoneID));
  1060. foreach($dnsZone['data']->records as $record) {
  1061. if(($record->name != $siteName) || ($record->type != 'A' && $record->type != 'CNAME')) {
  1062. array_push($zoneRecords, $record);
  1063. };
  1064. }
  1065. $result = localAPI('dnsmanager' ,
  1066. array(
  1067. 'dnsaction' => 'updateZone',
  1068. 'zone_id' => $zoneID,
  1069. 'records' => $zoneRecords,
  1070. )
  1071. );
  1072. if($result['result'] != 'success') {
  1073. return 'Error: ' . $result['message'];
  1074. }
  1075. return 'success';
  1076. }
  1077. /**
  1078. * Returns API Url .
  1079. *
  1080. * @param string $params common module parameters
  1081. *
  1082. * @see https://developers.whmcs.com/provisioning-modules/supported-functions/
  1083. *
  1084. * @return string $apiUrl
  1085. */
  1086. function getSiteBuilderApiURL($params) {
  1087. $httpPrefix = $params['serversecure'] ? 'https://' : 'http://';
  1088. $serverPort = $params['serverport'] ? ':' . $params['serverport'] . '/' : '/';
  1089. return $httpPrefix . $params['serverhostname'] . $serverPort;
  1090. }
  1091. /**
  1092. * Returns all sitenames of an account.
  1093. *
  1094. * @param string $params common module parameters
  1095. *
  1096. * @see https://developers.whmcs.com/provisioning-modules/supported-functions/
  1097. *
  1098. * @return array $sites array of sitenames
  1099. */
  1100. function getSites($serviceID) {
  1101. $sitesObj = Capsule::table('sitePro_site')
  1102. ->where('relid', $serviceID)
  1103. ->get();
  1104. $sites = [];
  1105. foreach($sitesObj as $site){
  1106. array_push($sites, $site->name);
  1107. }
  1108. return $sites;
  1109. }
  1110. /**
  1111. * Returns all names of enabled sites of an account.
  1112. *
  1113. * @param string $params common module parameters
  1114. *
  1115. * @see https://developers.whmcs.com/provisioning-modules/supported-functions/
  1116. *
  1117. * @return array $sites array of sitenames
  1118. */
  1119. function getSitesEnabled($serviceID) {
  1120. $sitesObj = Capsule::table('sitePro_site')
  1121. ->where('relid', $serviceID)
  1122. ->where('enabled', 1)
  1123. ->get();
  1124. $sites = [];
  1125. foreach($sitesObj as $site){
  1126. array_push($sites, $site->name);
  1127. }
  1128. return $sites;
  1129. }
  1130. /**
  1131. * Creates tables for account & site management if not exists
  1132. */
  1133. function siteBuilderCreateTables() {
  1134. // Create a new table.
  1135. if (!Capsule::schema()->hasTable('sitePro_acc')) {
  1136. try {
  1137. Capsule::schema()->create(
  1138. 'sitePro_acc',
  1139. function ($table) {
  1140. /** @var \Illuminate\Database\Schema\Blueprint $table */
  1141. $table->increments('id');
  1142. $table->string('account');
  1143. $table->integer('pid');
  1144. $table->boolean('enabled');
  1145. }
  1146. );
  1147. } catch (\Exception $e) {
  1148. echo "Unable to create sitePro_acc: {$e->getMessage()}";
  1149. }
  1150. }
  1151. if (!Capsule::schema()->hasTable('sitePro_site')) {
  1152. try {
  1153. Capsule::schema()->create(
  1154. 'sitePro_site',
  1155. function ($table) {
  1156. /** @var \Illuminate\Database\Schema\Blueprint $table */
  1157. $table->increments('id');
  1158. $table->integer('relid');
  1159. $table->string('name');
  1160. $table->boolean('enabled');
  1161. }
  1162. );
  1163. } catch (\Exception $e) {
  1164. echo "Unable to create sitePro_site: {$e->getMessage()}";
  1165. }
  1166. }
  1167. }