Browse Source

new version 3.4.0

andre 4 years ago
parent
commit
cbc5177dde
89 changed files with 1706 additions and 275 deletions
  1. 12 0
      ProxmoxCloudVps.php
  2. 56 1
      app/Config/Packages/Provisioning.php
  3. 2 2
      app/Config/configuration.yml
  4. 20 0
      app/Config/cron.yml
  5. 5 0
      app/Helpers/ProxmoxAddonNotInstalledException.php
  6. 5 2
      app/Hooks/AdminAreaFooterOutput.php
  7. 5 3
      app/Http/Actions/ChangeUserRole.php
  8. 1 1
      app/Http/Actions/MetaData.php
  9. 14 4
      app/Http/Actions/ResetBandwidth.php
  10. 1 1
      app/Http/Admin/Product.php
  11. 100 1
      app/Http/Client/Console.php
  12. 24 6
      app/Http/Client/CustomTemplate.php
  13. 12 0
      app/UI/AccountSummary/Providers/AccountSummaryProvider.php
  14. 69 8
      app/UI/Admin/Product/Forms/VirtualizationChangeForm.php
  15. 30 0
      app/UI/Admin/Product/Sections/AlertSection.php
  16. 8 0
      app/UI/Admin/Product/Sections/BackupSection.php
  17. 10 0
      app/UI/Admin/Product/Sections/FirewallSection.php
  18. 25 0
      app/UI/Admin/Product/Sections/Lxc/ClientAreaSection.php
  19. 5 0
      app/UI/Admin/Product/Sections/Lxc/ConfigurableOptionUnitsSection.php
  20. 2 0
      app/UI/Admin/Product/Sections/Lxc/MountPointSection.php
  21. 5 0
      app/UI/Admin/Product/Sections/Lxc/ServerSection.php
  22. 10 1
      app/UI/Admin/Product/Sections/MainSection.php
  23. 25 0
      app/UI/Admin/Product/Sections/Qemu/AdditonalDisk.php
  24. 6 0
      app/UI/Admin/Product/Sections/Qemu/CloudInitSection.php
  25. 1 0
      app/UI/Admin/Product/Sections/Qemu/ConfigurableOptionUnitsSection.php
  26. 5 0
      app/UI/Admin/Product/Sections/Qemu/DefaultConfigurationSection.php
  27. 2 0
      app/UI/Admin/Product/Sections/Qemu/DiskSection.php
  28. 5 0
      app/UI/Admin/Product/Sections/Qemu/ServerSection.php
  29. 5 0
      app/UI/Admin/Product/Sections/TwiceColumnSection.php
  30. 0 6
      app/UI/Admin/User/Pages/UserDataTable.php
  31. 1 1
      app/UI/Backup/Forms/DeleteForm.php
  32. 37 5
      app/UI/Backup/Providers/BackupProvider.php
  33. 0 6
      app/UI/BackupJob/Buttons/CreateButton.php
  34. 0 6
      app/UI/BackupJob/Forms/DeleteForm.php
  35. 22 3
      app/UI/BackupJob/Modals/CreateModal.php
  36. 5 1
      app/UI/Client/Templates/assets/css/integration.css
  37. 45 2
      app/UI/Client/Templates/assets/img/buttons/backup.png
  38. 1 1
      app/UI/CustomTemplate/Buttons/CreateButton.php
  39. 0 17
      app/UI/Disk/Validators/DiskSizeValidator.php
  40. 47 0
      app/UI/Firewall/Buttons/DeleteButton.php
  41. 47 0
      app/UI/Firewall/Buttons/DownloadButton.php
  42. 22 0
      app/UI/Firewall/Buttons/EnableSwitchButton.php
  43. 50 0
      app/UI/Firewall/Buttons/UpRuleButton.php
  44. 60 0
      app/UI/Firewall/Buttons/UpdateRuleButton.php
  45. 20 0
      app/UI/Firewall/Forms/RuleForm.php
  46. 14 1
      app/UI/Firewall/Modals/UpdateGroupModal.php
  47. 23 0
      app/UI/Firewall/Providers/FirewallProvider.php
  48. 20 16
      app/UI/FirewallOption/Buttons/UpdateButton.php
  49. 1 1
      app/UI/FirewallOption/Modals/UpdateModal.php
  50. 7 0
      app/UI/FirewallOption/Providers/FirewallOptionProvider.php
  51. 9 0
      app/UI/MountPoint/Buttons/BackupSwitchButton.php
  52. 37 0
      app/UI/Resources/Pages/ResourcesContainer.php
  53. 39 0
      app/UI/Resources/Providers/BackupResourceProvider.php
  54. 5 0
      app/UI/Resources/Templates/pages/resourcesContainer.tpl
  55. 58 0
      app/UI/Resources/Templates/pages/resourcesContainer_components.js
  56. 39 0
      app/UI/Resources/Templates/pages/resourcesContainer_components.tpl
  57. 2 1
      app/UI/ServiceGraph/Pages/BaseGraph.php
  58. 2 0
      app/UI/Snapshot/Pages/SnapshotDataTable.php
  59. 1 0
      app/UI/Snapshot/Pages/SnapshotTrait.php
  60. 4 0
      app/UI/Snapshot/Providers/JobProvider.php
  61. 20 8
      app/UI/Snapshot/Providers/SnapshotProvider.php
  62. 46 5
      app/UI/VirtualInterface/Forms/CreateForm.php
  63. 2 0
      app/UI/VirtualNetwork/Buttons/CreateButton.php
  64. 5 1
      app/UI/Vm/Pages/DetailTab.php
  65. 55 0
      app/UI/Vm/Templates/pages/detailTab.tpl
  66. 8 1
      app/UI/VmCreate/Fields/IsoImageSelect.php
  67. 84 26
      app/UI/VmCreate/Fields/SecondaryIsoImageSelect.php
  68. 32 30
      app/UI/VmCreate/Sections/AccountSummary.php
  69. 14 25
      app/UI/VmCreate/Sections/Qemu/GeneralSection.php
  70. 0 2
      app/UI/VmCreate/Sections/TopSection.php
  71. 14 11
      app/UI/VmCreate/Sections/VirtualNetworkSection.php
  72. 31 0
      app/UI/VmCreate/Templates/sections/accountSummary.tpl
  73. 24 16
      app/UI/VmCreate/Validators/DiskSizeValidator.php
  74. 23 13
      app/UI/VmUpdate/Sections/Lxc/AdditionalDiskSection.php
  75. 4 8
      app/UI/VmUpdate/Sections/Qemu/AdditionalDiskSection.php
  76. 7 0
      app/UI/VmUpdate/Sections/VirtualNetworkSection.php
  77. 7 2
      app/UI/Vms/Modals/DeleteModal.php
  78. 3 0
      app/UI/Vms/Providers/DeleteVmProvider.php
  79. 1 1
      commands/commands.php
  80. 1 1
      core/App/Controllers/Instances/Addon/Deactivate.php
  81. 9 0
      core/UI/Widget/Forms/DataProviders/BaseModelDataProvider.php
  82. 171 18
      core/UI/Widget/Forms/Fields/Hidden.php
  83. 2 2
      logo.png
  84. 4 1
      packages/Provisioning/Config/PackageConfiguration.php
  85. 1 1
      templates/admin/assets/fonts/icons/Material-Design-Iconic-Font.eot
  86. 9 3
      templates/client/default/assets/css/mg_styles.css
  87. 3 1
      templates/client/default/assets/js/defaultComponents/ajaxFieldForDataTable.js
  88. 36 0
      templates/client/default/assets/js/defaultComponents/dataTableSelectFilter.js
  89. 2 2
      templates/client/default/ui/core/default/widget/forms/fields/hidden.tpl

+ 12 - 0
ProxmoxCloudVps.php

@@ -158,3 +158,15 @@ function ProxmoxCloudVps_ClientArea($params)
     return $appContext->runApp('clientarea', $params);
 }
 
+function ProxmoxCloudVps_GetLicenseData($force = false)
+{
+    $class  = '';
+
+    if(!class_exists($class ))
+    {
+        return [];
+    }
+    $class = '\\'.$class;
+
+    return $class::getLicenseData($force);
+}

+ 56 - 1
app/Config/Packages/Provisioning.php

@@ -3,11 +3,11 @@
 
 namespace ModulesGarden\Servers\ProxmoxCloudVps\App\Config\Packages;
 
+use MGProvision\Proxmox\v2\repository\StorageRepository;
 use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
 use ModulesGarden\ProxmoxAddon\App\Services\Cloud\ProductService;
 use ModulesGarden\ProxmoxAddon\App\Enum\Cloud\ConfigurableOption;
 use ModulesGarden\ProxmoxAddon\App\Enum\Cloud\CustomField;
-use ModulesGarden\Servers\ProxmoxCloudVps\App\Libs\AwsIntegration\ClientWrapper;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\Models\AvailableImages\Repository;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Admin\ProductConfig\Providers\Config;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\App\Packages\AppPackageConfiguration;
@@ -303,6 +303,61 @@ class WhmcsService extends AppPackageConfiguration
                 ]
             ]
         ];
+        //snapshotJobs
+        $configOptions[] = [
+            Enum::OPTION_NAME         =>  ConfigurableOption::SNAPSHOT_JOBS.'|Snapshot Jobs',
+            Enum::OPTION_TYPE         => Enum::OPTION_TYPE_QUANTITY,
+            Enum::OPTION_QUANTITY_MIN => 0,
+            Enum::OPTION_QUANTITY_MAX => 100,
+            Enum::CONFIG_SUB_OPTIONS  => [
+                [
+                    Enum::OPTION_SUB_NAME  => 'Unit|Unit',
+                    Enum::OPTION_SUB_ORDER => Enum::OPTION_SUB_ORDER_DEFAULT,
+                ]
+            ]
+        ];
+        //storage disk
+        $configOptions[] = [
+            Enum::OPTION_NAME => ConfigurableOption::STORAGE_DISK.'|Storage Disk Space',
+            Enum::OPTION_TYPE => Enum::OPTION_TYPE_DROPDOWN,
+        ];
+
+
         return $configOptions;
     }
+
+    public function storageDiskGetSubOptions()
+    {
+        $subOptions = [];
+        try
+        {
+            $subOptions[]               = [
+                Enum::OPTION_SUB_NAME  => '0|None',
+                Enum::OPTION_SUB_ORDER => Enum::OPTION_SUB_ORDER_DEFAULT,
+            ];
+            $unit = strtoupper($this->configuration()->getStorageUnit());
+            //node
+            $node = $this->getDefaultNode();
+            //storages
+            $storageRepository = new StorageRepository();
+            $storageRepository->findByNodes([$node->getNode()])
+                ->findEnabed();
+            $sizes =[100,200,300,400,500];
+            foreach ($storageRepository->fetch() as $storage)
+            {
+                foreach ($sizes as $size){
+                    $subOptions[] = [
+                        Enum::OPTION_SUB_NAME  => sprintf("%s:%s|%s %s %s",$storage->getStorage(), $size,$storage->getStorage(),$size, $unit),
+                        Enum::OPTION_SUB_ORDER => Enum::OPTION_SUB_ORDER_DEFAULT,
+                    ];
+                }
+            }
+            return $subOptions;
+        }
+        catch (ProxmoxApiException $ex)
+        {
+            return $subOptions;
+        }
+
+    }
 }

+ 2 - 2
app/Config/configuration.yml

@@ -1,7 +1,7 @@
 version: '2.7.0'
 systemName: 'ProxmoxCloudVps'
-name: 'Proxmox Cloud VPS'
-description: 'Proxmox Cloud VPS For WHMCS.<br>For more info visit our <a href="http://www.docs.modulesgarden.com/CHANGE_ME" style="color: #4169E1;" target="_blank">Wiki</a>.'
+name: 'Proxmox VE Cloud  VPS'
+description: 'Proxmox VE Cloud VPS For WHMCS.<br>For more info visit our <a href="http://www.docs.modulesgarden.com/CHANGE_ME" style="color: #4169E1;" target="_blank">Wiki</a>.'
 clientareaName: 'MG Demo'
 author: '<a href="http://www.modulesgarden.com" targer="_blank">ModulesGarden</a>'
 moduleIcon: 'ip_manager'

+ 20 - 0
app/Config/cron.yml

@@ -0,0 +1,20 @@
+<?php
+
+
+namespace ModulesGarden\Servers\ProxmoxCloudVps\App\Helpers;
+
+
+trait LicenseValidator
+{
+
+    public function isLicensePayingFullAnnuallyPrice($force = false){
+        if(!function_exists('ProxmoxCloudVps_GetLicenseData')){
+            return true;
+        }
+        $licenseData = ProxmoxCloudVps_GetLicenseData($force);
+        if(is_array($licenseData) && isset($licenseData['isPayingFullAnnuallyPrice']) && $licenseData['isPayingFullAnnuallyPrice'] !=1){
+            return false;
+        }
+        return true;
+    }
+}

+ 5 - 0
app/Helpers/ProxmoxAddonNotInstalledException.php

@@ -64,4 +64,9 @@ class UrlServiceHelper
         return $this->urlService->getUrl();
     }
 
+    public function getDownloadFirewallRulesUrl(){
+        $id = \ModulesGarden\ProxmoxAddon\Core\Helper\sl('Vm')->getVmModel()->id;
+        return $this->urlService->getUrl('vm', 'download',['vm'=> $id]);
+    }
+
 }

+ 5 - 2
app/Hooks/AdminAreaFooterOutput.php

@@ -59,8 +59,11 @@ class ChangePackage extends AddonController
             //Assing ip
             if (!Utility::isIpManagerProxmoxCloudIntegration())
             {
-                list($ip4, $ip6) = $this->networkService->getIpAddressesRequest();
-                $this->networkService->addIp($ip4, $ip6, $this->getDefaultNodeIfSet());
+                if($this->configuration()->isOrderPublicIp()){
+                    list($ip4, $ip6) = $this->networkService->getIpAddressesRequest();
+                    $bridge = $this->configuration()->getBridge();
+                    $this->networkService->addIp($ip4, $ip6, $this->getDefaultNodeIfSet(),$bridge);
+                }
             }
             return "success";
         }catch (\Exception $ex)

+ 5 - 3
app/Http/Actions/ChangeUserRole.php

@@ -65,9 +65,11 @@ class CreateAccount extends AddonController
             //Assing ip
             if (!Utility::isIpManagerProxmoxCloudIntegration())
             {
-                list($ip4, $ip6) = $this->networkService->getIpAddressesRequest();
-
-                $this->networkService->addIp($ip4, $ip6, $this->getDefaultNodeIfSet());
+                if($this->configuration()->isOrderPublicIp()){
+                    list($ip4, $ip6) = $this->networkService->getIpAddressesRequest();
+                    $bridge = $this->configuration()->getBridge();
+                    $this->networkService->addIp($ip4, $ip6, $this->getDefaultNodeIfSet(), $bridge);
+                }
             }
             if( $this->isUser()){
                 return "success";

+ 1 - 1
app/Http/Actions/MetaData.php

@@ -26,7 +26,7 @@ class MetaData extends AddonController
     public function execute($params = null)
     {
         return [
-            'DisplayName'    => 'Proxmox Cloud VPS',
+            'DisplayName'    => 'Proxmox VE Cloud  VPS',
             'RequiresServer' => true,
             'DefaultNonSSLPort' => '8006', // Default Non-SSL Connection Port
             'DefaultSSLPort' => '8006', // Default SSL Connection Port

+ 14 - 4
app/Http/Actions/ResetBandwidth.php

@@ -3,6 +3,7 @@
 namespace ModulesGarden\Servers\ProxmoxCloudVps\App\Http\Admin;
 
 use MGProvision\Proxmox\v2\Api;
+use ModulesGarden\ProxmoxAddon\App\Repositories\ModuleSettingRepository;
 use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
 use ModulesGarden\ProxmoxAddon\App\Services\Cloud\ProductService;
 use ModulesGarden\ProxmoxAddon\App\Services\Cloud\UserService;
@@ -31,17 +32,26 @@ class Home extends AbstractController
     use UserService;
     public function index()
     {
+        $this->moduleSetting = new ModuleSettingRepository();
         $view = Helper\viewIntegrationAddon();
         $view->initCustomAssetFiles();
         (new AppParams())->initFromWhmcsParams();
         //Resurces
-        $view->addElement(AccountResourcesContainer::class);
+        if($this->moduleSetting->isPermissionAccountResources()){
+            $view->addElement(AccountResourcesContainer::class);
+        }
         //VMs
-        $view->addElement(VmsDataTable::class);
+        if($this->moduleSetting->isPermissionVms()){
+            $view->addElement(VmsDataTable::class);
+        }
         //IPs
-        $view->addElement(IpAddressDataTable::class);
+        if($this->moduleSetting->isPermissionIpAddresses()){
+            $view->addElement(IpAddressDataTable::class);
+        }
         //User
-        $view->addElement(UserDataTable::class);
+        if($this->moduleSetting->isPermissionUserDetails()){
+            $view->addElement(UserDataTable::class);
+        }
         return $view;
 
     }

+ 1 - 1
app/Http/Admin/Product.php

@@ -36,7 +36,7 @@ trait BaseClientController
         if (!$vmModel->vmid || $vmModel->vmid == 0 ){
             return false;
         }
-        if(Job::waiting()->ofHostingId($this->getWhmcsParamByKey("serviceid"))->ofJobs($jobs)->ofCustomId($vmModel->id)->count() > 0){
+        if(Job::waiting()->ofHostingId($vmModel->hosting_id)->ofJobs($jobs)->ofCustomId($vmModel->id)->count() > 0){
             return false;
         }
 

+ 100 - 1
app/Http/Client/Console.php

@@ -3,17 +3,25 @@
 namespace ModulesGarden\Servers\ProxmoxCloudVps\App\Http\Client;
 
 use MGProvision\Proxmox\v2\Api;
+use MGProvision\Proxmox\v2\models\Kvm;
+use MGProvision\Proxmox\v2\models\Lxc;
+use ModulesGarden\ProxmoxAddon\App\Factory\ProxyServiceFactory;
 use ModulesGarden\ProxmoxAddon\App\Models\ModuleSettings;
+use ModulesGarden\ProxmoxAddon\App\Repositories\ModuleSettingRepository;
+use ModulesGarden\ProxmoxAddon\App\Repositories\ServerConfigurationRepository;
 use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
 use ModulesGarden\ProxmoxAddon\App\Services\Cloud\ProductService;
 use ModulesGarden\ProxmoxAddon\App\Services\Cloud\UserService;
 use ModulesGarden\ProxmoxAddon\App\Services\Utility;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\Helpers\AppParams;
+use ModulesGarden\Servers\ProxmoxCloudVps\App\Helpers\LicenseValidator;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Home\Pages\DetailsContainer;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\Http\AbstractClientController;
+use ModulesGarden\Servers\ProxmoxCloudVps\Core\ModuleConstants;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Traits\WhmcsParams;
 use Symfony\Component\HttpFoundation\RedirectResponse;
 use Symfony\Component\HttpFoundation\StreamedResponse;
+use function ModulesGarden\Servers\ProxmoxCloudVps\Core\Helper\sl;
 
 class Console extends AbstractClientController
 {
@@ -23,8 +31,12 @@ class Console extends AbstractClientController
     use ApiService;
     use ProductService;
     use BaseClientController;
+    use LicenseValidator;
 
-
+    /**
+     * @var ModuleSettingRepository
+     */
+    protected $moduleConfiguration;
     /**
      * Console constructor.
      */
@@ -37,12 +49,20 @@ class Console extends AbstractClientController
     public function novnc()
     {
         $this->acl()->novnc();
+        $this->moduleConfiguration = new ModuleSettingRepository();
+        if($this->moduleConfiguration->getConsoleApiKey() && $this->moduleConfiguration->consoleHost && $this->isLicensePayingFullAnnuallyPrice()){
+            $this->novncProxy();
+        }
         $this->console(['novnc' => 1]);
     }
 
     public function xtermjs()
     {
         $this->acl()->xtermjs();
+        $this->moduleConfiguration = new ModuleSettingRepository();
+        if($this->moduleConfiguration->getConsoleApiKey() && $this->moduleConfiguration->consoleHost && $this->isLicensePayingFullAnnuallyPrice()){
+            $this->xtermjsProxy();
+        }
         $this->console(['xtermjs' => 1]);
     }
 
@@ -140,4 +160,83 @@ class Console extends AbstractClientController
         $response->send();
         exit();
     }
+
+    /**
+     * @return Kvm|Lxc
+     */
+    protected function vmAsUser(){
+        if($this->vmAsUser){
+            return $this->vmAsUser;
+        }
+        //User
+        $vpsUser = $this->getUser();
+        if (empty($vpsUser->username))
+        {
+            throw new \Exception('User does not have permissions to access noVNC console');
+        }
+        $serverHost = $this->getWhmcsParamByKey('serverip') ? $this->getWhmcsParamByKey('serverip') : $this->getWhmcsParamByKey('serverhostname');
+        //Load Users API
+        if(!preg_match('/\:/', $serverHost) && $this->getWhmcsParamByKey('serverport') ){
+            $serverHost .=":".$this->getWhmcsParamByKey('serverport');
+        }
+        $api = new Api($serverHost, $vpsUser->username, $vpsUser->realm, $vpsUser->getPassword());
+        $api->debug(ModuleSettings::isDebug());
+        //websocket
+        $vm = \ModulesGarden\ProxmoxAddon\Core\Helper\sl('Vm')->getVm();
+        $vm->setApi($api);
+        if(!$vm->isRunning()){
+            throw new \Exception(sl('lang')->abtr("VM not running"));
+        }
+        return $this->vmUser = $vm;
+    }
+
+    public function novncProxy(){
+        $vars=[
+            'novncAppUrl' => './modules/addons/proxmoxAddon/templates/client/default/novnc'
+        ];
+        if($this->isAdmin()){
+            $vars['novncAppUrl']=  '../modules/addons/proxmoxAddon/templates/client/default/novnc';
+        }
+        try{
+            $vnc = $this->vmAsUser()->vncproxy(1);
+            $vncHost = $this->vmAsUser()->vncWebsocketPath( $vnc);
+            $clientIp = sl('request')->getClientIp();
+            //proxy generate token
+            $procyService = (new ProxyServiceFactory())->fromModuleConfiguration($this->moduleConfiguration);
+            $vars['websocketUrl'] = $procyService->proxmox("https://".$vncHost, $clientIp, $this->vmAsUser()->getApi()->getAuthCookieAsArray());
+            $vars['password'] = $vnc['ticket'];
+
+        }catch (\Exception $ex){
+            $vars['error'] = $ex->getMessage();
+        }
+        echo $this->getSmarty()
+            ->view(ModuleConstants::getFullPathWhmcs().DS.'modules'.DS.'addons'.DS.'proxmoxAddon'.DS.'templates'.DS.'client'.DS.'default'.DS.'pages'.DS.'console'.DS.'novnc', $vars);
+        exit();
+    }
+
+    public function xtermjsProxy(){
+
+        $vars=[
+            'appUrl' => './modules/addons/proxmoxAddon/templates/client/default',
+        ];
+        if($this->isAdmin()){
+            $vars['appUrl']=  '../modules/addons/proxmoxAddon/templates/client/default';
+        }
+        try{
+            $vnc = $this->vmAsUser()->termproxy();
+            $vncHost = $this->vmAsUser()->vncWebsocketPath( $vnc);
+            $clientIp = sl('request')->getClientIp();
+            //proxy generate token
+            $procyService = (new ProxyServiceFactory())->fromModuleConfiguration($this->moduleConfiguration);
+            $vars['websocketUrl'] = $procyService->proxmox("https://".$vncHost, $clientIp, $this->vmAsUser()->getApi()->getAuthCookieAsArray());
+            $vars['password'] = $vnc['ticket'];
+            $vars['user'] =$vnc['user'];
+        }catch (\Exception $ex){
+            $vars['error'] = $ex->getMessage();
+        }
+        echo $this->getSmarty()
+            ->view(ModuleConstants::getFullPathWhmcs().DS.'modules'.DS.'addons'.DS.'proxmoxAddon'.DS.'templates'.DS.'client'.DS.'default'.DS.'pages'.DS.'console'.DS.'xtermjs', $vars);
+        exit();
+    }
+
 }

+ 24 - 6
app/Http/Client/CustomTemplate.php

@@ -4,6 +4,7 @@
 namespace ModulesGarden\Servers\ProxmoxCloudVps\App\Http\Client;
 
 
+use MGProvision\Proxmox\v2\repository\FirewallRulesRepository;
 use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
 use ModulesGarden\ProxmoxAddon\App\Services\Cloud\ProductService;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\Helpers\AppParams;
@@ -21,6 +22,7 @@ use ModulesGarden\Servers\ProxmoxCloudVps\Core\Http\AbstractClientController;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Traits\WhmcsParams;
 use function ModulesGarden\Servers\ProxmoxCloudVps\Core\Helper\sl;
 use function ModulesGarden\Servers\ProxmoxCloudVps\Core\Helper\view;
+use Symfony\Component\HttpFoundation\StreamedResponse;
 
 class Vm extends AbstractClientController
 {
@@ -67,21 +69,37 @@ class Vm extends AbstractClientController
         (new AppParams())->initFromWhmcsParams();
         $view = view();
         $view->initCustomAssetFiles();
-        /**
-         * @deprecated
-         *     $view->addElement(\ModulesGarden\Servers\ProxmoxCloudVps\App\UI\VmCreate\Sections\AccountSummary::class);
-         */
-
         return $view->addElement(VmCreateForm::class);
     }
 
     public function update()
     {
-//        sl("sidebar")->getSidebar("virtualMachinesProxmoxCloudVps")->getChild("vmupdate")->setActive(true);
         $this->initVm();
         (new AppParams())->initFromWhmcsParams();
         $this->api();
         return view()->addElement(VmUpdateForm::class);
     }
 
+    public function download()
+    {
+        $this->initVm();
+        (new AppParams())->initFromWhmcsParams();
+        $this->api();
+        $response = new StreamedResponse();
+        $response->setStatusCode(200);
+        $response->headers->set('Content-Type', 'application/json; charset=utf-8');
+        $response->headers->set('Content-Transfer-Encoding', 'Binary');
+        $filename = sprintf("%s-firewal-rules.json",\ModulesGarden\ProxmoxAddon\Core\Helper\sl('Vm')->getVmModel()->name);
+        $response->headers->set('Content-Disposition', 'attachment; filename="'.$filename.'"');
+        $firewalRules = new FirewallRulesRepository();
+        $firewalRules->setApi($this->api());
+        $firewalRules->findByVmModel([\ModulesGarden\ProxmoxAddon\Core\Helper\sl('Vm')->getVmModel()]);
+        $response->setCallback(function () use( $firewalRules)
+        {
+            echo  \json_encode($firewalRules->fetchAsArray());
+            die();
+        });
+        $response->send();
+    }
+
 }

+ 12 - 0
app/UI/AccountSummary/Providers/AccountSummaryProvider.php

@@ -19,9 +19,11 @@
 
 namespace ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Admin\Product\Forms;
 
+use ModulesGarden\Servers\ProxmoxCloudVps\App\Helpers\LicenseValidator;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Admin\Product\Buttons\VirtualizationChangButton;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Admin\Product\Providers\ProductProvider;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Admin\Product\Sections\AdminNotificationSection;
+use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Admin\Product\Sections\AlertSection;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Admin\Product\Sections\BackupSection;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Admin\Product\Sections\ClientNotificationSection;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Admin\Product\Sections\ConsoleSection;
@@ -43,6 +45,8 @@ use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Forms\FormIntegration;
 class MainForm extends FormIntegration implements AdminArea
 {
 
+    use LicenseValidator;
+
     public function initContent()
     {
        /**
@@ -56,6 +60,7 @@ class MainForm extends FormIntegration implements AdminArea
          *
          */
         $isQemu = !$this->dataProvider->getValueById('customconfigoption[virtualization]') || $this->dataProvider->getValueById('customconfigoption[virtualization]') == "qemu";
+        $this->licenseAlert();
         /**
          * Main Section
          */
@@ -134,4 +139,11 @@ class MainForm extends FormIntegration implements AdminArea
         }
         return array_unique($fieldNames);
     }
+
+    public function licenseAlert(){
+        if(!$this->isLicensePayingFullAnnuallyPrice(true)){
+            $this->addSection(new AlertSection("You can use proxy for Proxmox console connections to increase the security of your infrastructure. Please contact <a href='https://www.modulesgarden.com/support/ticket/product-presales/Proxmox%20module%20upgrade%20request%20-%20Proxy%20console' target='_blank'>ModulesGarden support</a> to get more details and upgrade your module."));
+        }
+
+    }
 }

+ 69 - 8
app/UI/Admin/Product/Forms/VirtualizationChangeForm.php

@@ -24,9 +24,11 @@ use MGProvision\Proxmox\v2\repository\ClusterResourcesRepository;
 use MGProvision\Proxmox\v2\repository\FileRepository;
 use MGProvision\Proxmox\v2\repository\NodeRepository;
 use MGProvision\Proxmox\v2\repository\StorageRepository;
+use ModulesGarden\ProxmoxAddon\App\Helper\VmidHelper;
 use ModulesGarden\ProxmoxAddon\App\Models\CloudInitScript;
 use ModulesGarden\ProxmoxAddon\App\Models\IpAddress;
 use ModulesGarden\ProxmoxAddon\App\Models\ProductConfiguration;
+use ModulesGarden\ProxmoxAddon\App\Models\ServerGroup;
 use ModulesGarden\ProxmoxAddon\App\Models\Whmcs\Hosting;
 use ModulesGarden\ProxmoxAddon\App\Models\Whmcs\Product;
 use ModulesGarden\ProxmoxAddon\App\Repositories\Cloud\ProductConfigurationRepository;
@@ -45,6 +47,7 @@ class ProductProvider extends BaseDataProvider implements AdminArea
 {
     use ApiService;
     use ProductService;
+    use VmidHelper;
 
     private $productId;
 
@@ -79,11 +82,7 @@ class ProductProvider extends BaseDataProvider implements AdminArea
     public function read()
     {
         foreach ($this->configuration->all() as $key => $value) {
-            if ($key == "serverSockets") {
-
-
-            }
-            //multiselect
+             //multiselect
             if (is_array($value)) {
                 $this->data[sprintf("customconfigoption[%s][]", $key)] = $value;
                 continue;
@@ -130,6 +129,7 @@ class ProductProvider extends BaseDataProvider implements AdminArea
         $nodeRepository->setApi($this->api());
         $nodeRepository->findOnline(true);
         foreach ($nodeRepository->fetch() as $node) {
+            $this->nodes[] = $node->getNode();
             $this->availableValues["customconfigoption[defaultNode]"][$node->getNode()] = $node->getNode();
             //locations
             $this->availableValues["customconfigoption[locations][]"][$node->getNode()] = $node->getNode();
@@ -219,13 +219,42 @@ class ProductProvider extends BaseDataProvider implements AdminArea
             "ndp" => $lang->abtr("NDP"),
             "macfilter" => $lang->abtr("MAC Filter"),
             "ipfilter" => $lang->abtr("IP Filter"),
+            "policy_in" => $lang->abtr("Input Policy"),
+            "policy_out" => $lang->abtr("Output Policy"),
         ];
         //buttonSyle
         $this->availableValues["customconfigoption[buttonSyle]"] = ["tiles" => $lang->tr('Tiles'), 'buttons' => $lang->tr('Buttons'),];
         //detailsView
         $this->availableValues["customconfigoption[detailsView]"] = ["standard" => $lang->tr('Standard'),
             'combined' => $lang->tr('Combined'),];
-
+        //serverGroup
+        $this->serverGroupRead();
+        //firewalOptionPolicyIn
+        $this->availableValues["customconfigoption[firewalOptionPolicyIn]"] = [
+            "0" => "",
+            "DROP"   => sl("lang")->abtr("DROP"),
+            "ACCEPT" => sl("lang")->abtr("ACCEPT"),
+            "REJECT" => sl("lang")->abtr("REJECT"),
+        ];
+        //firewalOptionPolicyOut
+        $this->availableValues["customconfigoption[firewalOptionPolicyOut]"] = [
+            "0" => "",
+            "DROP"   => sl("lang")->abtr("DROP"),
+            "ACCEPT" => sl("lang")->abtr("ACCEPT"),
+            "REJECT" => sl("lang")->abtr("REJECT"),
+        ];
+        //permissionBackupCompress
+        $this->availableValues["customconfigoption[permissionBackupCompress][]"] = [
+            "none"   => $lang->abtr("None"),
+            "lzo" => $lang->abtr("LZO (fast)"),
+            "gzip" => $lang->abtr("GZIP (good)"),
+            "zstd" => $lang->abtr("ZSTD (fast and good)"),
+        ];
+        //permissionSnapshotJobPeriod
+        $this->availableValues["customconfigoption[permissionSnapshotJobPeriod][]"] = [
+            JobPeriod::HOURLY => $lang->tr(JobPeriod::HOURLY),
+            JobPeriod::DAILY => $lang->tr(JobPeriod::DAILY)
+        ];
     }
 
     /**
@@ -337,7 +366,7 @@ class ProductProvider extends BaseDataProvider implements AdminArea
         //memoryUnit
         $this->availableValues["customconfigoption[memoryUnit]"] = ['mb' => $lang->tr("MB"), "gb" => $lang->tr("GB")];
         //storageUnit
-        $this->availableValues["customconfigoption[storageUnit]"] = ['mb' => $lang->tr("MB"), "gb" => $lang->tr("GB"), "tb" => $lang->tr("TB")];
+        $this->availableValues["customconfigoption[storageUnit]"] = [ "gb" => $lang->tr("GB"), "tb" => $lang->tr("TB")];
         //cdromType
         $this->availableValues["customconfigoption[cdromType]"] = $this->availableValues["customconfigoption[diskType]"];
         //bios
@@ -358,6 +387,17 @@ class ProductProvider extends BaseDataProvider implements AdminArea
         foreach ($jsonData->get() as $k => $name) {
             $this->availableValues["customconfigoption[cpu]"][$k] = $lang->tr($name);
         }
+        //archive
+        $fileRepository->findBackupQemuTemplates();
+        $fileRepository->findByNodes($this->nodes);
+        foreach (   $fileRepository->fetch() as $file) {
+            if($this->vmidExistInWhmcs($file->getVmid())){
+                continue;
+            }
+            $this->availableValues["customconfigoption[archive][]"][$file->getNode().":".$file->getVolid()] = $file->formatVolid();
+        }
+        //cloudInitStorage
+        $this->availableValues["customconfigoption[cloudInitStorage]"] = [0=> ""] + $this->availableValues["customconfigoption[diskStorage]"];
 
     }
 
@@ -395,7 +435,7 @@ class ProductProvider extends BaseDataProvider implements AdminArea
         //memoryUnit
         $this->availableValues["customconfigoption[memoryUnit]"] = ['mb' => $lang->tr("MB"), "gb" => $lang->tr("GB")];
         //storageUnit
-        $this->availableValues["customconfigoption[storageUnit]"] = ['mb' => $lang->tr("MB"), "gb" => $lang->tr("GB"), "tb" => $lang->tr("TB")];
+        $this->availableValues["customconfigoption[storageUnit]"] = [ "gb" => $lang->tr("GB"), "tb" => $lang->tr("TB")];
         //persimonOsTemplates
         $this->availableValues["customconfigoption[permissionOsTemplates][]"] = $this->availableValues["customconfigoption[osTemplate]"];
         //mountPointStorage
@@ -423,6 +463,15 @@ class ProductProvider extends BaseDataProvider implements AdminArea
         ksort($this->availableValues["customconfigoption[bridge]"]);
         //privateBridge
         $this->availableValues["customconfigoption[privateBridge]"] = ['0' => ""] + (array)$this->availableValues["customconfigoption[bridge]"];
+        //archive
+        $fileRepository->findBackupLxcTemplates();
+        $fileRepository->findByNodes($this->nodes);
+        foreach (   $fileRepository->fetch() as $file) {
+            if($this->vmidExistInWhmcs($file->getVmid())){
+                continue;
+            }
+            $this->availableValues["customconfigoption[archive][]"][$file->getNode().":".$file->getVolid()] = $file->formatVolid();
+        }
     }
 
     public function update()
@@ -479,4 +528,16 @@ class ProductProvider extends BaseDataProvider implements AdminArea
             $newEntity->save();
         }
     }
+
+    protected function serverGroupRead(){
+        $groupId  = sl("whmcsParams")->getWhmcsParams()['groupid'];
+        $sg = (new ServerGroup())->getTable();
+        $ssg = "tblservergroupsrel";
+        $query = ServerGroup::select("{$sg}.id", "{$sg}.name")
+            ->leftJoin($ssg,"{$ssg}.serverid","=","{$sg}.server_id"  )
+            ->where("{$ssg}.groupid", $groupId);
+        foreach ($query->get() as $row){
+            $this->availableValues['customconfigoption[serverGroup][]'][$row->id] = $row->name;
+        }
+    }
 }

+ 30 - 0
app/UI/Admin/Product/Sections/AlertSection.php

@@ -0,0 +1,30 @@
+<?php
+
+
+namespace ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Admin\Product\Sections;
+
+
+use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Traits\Alerts;
+use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Forms\Sections\BoxSection;
+
+class AlertSection extends BoxSection implements AdminArea
+{
+
+    use Alerts;
+
+    public function __construct($mesage , $type ='info')
+    {
+        $this->internalAlertMessage = $mesage;
+        $this->internalAlertMessageType = $type;
+        parent::__construct('alertSection');
+    }
+
+    public function initContent()
+    {
+//        dump($this->getTemplateDir());
+//        $this->getHtml();
+//        die();
+
+    }
+}

+ 8 - 0
app/UI/Admin/Product/Sections/BackupSection.php

@@ -3,6 +3,7 @@
 namespace ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Admin\Product\Sections;
 
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Forms\Fields\Select;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Forms\Fields\Switcher;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Forms\Sections\BoxSection;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Forms\Sections\HalfPageSection;
@@ -54,6 +55,13 @@ class FirewallOptionSection extends BoxSection implements AdminArea
         //ipfilter
         $field = new Switcher("customconfigoption[firewalOptionIpfilter]");
         $this->addField($field);
+        //policy_out
+        $field = new Select("customconfigoption[firewalOptionPolicyIn]");
+        $this->addField($field);
+        //policy_out
+        $field = new Select("customconfigoption[firewalOptionPolicyOut]");
+        $this->addField($field);
+
     }
 
     public function addField($field){

+ 10 - 0
app/UI/Admin/Product/Sections/FirewallSection.php

@@ -50,6 +50,16 @@ class LoadBalancerSection extends BoxSection implements AdminArea
         $field = new Switcher('customconfigoption[loadBalancerStopOnUpgrade]');
         $field->setDescription('tip');
         $this->rightSection->addField($field);
+        //serverGroup
+        $field = new Select('customconfigoption[serverGroup][]');
+        $field->enableMultiple();
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //with-local-disks
+        $field = new Switcher('customconfigoption[loadBalancerMigrationWithLocalDisks]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+
     }
 
 }

+ 25 - 0
app/UI/Admin/Product/Sections/Lxc/ClientAreaSection.php

@@ -164,6 +164,31 @@ class ClientAreaSection extends TwiceColumnSection implements AdminArea
         $field->setDescription('tip');
         $field->setDefaultValue("on");
         $this->addField($field);
+        //permissionBackupCompress
+        $field = new Select("customconfigoption[permissionBackupCompress][]");
+        $field->enableMultiple();
+        $field->setDescription('description');
+        $this->addField($field);
+        //Snapshot Jobs
+        $field = new Switcher('customconfigoption[permissionSnapshotJob]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->addField($field);
+        //How Often
+        $field = new Select('customconfigoption[permissionSnapshotJobPeriod][]');
+        $field->setDescription('tip');
+        $field->enableMultiple();
+        $this->addField($field);
+        //permissionArchive
+        $field = new Switcher('customconfigoption[permissionArchive]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->addField($field);
+        //archive
+        $field = new Select('customconfigoption[archive][]');
+        $field->enableMultiple();
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
     }
 
 

+ 5 - 0
app/UI/Admin/Product/Sections/Lxc/ConfigurableOptionUnitsSection.php

@@ -86,6 +86,11 @@ class DefaultConfigurationSection extends TwiceColumnSection implements AdminAre
         $field->setDescription('tip');
         $field->setDefaultValue(1);
         $this->addField($field);
+        //snapshotJobs
+        $field = new Text('customconfigoption[snapshotJobs]');
+        $field->setDescription('tip');
+        $field->setDefaultValue(1);
+        $this->addField($field);
     }
 
 }

+ 2 - 0
app/UI/Admin/Product/Sections/Lxc/MountPointSection.php

@@ -58,10 +58,12 @@ class NetworkSection extends BoxSection implements AdminArea
         $this->leftSection->addField($field);
         //VLAN TAG Range From
         $field = new Text('customconfigoption[tagFrom]');
+        $field->setDecimal(1);
         $field->setDescription('tip');
         $this->rightSection->addField($field);
         //VLAN TAG Range To
         $field = new Text('customconfigoption[tagTo]');
+        $field->setDecimal(4094);
         $field->setDescription('tip');
         $this->leftSection->addField($field);
         //Tag

+ 5 - 0
app/UI/Admin/Product/Sections/Lxc/ServerSection.php

@@ -56,5 +56,10 @@ class ServerSection extends TwiceColumnSection implements AdminArea
         $field->setDescription('tip');
         $field->setDefaultValue('0-10');
         $this->addField($field);
+        //serverInterfaces
+        $field = new Text('customconfigoption[serverVirtualInterfaces]');
+        $field->setDescription('tip');
+        $field->setDefaultValue('0-10');
+        $this->addField($field);
     }
 }

+ 10 - 1
app/UI/Admin/Product/Sections/MainSection.php

@@ -40,7 +40,7 @@ class MiscellaneousSection extends BoxSection implements AdminArea
         $field->setDescription('tip');
         $this->leftSection->addField($field);
         //Reboot VM After Changing Package
-        $field = new Switcher('customconfigoption[rebootVmAfterUpgrade');
+        $field = new Switcher('customconfigoption[rebootVmAfterUpgrade]');
         $field->setDescription('tip');
         $this->rightSection->addField($field);
         //Bandwidth Overage
@@ -61,6 +61,15 @@ class MiscellaneousSection extends BoxSection implements AdminArea
         $field->setDefaultValue('standard');
         $field->setDescription('tip');
         $this->leftSection->addField($field);
+        //Order Public IP
+        $field = new Switcher('customconfigoption[suspendOnBandwidthOverage]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Order Public IP
+        $field = new Switcher('customconfigoption[orderPublicIp]');
+        $field->setDefaultValue('on');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
     }
 
 }

+ 25 - 0
app/UI/Admin/Product/Sections/Qemu/AdditonalDisk.php

@@ -221,6 +221,31 @@ class ClientAreaSection extends TwiceColumnSection implements AdminArea
         $field->enableMultiple();
         $field->setDescription('tip');
         $this->leftSection->addField($field);
+        //permissionBackupCompress
+        $field = new Select("customconfigoption[permissionBackupCompress][]");
+        $field->enableMultiple();
+        $field->setDescription('description');
+        $this->addField($field);
+        //Snapshot Jobs
+        $field = new Switcher('customconfigoption[permissionSnapshotJob]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->addField($field);
+        //How Often
+        $field = new Select('customconfigoption[permissionSnapshotJobPeriod][]');
+        $field->setDescription('tip');
+        $field->enableMultiple();
+        $this->addField($field);
+        //permissionArchive
+        $field = new Switcher('customconfigoption[permissionArchive]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->addField($field);
+        //archive
+        $field = new Select('customconfigoption[archive][]');
+        $field->enableMultiple();
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
     }
     
 }

+ 6 - 0
app/UI/Admin/Product/Sections/Qemu/CloudInitSection.php

@@ -4,6 +4,7 @@ namespace ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Admin\Product\Sections\Qe
 
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Admin\Product\Sections\TwiceColumnSection;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Forms\Fields\Select;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Forms\Fields\Switcher;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Forms\Fields\Text;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Forms\Fields\Textarea;
@@ -31,6 +32,11 @@ class CloudInitSection extends TwiceColumnSection implements AdminArea
         $field = new Textarea('customconfigoption[cicustom]');
         $field->setDescription('tip');
         $this->addField($field);
+        //cloudInitStorage
+        $field = new Select('customconfigoption[cloudInitStorage]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+
 
     }
 

+ 1 - 0
app/UI/Admin/Product/Sections/Qemu/ConfigurableOptionUnitsSection.php

@@ -171,6 +171,7 @@ class ConfigurationSection extends BoxSection implements AdminArea
         $field = new Text('customconfigoption[vgaMemory]');
         $field->setDescription('tip');
         $this->leftSection->addField($field);
+
     }
 
 }

+ 5 - 0
app/UI/Admin/Product/Sections/Qemu/DefaultConfigurationSection.php

@@ -84,6 +84,11 @@ class DefaultConfigurationSection extends TwiceColumnSection implements AdminAre
         $field->setDescription('tip');
         $field->setDefaultValue(1);
         $this->addField($field);
+        //snapshotJobs
+        $field = new Text('customconfigoption[snapshotJobs]');
+        $field->setDescription('tip');
+        $field->setDefaultValue(1);
+        $this->addField($field);
     }
 
 }

+ 2 - 0
app/UI/Admin/Product/Sections/Qemu/DiskSection.php

@@ -56,10 +56,12 @@ class NetworkSection extends TwiceColumnSection implements AdminArea
         $this->addField($field);
         //VLAN TAG Range From
         $field = new Text('customconfigoption[tagFrom]');
+        $field->setDecimal(1);
         $field->setDescription('tip');
         $this->addField($field);
         //VLAN TAG Range To
         $field = new Text('customconfigoption[tagTo]');
+        $field->setDecimal(4094);
         $field->setDescription('tip');
         $this->addField($field);
         //Tag

+ 5 - 0
app/UI/Admin/Product/Sections/Qemu/ServerSection.php

@@ -61,5 +61,10 @@ class ServerSection extends TwiceColumnSection implements AdminArea
         $field->setDescription('tip');
         $field->setDefaultValue('0-10');
         $this->addField($field);
+        //serverInterfaces
+        $field = new Text('customconfigoption[serverVirtualInterfaces]');
+        $field->setDescription('tip');
+        $field->setDefaultValue('0-10');
+        $this->addField($field);
     }
 }

+ 5 - 0
app/UI/Admin/Product/Sections/TwiceColumnSection.php

@@ -0,0 +1,5 @@
+<div class="alert {if $rawObject->getInternalAlertSize() !== ''}alert--{$rawObject->getInternalAlertSize()}{/if} alert-{$rawObject->getInternalAlertMessageType()} alert--faded datatable-alert-top" style="margin-top:0px; margin-bottom: 10px !important;">
+    <div class="alert__body">
+        {if $rawObject->isInternalAlertMessageRaw()|unescape:'html'}{$rawObject->getInternalAlertMessage()}{else}{$MGLANG->T($rawObject->getInternalAlertMessage())|unescape:'html'}{/if}
+    </div>
+</div>

+ 0 - 6
app/UI/Admin/User/Pages/UserDataTable.php

@@ -64,12 +64,6 @@ class CreateForm extends BaseForm implements ClientArea
     {
         //compress
         $field = new Select('compress');
-        $field->setAvailableValues([
-            "0"    => sl("lang")->tr("None"),
-            "lzo"  => sl("lang")->tr("LZO (fast)"),
-            "gzip" => sl("lang")->tr("GZIP (good)"),
-            "zstd" => sl("lang")->abtr("ZSTD (fast and good)")
-        ]);
         $field->setDefaultValue('zstd');
         $this->addField($field);
         //mode

+ 1 - 1
app/UI/Backup/Forms/DeleteForm.php

@@ -52,7 +52,7 @@ class BackupDataTable extends DataTable implements ClientArea
         $createButton->addClass("pmCreateBackupButton");
         if (!$this->resourceGuard()->hasBackupLimit())
         {
-            $createButton->addClass("hidden");
+            $createButton->addClass("disabled");
         }
         $this->unsetShowTitle();
         if ($this->configuration()->isPermissionBackup())

+ 37 - 5
app/UI/Backup/Providers/BackupProvider.php

@@ -28,6 +28,7 @@ use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Interfaces\ClientArea;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\ResponseTemplates\HtmlDataJsonResponse;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Forms\DataProviders\BaseDataProvider;
 use function ModulesGarden\ProxmoxAddon\Core\Helper\queue;
+use function ModulesGarden\Servers\ProxmoxCloudVps\Core\Helper\sl;
 
 class BackupProvider extends BaseDataProvider implements ClientArea
 {
@@ -40,6 +41,25 @@ class BackupProvider extends BaseDataProvider implements ClientArea
         {
             $this->data = json_decode(base64_decode($this->actionElementId), true);
         }
+        $this->availableValues['compress'] = [
+            "0"    => sl("lang")->abtr("None"),
+            "lzo"  => sl("lang")->abtr("LZO (fast)"),
+            "gzip" => sl("lang")->abtr("GZIP (good)"),
+            "zstd" => sl("lang")->abtr("ZSTD (fast and good)")
+        ];
+        $optionBackupCompress = $this->configuration()->getPermissionBackupCompress();
+        if(empty($optionBackupCompress)){
+            return;
+        }
+        foreach ($this->availableValues['compress'] as $k => $option){
+            if($k=="0" && !in_array("none", $optionBackupCompress)){
+                unset($this->availableValues['compress'][$k]);
+            }
+            if(!in_array($k, $optionBackupCompress)){
+                unset($this->availableValues['compress'][$k]);
+            }
+        }
+
     }
 
     public function create()
@@ -51,16 +71,23 @@ class BackupProvider extends BaseDataProvider implements ClientArea
         $maxFiles       =  $this->configuration()->getBackupMaxFiles();
         if($this->isWhmcsConfigOption(ConfigurableOption::BACKUPS_FILES) &&  $this->getWhmcsConfigOption(ConfigurableOption::BACKUPS_FILES)!="-1"){
             $maxFiles       = $this->getWhmcsConfigOption(ConfigurableOption::BACKUPS_FILES);
-        }else if($this->getWhmcsConfigOption(ConfigurableOption::BACKUPS_FILES)=="-1"){
+        }else if($this->getWhmcsConfigOption(ConfigurableOption::BACKUPS_FILES, $this->configuration()->getBackupMaxFiles())=="-1"){
             $maxFiles       = null;
         }
         $vm = \ModulesGarden\ProxmoxAddon\Core\Helper\sl('Vm')->getVm();
+        if($vm->isLockBackup()){
+            return (new HtmlDataJsonResponse())
+                ->setStatusError()
+                ->setMessageAndTranslate('The backup creation is in progress');
+        }
         $vm ->backup($storage, $routing, $maxFiles, $this->formData['compress'], $this->formData['mode']);
         return (new HtmlDataJsonResponse())
             ->setStatusSuccess()
             ->setMessageAndTranslate('The backup creation is in progress')
             ->addData('createButtonStatus', $this->configuration()->isPermissionBackup() && $this->resourceGuard()->hasBackupLimit())
-            ->setCallBackFunction('pmToggleBackupButton');
+            ->setCallBackFunction('pmToggleBackupButton')
+            ->addRefreshTargetId('resourcesContainer')
+            ->addRefreshTargetId('backupDataTable');
     }
 
     public function restore()
@@ -92,7 +119,10 @@ class BackupProvider extends BaseDataProvider implements ClientArea
             ->setStatusSuccess()
             ->setMessageAndTranslate('The backup has been deleted successfully')
             ->addData('createButtonStatus', $this->configuration()->isPermissionBackup() && $this->resourceGuard()->hasBackupLimit())
-            ->setCallBackFunction('pmToggleBackupButton');
+            ->setCallBackFunction('pmToggleBackupButton')
+            ->addRefreshTargetId('resourcesContainer')
+            ->addRefreshTargetId('backupDataTable');
+
     }
 
     public function deleteMass()
@@ -113,7 +143,9 @@ class BackupProvider extends BaseDataProvider implements ClientArea
             ->setStatusSuccess()
             ->setMessageAndTranslate('The backups have been deleted successfully')
             ->addData('createButtonStatus', $this->configuration()->isPermissionBackup() && $this->resourceGuard()->hasBackupLimit())
-            ->setCallBackFunction('pmToggleBackupButton');
+            ->setCallBackFunction('pmToggleBackupButton')
+            ->addRefreshTargetId('resourcesContainer')
+            ->addRefreshTargetId('backupDataTable');
     }
 
-}
+}

+ 0 - 6
app/UI/BackupJob/Buttons/CreateButton.php

@@ -94,12 +94,6 @@ class CreateForm extends BaseForm implements ClientArea
         $this->addField($field);
         //compress
         $field = new Select('compress');
-        $field->setAvailableValues([
-            "0"    => sl("lang")->tr("0"),
-            "lzo"  => sl("lang")->tr("lzo"),
-            "gzip" => sl("lang")->tr("gzip"),
-            "zstd" => sl("lang")->tr("zstd")
-        ]);
         $field->setDefaultValue('zstd');
         $field->notEmpty();
         $this->addField($field);

+ 0 - 6
app/UI/BackupJob/Forms/DeleteForm.php

@@ -98,12 +98,6 @@ class UpdateForm extends BaseForm implements ClientArea
         $this->addField($field);
         //compress
         $field = new Select('compress');
-        $field->setAvailableValues([
-            "0"    => sl("lang")->tr("0"),
-            "lzo"  => sl("lang")->tr("lzo"),
-            "gzip" => sl("lang")->tr("gzip"),
-            "zstd" => sl("lang")->tr("zstd")
-        ]);
         $field->setDefaultValue('zstd');
         $field->notEmpty();
         $this->addField($field);

+ 22 - 3
app/UI/BackupJob/Modals/CreateModal.php

@@ -26,6 +26,7 @@ use ModulesGarden\ProxmoxAddon\App\Enum\Cloud\ConfigurableOption;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Interfaces\ClientArea;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\ResponseTemplates\HtmlDataJsonResponse;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Forms\DataProviders\BaseDataProvider;
+use function ModulesGarden\Servers\ProxmoxCloudVps\Core\Helper\sl;
 
 class BackupJobProvider extends BaseDataProvider implements ClientArea
 {
@@ -44,6 +45,24 @@ class BackupJobProvider extends BaseDataProvider implements ClientArea
             $mailto               = $this->data['mailto'];
             $this->data['mailto'] = $mailto ? "on" : "off";
         }
+        $this->availableValues['compress'] = [
+            "0"    => sl("lang")->abtr("None"),
+            "lzo"  => sl("lang")->abtr("LZO (fast)"),
+            "gzip" => sl("lang")->abtr("GZIP (good)"),
+            "zstd" => sl("lang")->abtr("ZSTD (fast and good)")
+        ];
+        $optionBackupCompress = $this->configuration()->getPermissionBackupCompress();
+        if(empty($optionBackupCompress)){
+            return;
+        }
+        foreach ($this->availableValues['compress'] as $k => $option){
+            if($k=="0" && !in_array("none", $optionBackupCompress)){
+                unset($this->availableValues['compress'][$k]);
+            }
+            if(!in_array($k, $optionBackupCompress)){
+                unset($this->availableValues['compress'][$k]);
+            }
+        }
     }
 
     public function create()
@@ -56,7 +75,7 @@ class BackupJobProvider extends BaseDataProvider implements ClientArea
 
         if($this->isWhmcsConfigOption(ConfigurableOption::BACKUPS_FILES) &&  $this->getWhmcsConfigOption(ConfigurableOption::BACKUPS_FILES)!="-1"){
             $maxFiles       = $this->getWhmcsConfigOption(ConfigurableOption::BACKUPS_FILES);
-        }else if($this->getWhmcsConfigOption(ConfigurableOption::BACKUPS_FILES)=="-1"){
+        }else if($this->getWhmcsConfigOption(ConfigurableOption::BACKUPS_FILES, $this->configuration()->getBackupMaxFiles())=="-1"){
             $maxFiles       = null;
         }
         $backupSchedule = new BackupSchedule();
@@ -90,7 +109,7 @@ class BackupJobProvider extends BaseDataProvider implements ClientArea
         $maxFiles       =  $this->configuration()->getBackupMaxFiles();
         if($this->isWhmcsConfigOption(ConfigurableOption::BACKUPS_FILES) &&  $this->getWhmcsConfigOption(ConfigurableOption::BACKUPS_FILES)!="-1"){
             $maxFiles       = $this->getWhmcsConfigOption(ConfigurableOption::BACKUPS_FILES);
-        }else if($this->getWhmcsConfigOption(ConfigurableOption::BACKUPS_FILES)=="-1"){
+        }else if($this->getWhmcsConfigOption(ConfigurableOption::BACKUPS_FILES, $this->configuration()->getBackupMaxFiles())=="-1"){
             $maxFiles       = null;
         }
         $backupSchedule = new BackupSchedule();
@@ -130,4 +149,4 @@ class BackupJobProvider extends BaseDataProvider implements ClientArea
     }
 
 
-}
+}

+ 5 - 1
app/UI/Client/Templates/assets/css/integration.css

@@ -154,4 +154,8 @@ input[type=range]:focus::-ms-fill-upper {
 
 .vm-actions .lu-btn{
     width: 23%;
-}
+}
+
+#layers #resourcesContainer .lu-progress--h .lu-progress__label {
+    flex-basis: 24% !important;
+}

+ 45 - 2
app/UI/Client/Templates/assets/img/buttons/backup.png


+ 1 - 1
app/UI/CustomTemplate/Buttons/CreateButton.php

@@ -123,7 +123,7 @@ class DiskProvider extends BaseDataProvider implements ClientArea
         }
         if($hdd->isMaster()){
             $vm->config(true);
-            $vmModel->disk =  $vm->getMasterHddSize();
+            $vmModel->disk =  $vm->getHardDiskRepostiory()->findById($hdd->getId())->getGb();
         }else{
             $vmModel->disks = $vm->getHardDiskRepostiory()->additionalSize();
         }

+ 0 - 17
app/UI/Disk/Validators/DiskSizeValidator.php

@@ -1,21 +1,4 @@
 <?php
-/* * ********************************************************************
-*  ProxmoxVPS Product developed. (27.03.19)
-* *
-*
-*  CREATED BY MODULESGARDEN       ->       http://modulesgarden.com
-*  CONTACT                        ->       contact@modulesgarden.com
-*
-*
-* This software is furnished under a license and may be used and copied
-* only  in  accordance  with  the  terms  of such  license and with the
-* inclusion of the above copyright notice.  This software  or any other
-* copies thereof may not be provided or otherwise made available to any
-* other person.  No title to and  ownership of the  software is  hereby
-* transferred.
-*
-*
-* ******************************************************************** */
 
 namespace ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Firewall\Buttons;
 

+ 47 - 0
app/UI/Firewall/Buttons/DeleteButton.php

@@ -0,0 +1,47 @@
+<?php
+
+
+namespace ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Firewall\Buttons;
+
+use MGProvision\Proxmox\v2\models\FirewallRule;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Firewall\Modals\UpdateGroupModal;
+use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Firewall\Modals\UpdateRuleModal;
+use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\ResponseTemplates\DataJsonResponse;
+use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+
+class DownRuleButton extends ButtonDataTableModalAction implements ClientArea
+{
+    use ProductService;
+    use ApiService;
+    protected $icon           = 'lu-btn__icon lu-zmdi lu-zmdi-long-arrow-down';
+
+    public function initContent()
+    {
+        $this->initIds('downRuleButton');
+        $this->htmlAttributes['@click'] = 'buttonAction($event, \'' . $this->id . '\')';
+    }
+
+    public function returnAjaxData()
+    {
+        try
+        {
+            $data         = json_decode(base64_decode($this->getRequestValue('actionElementId')), true);
+            $vm = \ModulesGarden\ProxmoxAddon\Core\Helper\sl('Vm')->getVm();
+            $firewallRule = new FirewallRule();
+            $firewallRule->setApi($this->api());
+            $pos = $data['pos'];
+            $firewallRule->setPath($vm->getPath() . "/firewall/rules/{$pos}");
+            $firewallRule->moveto( $pos+2);
+        }
+        catch (\Exception $exc)
+        {
+            return (new DataJsonResponse())->setStatusError()->setMessage($exc->getMessage())->setCallBackFunction($this->callBackFunction)->addRefreshTargetId($this->refreshActionIds);
+        }
+        return (new DataJsonResponse())->setMessageAndTranslate('changesSaved')->addRefreshTargetId('firewallDataTable');
+    }
+
+
+}

+ 47 - 0
app/UI/Firewall/Buttons/DownloadButton.php

@@ -0,0 +1,47 @@
+<?php
+/* * ********************************************************************
+*  ProxmoxVPS Product developed. (27.03.19)
+* *
+*
+*  CREATED BY MODULESGARDEN       ->       http://modulesgarden.com
+*  CONTACT                        ->       contact@modulesgarden.com
+*
+*
+* This software is furnished under a license and may be used and copied
+* only  in  accordance  with  the  terms  of such  license and with the
+* inclusion of the above copyright notice.  This software  or any other
+* copies thereof may not be provided or otherwise made available to any
+* other person.  No title to and  ownership of the  software is  hereby
+* transferred.
+*
+*
+* ******************************************************************** */
+
+namespace ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Firewall\Buttons;
+
+use ModulesGarden\Servers\ProxmoxCloudVps\App\Helpers\UrlServiceHelper;
+use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Firewall\Modals\CreateGroupModal;
+use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Buttons\ButtonCreate;
+use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Buttons\ButtonRedirect;
+use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Buttons\DropdawnButtonWrappers\ButtonDropdownItem;
+
+
+class DownloadButton extends ButtonRedirect  implements ClientArea
+{
+    protected $id='downloadButton';
+    protected $name ='downloadButton';
+    protected $title='downloadButton';
+    protected $icon  = 'lu-dropdown__link-icon lu-zmdi  lu-zmdi-download';
+    protected $class          = ['lu-dropdown__link'];
+    protected $showTitle = true;
+
+    public function initContent()
+    {
+        $this->initIds('downloadButton');
+        $url = (new UrlServiceHelper())->getDownloadFirewallRulesUrl();
+        $this->setRawUrl($url);
+    }
+
+
+}

+ 22 - 0
app/UI/Firewall/Buttons/EnableSwitchButton.php

@@ -0,0 +1,22 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Firewall\Buttons;
+
+use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Firewall\Modals\CreateGroupModal;
+use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Firewall\Modals\RestoreModal;
+use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Buttons\ButtonCreate;
+use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Buttons\DropdawnButtonWrappers\ButtonDropdownItem;
+
+
+class RestoreButton extends ButtonDropdownItem  implements ClientArea
+{
+    protected $id = 'restoreButton';
+    protected $icon  = 'lu-dropdown__link-icon lu-zmdi  lu-zmdi-time-restore';
+
+    public function initContent()
+    {
+        $this->initIds('restoreButton');
+        $this->initLoadModalAction(new RestoreModal());
+    }
+}

+ 50 - 0
app/UI/Firewall/Buttons/UpRuleButton.php

@@ -0,0 +1,50 @@
+<?php
+
+
+namespace ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Firewall\Buttons;
+
+use MGProvision\Proxmox\v2\models\FirewallRule;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Firewall\Modals\UpdateGroupModal;
+use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Firewall\Modals\UpdateRuleModal;
+use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\ResponseTemplates\DataJsonResponse;
+use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+
+class UpRuleButton extends ButtonDataTableModalAction implements ClientArea
+{
+    use ProductService;
+    use ApiService;
+    protected $icon           = 'lu-btn__icon lu-zmdi lu-zmdi-long-arrow-up';//zmdi-long-arrow-down
+
+    public function initContent()
+    {
+        $this->initIds('upRuleButton');
+        $this->htmlAttributes['@click'] = 'buttonAction($event, \'' . $this->id . '\')';
+    }
+
+    public function returnAjaxData()
+    {
+        try
+        {
+            $data         = json_decode(base64_decode($this->getRequestValue('actionElementId')), true);
+            $vm = \ModulesGarden\ProxmoxAddon\Core\Helper\sl('Vm')->getVm();
+            if($data['pos']==0){
+                return (new DataJsonResponse())->setMessageAndTranslate('changesSaved')->setCallBackFunction($this->callBackFunction)->addRefreshTargetId($this->refreshActionIds);
+            }
+            $firewallRule = new FirewallRule();
+            $firewallRule->setApi($this->api());
+            $pos = $data['pos'];
+            $firewallRule->setPath($vm->getPath() . "/firewall/rules/{$pos}");
+            $firewallRule->moveto( $pos-1);
+        }
+        catch (\Exception $exc)
+        {
+            return (new DataJsonResponse())->setStatusError()->setMessage($exc->getMessage())->setCallBackFunction($this->callBackFunction)->addRefreshTargetId($this->refreshActionIds);
+        }
+        return (new DataJsonResponse())->setMessageAndTranslate('changesSaved')->addRefreshTargetId('firewallDataTable');
+    }
+
+
+}

+ 60 - 0
app/UI/Firewall/Buttons/UpdateRuleButton.php

@@ -0,0 +1,60 @@
+<?php
+/* * ********************************************************************
+*  ProxmoxVPS Product developed. (27.03.19)
+* *
+*
+*  CREATED BY MODULESGARDEN       ->       http://modulesgarden.com
+*  CONTACT                        ->       contact@modulesgarden.com
+*
+*
+* This software is furnished under a license and may be used and copied
+* only  in  accordance  with  the  terms  of such  license and with the
+* inclusion of the above copyright notice.  This software  or any other
+* copies thereof may not be provided or otherwise made available to any
+* other person.  No title to and  ownership of the  software is  hereby
+* transferred.
+*
+*
+* ******************************************************************** */
+
+namespace ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Firewall\Forms;
+
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Firewall\Providers\FirewallProvider;
+use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Forms\Fields\FileField;
+use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Forms\Fields\Hidden;
+use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Forms\Fields\Text;
+
+class RestoreForm extends BaseForm implements ClientArea
+{
+    use ApiService;
+
+    public function initContent()
+    {
+        $this->initIds('restoreForm');
+        $this->setFormType('restore');
+        $this->setProvider(new FirewallProvider());
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['restore'];
+    }
+
+    protected function initFields(){
+        //rules
+        $field = new FileField('rules');
+        $field->setId('pmFirewallRules');
+        $this->addField($field);
+        //rules
+        $field = new Hidden('rulesJson');
+        $field->addHtmlAttribute('id','pmRulesJson');
+        $this->addField($field);
+
+    }
+
+}

+ 20 - 0
app/UI/Firewall/Forms/RuleForm.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Firewall\Modals;
+
+use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Firewall\Forms\CreateGroupForm;
+use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Firewall\Forms\RestoreForm;
+use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Modals\BaseEditModal;
+use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Modals\ModalConfirmSuccess;
+
+class RestoreModal extends BaseEditModal implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('restoreModal');
+        $this->addForm(new RestoreForm());
+    }
+
+}

+ 14 - 1
app/UI/Firewall/Modals/UpdateGroupModal.php

@@ -26,9 +26,12 @@ use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Firewall\Buttons\CreateGroupBut
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Firewall\Buttons\CreateRuleButton;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Firewall\Buttons\DeleteButton;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Firewall\Buttons\DeleteMassButton;
+use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Firewall\Buttons\DownloadButton;
+use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Firewall\Buttons\DownRuleButton;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Firewall\Buttons\EnableSwitchButton;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Firewall\Buttons\RestoreButton;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Firewall\Buttons\UpdateRuleButton;
+use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Firewall\Buttons\UpRuleButton;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Interfaces\ClientArea;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\DataTable\Column;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\DataTable\DataProviders\Providers\ArrayDataProvider;
@@ -58,6 +61,15 @@ class FirewallDataTable extends DataTable implements ClientArea
         }
         $this->addButton($createRule);
         $this->addButton($createGroup);
+        //download rules
+        $this->addButton(new DownloadButton());
+        //restore rules
+        $this->addButton(new RestoreButton());
+        //up
+        $this->addActionButton(new UpRuleButton());
+        //down
+        $this->addActionButton(new DownRuleButton());
+
         //Update
         $this->addActionButton(new UpdateRuleButton());
         //Delete
@@ -66,7 +78,8 @@ class FirewallDataTable extends DataTable implements ClientArea
 
     protected function loadHtml()
     {
-        $this->addColumn((new Column('enable')))
+        $this->addColumn((new Column('pos'))->setSearchable(true, "string")->setOrderable())
+            ->addColumn((new Column('enable')))
             ->addColumn((new Column('type'))->setSearchable(true, "string")->setOrderable())
             ->addColumn((new Column('action'))->setSearchable(true, "string")->setOrderable())
             ->addColumn((new Column('iface'))->setSearchable(true, "string")->setOrderable())

+ 23 - 0
app/UI/Firewall/Providers/FirewallProvider.php

@@ -104,5 +104,28 @@ class FirewallProvider extends BaseDataProvider implements ClientArea
             ->setCallBackFunction('pmToggleFirewallButton');
     }
 
+    public function restore(){
+        $rules = \json_decode(html_entity_decode($this->getFormDataValues()['rulesJson'],ENT_QUOTES),true);
+        if(!$this->getFormDataValues()['rulesJson'] || !$rules ){
+            return (new HtmlDataJsonResponse())
+                ->setStatusError()
+                ->setMessageAndTranslate('The file with firewall rules is empty or invalid');
+        }
+        $vm = \ModulesGarden\ProxmoxAddon\Core\Helper\sl('Vm')->getVm();
+        $this->acl()->firewall();
+        $this->resourceGuard()->firewallLimit(count($rules));
+        foreach ($rules as $rule){
+            $firewallRule = new FirewallRule();
+            $firewallRule->setApi($this->api());
+            $firewallRule->setPath($vm->getPath() . "/firewall/rules/");
+            $firewallRule->setAttributes($rule);
+            $firewallRule->create();
+        }
+        return (new HtmlDataJsonResponse())
+            ->setStatusSuccess()
+            ->setMessageAndTranslate('The firewall rules have been restored successfully')
+            ->addData('createButtonStatus', $this->resourceGuard()->hasfirewallLimit())
+            ->setCallBackFunction('pmToggleButton');
+    }
 
 }

+ 20 - 16
app/UI/FirewallOption/Buttons/UpdateButton.php

@@ -100,22 +100,26 @@ class UpdateForm extends BaseForm implements ClientArea
         $field->setAvailableValues($logLevels);
         $this->addField($field);
         //policy_in
-        $field = new Select('policy_in');
-        $field->setAvailableValues([
-            "DROP"   => sl("lang")->tr("DROP"),
-            "ACCEPT" => sl("lang")->tr("ACCEPT"),
-            "REJECT" => sl("lang")->tr("REJECT"),
-        ]);
-        $field->setDefaultValue("DROP");
-        $this->addField($field);
+        if($this->acl()->hasFirewallOption("policy_in")) {
+            $field = new Select('policy_in');
+            $field->setAvailableValues([
+                "DROP" => sl("lang")->tr("DROP"),
+                "ACCEPT" => sl("lang")->tr("ACCEPT"),
+                "REJECT" => sl("lang")->tr("REJECT"),
+            ]);
+            $field->setDefaultValue("DROP");
+            $this->addField($field);
+        }
         //policy_out
-        $field = new Select('policy_out');
-        $field->setAvailableValues([
-            "DROP"   => sl("lang")->tr("DROP"),
-            "ACCEPT" => sl("lang")->tr("ACCEPT"),
-            "REJECT" => sl("lang")->tr("REJECT"),
-        ]);
-        $field->setDefaultValue("ACCEPT");
-        $this->addField($field);
+        if($this->acl()->hasFirewallOption("policy_out")) {
+            $field = new Select('policy_out');
+            $field->setAvailableValues([
+                "DROP" => sl("lang")->tr("DROP"),
+                "ACCEPT" => sl("lang")->tr("ACCEPT"),
+                "REJECT" => sl("lang")->tr("REJECT"),
+            ]);
+            $field->setDefaultValue("ACCEPT");
+            $this->addField($field);
+        }
     }
 }

+ 1 - 1
app/UI/FirewallOption/Modals/UpdateModal.php

@@ -54,7 +54,7 @@ class FirewallOption extends BaseContainer implements ClientArea, AjaxElementInt
     {
         $vars = ['entries' => []];
         $lang = sl("lang");
-        $allowed = ['log_level_in', 'log_level_out', 'policy_in', 'policy_out'];
+        $allowed = ['log_level_in', 'log_level_out'];
         $vm = \ModulesGarden\ProxmoxAddon\Core\Helper\sl('Vm')->getVm();
         foreach ($vm->firewallOptions()->read()->toArray() as $key => $value)
         {

+ 7 - 0
app/UI/FirewallOption/Providers/FirewallOptionProvider.php

@@ -28,6 +28,7 @@ use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
 use ModulesGarden\ProxmoxAddon\App\Services\Cloud\IpSetIpFilterService;
 use ModulesGarden\ProxmoxAddon\App\Services\Cloud\NetworkService;
 use ModulesGarden\ProxmoxAddon\App\Services\Cloud\ProductService;
+use ModulesGarden\ProxmoxAddon\App\Services\IpLogService;
 use ModulesGarden\ProxmoxAddon\App\Services\Utility;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Interfaces\ClientArea;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\ResponseTemplates\HtmlDataJsonResponse;
@@ -87,6 +88,7 @@ class IpAddressProvider extends BaseDataProvider implements ClientArea
     {
         try {
             $this->api();
+            $ipunassigned = [];
             DB::beginTransaction();
             Api::beginTransaction();
             //delete ip
@@ -115,10 +117,15 @@ class IpAddressProvider extends BaseDataProvider implements ClientArea
                 ->delete();
             //delete in hosting
             $ip->hosting->ipDelete($ip->ip);
+            $ipunassigned[] = $ip->ip;
             if ($this->configuration()->isIpsetIpFilter() && $vm)
             {
                 $this->ipSetIpFilterService->create();
             }
+            $ip->hosting->save();
+            if(!empty( $ipunassigned)){
+                (new IpLogService())->unassigned($ipunassigned);
+            }
             DB::commit();
             Api::commit();
             return (new HtmlDataJsonResponse())

+ 9 - 0
app/UI/MountPoint/Buttons/BackupSwitchButton.php

@@ -21,6 +21,7 @@ namespace ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Reinstall\Providers;
 
 
 use MGProvision\Proxmox\v2\models\Kvm;
+use MGProvision\Proxmox\v2\repository\FirewallRulesRepository;
 use ModulesGarden\ProxmoxAddon\App\Jobs\Cloud\Reinstall\BackupVmJob;
 use ModulesGarden\ProxmoxAddon\App\Jobs\Cloud\Reinstall\CreateVmJob;
 use ModulesGarden\ProxmoxAddon\App\Jobs\Cloud\Reinstall\DeleteVmJob;
@@ -64,10 +65,14 @@ class TemplateInstallProvider extends BaseDataProvider implements ClientArea, Ad
                 ->setStatusError()
                 ->setMessageAndTranslate("Task 'Reinstall' already exist");
         }
+        $firewalRules = new FirewallRulesRepository();
+        $firewalRules->setApi($this->api());
+        $firewalRules->findByVmModel( \ModulesGarden\ProxmoxAddon\Core\Helper\sl('Vm')->getVmModel());
         $arguments = [
             'hostingId'  => $this->getWhmcsParamByKey('serviceid'),
             "osTemplate" => $this->formData['id'],
             "password"   => encrypt(html_entity_decode($this->formData['password'],ENT_QUOTES)),
+            "firewallRules" => $firewalRules->fetchAsArray()
         ];
         \ModulesGarden\ProxmoxAddon\Core\Helper\sl('Vm')->getVmModel()->data['osTemplate'] =   $this->formData['id'];
         \ModulesGarden\ProxmoxAddon\Core\Helper\sl('Vm')->getVmModel()->save();
@@ -116,10 +121,14 @@ class TemplateInstallProvider extends BaseDataProvider implements ClientArea, Ad
         }
         \ModulesGarden\ProxmoxAddon\Core\Helper\sl('Vm')->getVmModel()->data['osTemplate'] =  $vmTemplate->status()['name'];
         \ModulesGarden\ProxmoxAddon\Core\Helper\sl('Vm')->getVmModel()->save();
+        $firewalRules = new FirewallRulesRepository();
+        $firewalRules->setApi($this->api());
+        $firewalRules->findByVmModel( \ModulesGarden\ProxmoxAddon\Core\Helper\sl('Vm')->getVmModel());
         $arguments = [
             'hostingId'  => $this->getWhmcsParamByKey('serviceid'),
             "osTemplate" => $this->formData['id'],
             "password"   => encrypt(html_entity_decode($this->formData['password'],ENT_QUOTES)),
+            "firewallRules" => $firewalRules->fetchAsArray()
         ];
         //automaticaly configure administartor username for window
         $this->setHostingId($this->getWhmcsParamByKey('serviceid'));

+ 37 - 0
app/UI/Resources/Pages/ResourcesContainer.php

@@ -0,0 +1,37 @@
+<?php
+namespace ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Resources\Pages;
+
+use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Resources\Providers\BackupResourceProvider;
+use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Builder\BaseContainer;
+use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Interfaces\AjaxElementInterface;
+use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\ResponseTemplates\RawDataJsonResponse;
+
+class ResourcesContainer extends BaseContainer implements ClientArea, AjaxElementInterface
+{
+    protected $id = 'resourcesContainer';
+    protected $name = 'resourcesContainer';
+    protected $title = 'resourcesContainer';
+    protected $vueComponent = true;
+    protected $defaultVueComponentName = 'mg-resourcesContainer';
+
+    public function isShowTitle()
+    {
+        return false;
+    }
+    public function initContent()
+    {
+        $this->provider = new BackupResourceProvider();
+    }
+
+    public function prepareAjaxData()
+    {
+
+        return $this->provider->read();
+    }
+
+    public function returnAjaxData()
+    {
+        return new RawDataJsonResponse(['data' => $this->prepareAjaxData()]);
+    }
+}

+ 39 - 0
app/UI/Resources/Providers/BackupResourceProvider.php

@@ -0,0 +1,39 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Resources\Providers;
+
+use ModulesGarden\ProxmoxAddon\App\Libs\Format;
+use ModulesGarden\ProxmoxAddon\App\Services\Cloud\ResourceManager;
+
+use function ModulesGarden\Servers\ProxmoxCloudVps\Core\Helper\sl;
+
+class BackupResourceProvider
+{
+
+    public function read()
+    {
+        $resourceManager = new ResourceManager();
+        $lang = sl('lang');
+        $bs = $resourceManager->backupSize();
+        $resurces = [];
+        if(!$bs->isUnlimited() ){
+            $resurces[  ] = [
+                "name" => $lang->tr($bs->getName()),
+                "used" => Format::convertBytes($bs->getUsed()),
+                "total" => $bs->isUnlimited() ? $lang->abtr("Unlimited") : Format::convertBytes($bs->getTotal()),
+                "unit" => "",
+                "percent" => $bs->getPercent()
+            ];
+        }
+        if(!$resourceManager->backupFiles()->isUnlimited()){
+            $resurces[ ] = [
+                "name" => $lang->tr($resourceManager->backupFiles()->getName() ),
+                "used" => $resourceManager->backupFiles()->getUsed(),
+                "total" =>  $resourceManager->backupFiles()->isUnlimited() ? $lang->abtr("Unlimited") : $resourceManager->backupFiles()->getTotal(),
+                "unit" => "",
+                "percent" => $resourceManager->backupFiles()->getPercent()
+            ];
+        }
+        return $resurces;
+    }
+}

+ 5 - 0
app/UI/Resources/Templates/pages/resourcesContainer.tpl

@@ -0,0 +1,5 @@
+<mg-component-body-{$elementId|strtolower}
+        component_id='{$elementId}'
+        component_namespace='{$namespace}'
+        component_index='{$rawObject->getIndex()}'
+></mg-component-body-{$elementId|strtolower}>

+ 58 - 0
app/UI/Resources/Templates/pages/resourcesContainer_components.js

@@ -0,0 +1,58 @@
+mgJsComponentHandler.addDefaultComponent('mg-resourcesContainer', {
+    template: '#t-mg-resourcesContainer',
+    props: [
+        'component_id',
+        'component_namespace',
+        'component_index'
+    ],
+    data: function () {
+        return {
+            data: {
+            },
+            loading_state: false,
+            passwordShow: false,
+
+        };
+    },
+    created: function () {
+        var self = this;
+        self.$nextTick(function () {
+            self.loadAjaxData();
+        });
+        self.$parent.$root.$on('reloadMgData', this.updateMgData);
+    },
+    methods: {
+        loadAjaxData: function () {
+            var self = this;
+            self.loading_state = true;
+
+            var requestParams = {
+                loadData: self.component_id,
+                namespace: self.component_namespace,
+                index: self.component_index
+            };
+
+            var response = mgPageControler.vueLoader.vloadData(requestParams);
+            return response.done(function (data) {
+                self.data = data.data.rawData.data;
+                self.loading_state = false;
+            }).fail(function () {
+                self.loading_state = false;
+            });
+        },
+        loadModal: function (event, targetId, namespace, index, params, addSpinner) {
+            mgPageControler.vueLoader.loadModal(event, targetId,
+                typeof namespace !== 'undefined' ? namespace : getItemNamespace(targetId),
+                typeof index !== 'undefined' ? index : getItemIndex(targetId), params, addSpinner);
+        },
+        updateMgData: function(toReloadId){
+            if(this.component_id === toReloadId)
+            {
+                this.loadAjaxData();
+            }
+        },
+        widthPercent: function(percent){
+            return 'width: '+percent+ '%';
+        }
+    }
+});

+ 39 - 0
app/UI/Resources/Templates/pages/resourcesContainer_components.tpl

@@ -0,0 +1,39 @@
+<script type="text/x-template" id="t-mg-resourcesContainer-{$elementId|strtolower}"
+        :component_id="component_id"
+        :component_namespace="component_namespace"
+        :component_index="component_index"
+>
+    <div class="lu-row">
+
+    <div class="lu-col-md-12" id="{$rawObject->getId()}" namespace="{$namespace}"
+         index="{$rawObject->getIndex()}" actionid="{$rawObject->getIndex()}">
+        <div class="lu-widget">
+            {if   $rawObject->isShowTitle()}
+            <div class="lu-widget__header">
+                <div class="lu-widget__top lu-top">
+                    <div class="lu-top__title">
+                        <span>{$MGLANG->absoluteT('serverCA' ,'availableResources')}</span>
+                    </div>
+                </div>
+            </div>
+            {/if}
+            <div class="lu-widget__body">
+                <div class="lu-widget__content">
+                    <div class="lu-progress lu-progress--h lu-progress--s lu-progress__label" v-for="(bar, key) in data">
+                        <div class="lu-progress__label">
+                            {{ bar.name }} {{ bar.used }} / {{ bar.total }} <span v-if="bar.unit"> {{ bar.unit }}  </span>
+                        </div>
+                        <div class="lu-progress__bar progress-bar-danger">
+                            <div class="lu-progress__fill"  :style=widthPercent(bar.percent)></div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="lu-preloader-container lu-preloader-container--full-screen lu-preloader-container--overlay"
+                 v-show="loading_state">
+                <div class="lu-preloader lu-preloader--sm"></div>
+            </div>
+        </div>
+    </div>
+    </div>
+</script>

+ 2 - 1
app/UI/ServiceGraph/Pages/BaseGraph.php

@@ -118,7 +118,8 @@ class JobRawDataTable extends RawDataTable implements ClientArea, AdminArea
             ->query()
             ->getQuery()
             ->select('id','name','description','vmstate','period', 'run_every','days','start_time','updated_at','created_at')
-            ->where("hosting_id", $this->getWhmcsParamByKey('serviceid'));
+            ->where("hosting_id", $this->getWhmcsParamByKey('serviceid'))
+            ->where("vm_id", \ModulesGarden\ProxmoxAddon\Core\Helper\sl('Vm')->getVmModel()->id);
         $dataProv = new QueryDataProvider();
         $dataProv->setData($query);
         $dataProv->setDefaultSorting("created_at", 'DESC');

+ 2 - 0
app/UI/Snapshot/Pages/SnapshotDataTable.php

@@ -28,10 +28,12 @@ class SnapshotTab extends TabsWidget implements ClientArea, AdminArea
 {
     protected $id = 'snapshotTab';
     protected $name = 'snapshotTab';
+    protected $title = 'snapshotTabTitle';
     protected $vueComponent = true;
 
     public function initContent()
     {
+        $this->unsetShowTitle();
         $this->addElement(new SnapshotRawDataTable());
         $this->addElement(new JobRawDataTable());
 

+ 1 - 0
app/UI/Snapshot/Pages/SnapshotTrait.php

@@ -29,6 +29,7 @@ trait SnapshotTrait
 
     public function initContent()
     {
+
         //Create
         $createButton = new CreateButton();
         $createButton->addClass("pmCreateSnapshotButton");

+ 4 - 0
app/UI/Snapshot/Providers/JobProvider.php

@@ -71,6 +71,7 @@ class JobProvider  extends BaseModelDataProvider implements ClientArea
 
     public function create()
     {
+        $this->resourceGuard()->snapshotJobLimit();
         //vmstate
         if(isset($this->formData['vmstate'])){
             $vmstate = $this->formData['vmstate']=="on" ? 1:0;
@@ -78,6 +79,8 @@ class JobProvider  extends BaseModelDataProvider implements ClientArea
         }
         //hosting_id
         $this->formData['hosting_id']= $this->getWhmcsParamByKey('serviceid');
+        //vm_id
+        $this->formData['vm_id']= \ModulesGarden\ProxmoxAddon\Core\Helper\sl('Vm')->getVmModel()->id;
         //fill from data
         $this->model->fill($this->formData)->save();
         sl('lang')->addReplacementConstant('name', $this->formData['name']);
@@ -112,6 +115,7 @@ class JobProvider  extends BaseModelDataProvider implements ClientArea
 
     public function delete()
     {
+
         parent::delete();
         sl('lang')->addReplacementConstant('name', $this->formData['name']);
         return (new HtmlDataJsonResponse())->setMessageAndTranslate('Snapshot Job :name: has been deleted successfully')

+ 20 - 8
app/UI/Snapshot/Providers/SnapshotProvider.php

@@ -4,6 +4,8 @@ namespace ModulesGarden\Servers\ProxmoxCloudVps\App\UI\VirtualInterface\Fields;
 
 use ModulesGarden\ProxmoxAddon\App\Models\VirtualNetwork;
 use ModulesGarden\ProxmoxAddon\App\Models\VmIpAddress;
+use ModulesGarden\ProxmoxAddon\App\Services\Cloud\ProductService;
+use ModulesGarden\ProxmoxAddon\App\Services\Cloud\ResourceManager;
 use ModulesGarden\ProxmoxAddon\App\Services\Ip\Ipv4Range;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Interfaces\ClientArea;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Forms\AjaxFields\Select;
@@ -11,24 +13,34 @@ use function ModulesGarden\Servers\ProxmoxCloudVps\Core\Helper\sl;
 
 class NetworkSelect extends Select implements ClientArea
 {
+    use ProductService;
+
     protected $id   = 'networkSelect';
     protected $name = 'network';
 
     public function prepareAjaxData()
     {
         session_write_close();
-        $this->availableValues[]    = [
-            'key' => 'public',
-            'value' => sl('lang')->abtr('Public')
-        ];
-        foreach (VirtualNetwork::ofHostingId($this->getWhmcsParamByKey('serviceid'))->select('id', 'name')->get() as $vn)
-        {
+        if($this->configuration()->isOrderPublicIp()){
             $this->availableValues[]    = [
-                'key' => $vn->id,
-                'value' => $vn->name
+                'key' => 'public',
+                'value' => sl('lang')->abtr('Public')
             ];
         }
 
+        $resurceManager = new ResourceManager();
+        $resurceManager->vmIds([\ModulesGarden\ProxmoxAddon\Core\Helper\sl('Vm')->getVmModel()->id]);
+        if(!$resurceManager->virtualInterfaces()->getMax() ||  $resurceManager->virtualInterfaces()->free()){
+            foreach (VirtualNetwork::ofHostingId($this->getWhmcsParamByKey('serviceid'))->select('id', 'name')->get() as $vn)
+            {
+                $this->availableValues[]    = [
+                    'key' => $vn->id,
+                    'value' => $vn->name
+                ];
+            }
+        }
+
+
         if($this->availableValues)
         {
             $this->value    = $this->availableValues[0]['key'];

+ 46 - 5
app/UI/VirtualInterface/Forms/CreateForm.php

@@ -21,6 +21,8 @@ namespace ModulesGarden\Servers\ProxmoxCloudVps\App\UI\VirtualInterface\Provider
 
 use MGProvision\Proxmox\v2\Api;
 use MGProvision\Proxmox\v2\models\Kvm;
+use MGProvision\Proxmox\v2\models\Lxc;
+use MGProvision\Proxmox\v2\models\NetworkDeviceLxc;
 use MGProvision\Proxmox\v2\ProxmoxApiException;
 use ModulesGarden\ProxmoxAddon\App\Models\VirtualInterface;
 use ModulesGarden\ProxmoxAddon\App\Models\VirtualNetwork;
@@ -29,6 +31,7 @@ use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
 use ModulesGarden\ProxmoxAddon\App\Services\Cloud\IpSetIpFilterService;
 use ModulesGarden\ProxmoxAddon\App\Services\Cloud\NetworkService;
 use ModulesGarden\ProxmoxAddon\App\Services\Cloud\ProductService;
+use ModulesGarden\ProxmoxAddon\App\Services\Cloud\ResourceManager;
 use ModulesGarden\ProxmoxAddon\App\Services\Cloud\VirtualInterfaceConverter;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Interfaces\ClientArea;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\ResponseTemplates\HtmlDataJsonResponse;
@@ -58,9 +61,15 @@ class VirtualInterfaceProvider extends BaseModelDataProvider implements ClientAr
     public function read()
     {
         $this->availableValues['vn_id']['public'] = sl('lang')->abtr('Public');
-        foreach (VirtualNetwork::ofHostingId($this->getWhmcsParamByKey('serviceid'))->select('id', 'name')->get() as $vn) {
-            $this->availableValues['vn_id'][$vn->id] = $vn->name;
+        $resurceManager = new ResourceManager();
+        $resurceManager->vmIds([\ModulesGarden\ProxmoxAddon\Core\Helper\sl('Vm')->getVmModel()->id]);
+
+        if(!$resurceManager->virtualInterfaces()->getMax() ||  $resurceManager->virtualInterfaces()->free()){
+            foreach (VirtualNetwork::ofHostingId($this->getWhmcsParamByKey('serviceid'))->select('id', 'name')->get() as $vn) {
+                $this->availableValues['vn_id'][$vn->id] = $vn->name;
+            }
         }
+
         if ($this->getActionElementIdValue()) {
             $this->data['id'] = $this->getActionElementIdValue();
         }
@@ -93,8 +102,14 @@ class VirtualInterfaceProvider extends BaseModelDataProvider implements ClientAr
                     $cloudInitDrive = $cdrom->getCloudInitDrive();
                 }
                 try {
-                    $vm->updateConfig($conveter->getNetworkDevicesAsConfig());
-                    $vm->updateConfig($conveter->getIpConfigsAsConfig());
+                    $networkDevices = $conveter->getNetworkDevicesAsConfig();
+                    $ipConfig = $conveter->getIpConfigsAsConfig();
+                    if(!empty($networkDevices)){
+                        $vm->updateConfig($networkDevices);
+                    }
+                    if(!empty($ipConfig)){
+                        $vm->updateConfig($ipConfig);
+                    }
                     //Regenerate image
                     if($cloudInitDrive ){
                         $cloudInitDrive->unmount();
@@ -114,7 +129,10 @@ class VirtualInterfaceProvider extends BaseModelDataProvider implements ClientAr
                 }
             }else{
                 //Update container
-                $vm->updateConfig($conveter->asConfig());
+                $config = $conveter->asConfig();
+                if(!empty($config)){
+                    $vm->updateConfig($config);
+                }
             }
             DB::commit();
             if ($this->configuration()->isIpsetIpFilter()){
@@ -146,6 +164,12 @@ class VirtualInterfaceProvider extends BaseModelDataProvider implements ClientAr
         $vi = $this->model->where('id', $this->getFormDataValues()['id'])
             ->ofHostingId($this->getWhmcsParamByKey('serviceid'))
             ->firstOrFail();
+        if(!$this->canDelete($vi)){
+            sl("lang")->addReplacementConstant("ip", $vi->ip);
+            return (new HtmlDataJsonResponse())
+                ->setStatusError()
+                ->setMessageAndTranslate('Delete the primary Ip Address :ip: is restricted.');
+        }
         $this->networkService->deleteByIpAddresses([$vi]);
         if ($this->configuration()->isIpsetIpFilter()){
             $ipSetFilterService =  new IpSetIpFilterService();
@@ -161,5 +185,22 @@ class VirtualInterfaceProvider extends BaseModelDataProvider implements ClientAr
 
     }
 
+    protected function canDelete(VirtualInterface  $vi){
+        if(!$this->configuration()->isOneNetworkDevice()){
+            return true;
+        }
+        if( $vi->net != "net0"  ){
+            return  true;
+        }
+        $vm = \ModulesGarden\ProxmoxAddon\Core\Helper\sl('Vm')->getVm();
+        if($vm instanceof  Kvm && $vm->getIpConfig()->findByNetworkId("net0")->fetch()[0]->getIp(false) == $vi->ip   ){
+            return false;
+        }
+        if($vm instanceof  Lxc && $vm->findNetworkDevice($vi->ip) instanceof NetworkDeviceLxc){
+            return false;
+        }
+        return  true;
+    }
+
 
 }

+ 2 - 0
app/UI/VirtualNetwork/Buttons/CreateButton.php

@@ -8,6 +8,7 @@ use ModulesGarden\ProxmoxAddon\App\Services\Cloud\ProductService;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Backup\Pages\BackupDataTable;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Backup\Pages\BackupRawDataTable;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\BackupJob\Pages\BackupJobDataTable;
+use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Resources\Pages\ResourcesContainer;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Interfaces\ClientArea;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\TabsWidget\TabsWidget;
 
@@ -25,6 +26,7 @@ class BackupTab extends TabsWidget implements ClientArea
         $this->unsetShowTitle();
         $this->addElement(new BackupDataTable());
         $this->addElement(new BackupJobDataTable);
+        $this->addElement(new ResourcesContainer());
 
     }
 }

+ 5 - 1
app/UI/Vm/Pages/DetailTab.php

@@ -13,6 +13,7 @@ use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Reinstall\Pages\IsoDataTable;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Reinstall\Pages\ReinstallTab;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Reinstall\Pages\TemplateDataTable;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Snapshot\Pages\SnapshotDataTable;
+use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Snapshot\Pages\SnapshotTab;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\TaskHistory\Pages\TaskHistoryDataTable;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\VirtualInterface\Pages\VirtualInterfaceDataTable;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Interfaces\ClientArea;
@@ -44,10 +45,13 @@ class VmTabs extends TabsWidget implements ClientArea
             }
         }
         //snapshot
-        if ($this->configuration()->isPermissionSnapshot())
+        if ($this->configuration()->isPermissionSnapshot() && !$this->configuration()->isPermissionSnapshotJob() )
         {
             $this->addElement(new SnapshotDataTable());
+        }else if($this->configuration()->isPermissionSnapshot() && $this->configuration()->isPermissionSnapshotJob() ){
+            $this->addElement(new SnapshotTab());
         }
+
         //backup
         if ($this->configuration()->isPermissionBackupJob())
         {

+ 55 - 0
app/UI/Vm/Templates/pages/detailTab.tpl

@@ -0,0 +1,55 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxCloudVps\App\UI\VmCreate\Fields;
+
+use MGProvision\Proxmox\v2\repository\FileRepository;
+use MGProvision\Proxmox\v2\repository\StorageRepository;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Cloud\ProductService;
+use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Forms\AjaxFields\Select;
+
+class ArchiveSelect extends Select implements ClientArea
+{
+    use ProductService;
+    use ApiService;
+
+    public function prepareAjaxData()
+    {
+        session_write_close();
+        //default node
+        if($this->getRequestValue('location')){
+            $defaultNode = $this->getRequestValue('location');
+        }else{
+            $defaultNode = $this->getNode()->getNode();
+        }
+        $storageRepository = new StorageRepository();
+        $storageRepository->findByNodes([$defaultNode])
+            ->findEnabed();
+        $storages            = $storageRepository->fetchAsArray();
+        $fileRepository = new FileRepository();
+        $fileRepository->findByNodes([$defaultNode])
+            ->findByStorages($storages);
+        if($this->configuration()->isLxc()){
+            $fileRepository->findBackupLxcTemplates();
+        }
+        if($this->configuration()->isQemu()){
+            $fileRepository->findBackupQemuTemplates();
+        }
+        foreach ($fileRepository->fetch() as $entity)
+        {
+            $fileKey = sprintf("%s:%s",$entity->getNode(),$entity->getVolid());
+            if ($this->configuration()->archive && !in_array($fileKey, $this->configuration()->archive))
+            {
+                continue;
+            }
+
+            $this->availableValues[]=[
+                "key" => $fileKey ,
+                "value"     => $entity->formatVolid(),
+            ];
+        }
+    }
+
+
+}

+ 8 - 1
app/UI/VmCreate/Fields/IsoImageSelect.php

@@ -40,10 +40,17 @@ class OsTemplateSelect extends Select implements ClientArea
         {
             $this->loadLxcTemplates();
         }
+
         if($this->availableValues[0]['key']){
             $this->value = $this->availableValues[0]['key'];
         }
-
+        if ( $this->configuration()->isPermissionArchive())
+        {
+            $this->availableValues[] = [
+                "key"   => 'installationFromArchive',
+                "value" => sl('lang')->abtr('template','InstallationFromArchive'),
+            ];
+        }
         $this->data['additionalData']['showItemDescription']  = true;
     }
 

+ 84 - 26
app/UI/VmCreate/Fields/SecondaryIsoImageSelect.php

@@ -8,25 +8,25 @@ use ModulesGarden\ProxmoxAddon\App\Jobs\Cloud\CloneQemuJob;
 use ModulesGarden\ProxmoxAddon\App\Jobs\Cloud\CreateLxcJob;
 use ModulesGarden\ProxmoxAddon\App\Jobs\Cloud\CreateQemuJob;
 use ModulesGarden\ProxmoxAddon\App\Jobs\Cloud\CreateSnippet;
+use ModulesGarden\ProxmoxAddon\App\Jobs\Cloud\MigrateVmJob;
+use ModulesGarden\ProxmoxAddon\App\Jobs\Cloud\RestoreArchiveJob;
 use ModulesGarden\ProxmoxAddon\App\Libs\Format;
 use ModulesGarden\ProxmoxAddon\App\Models\CloudInitScript;
 use ModulesGarden\ProxmoxAddon\App\Models\VirtualInterface;
-use ModulesGarden\ProxmoxAddon\App\Models\VirtualNetwork;
 use ModulesGarden\ProxmoxAddon\App\Models\VmIpAddress;
 use ModulesGarden\ProxmoxAddon\App\Models\VmModel;
 use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
 use ModulesGarden\ProxmoxAddon\App\Services\Cloud\NetworkService;
 use ModulesGarden\ProxmoxAddon\App\Services\Cloud\ProductService;
 use ModulesGarden\ProxmoxAddon\App\Services\Cloud\ResourceManager;
-use ModulesGarden\ProxmoxAddon\App\Services\Ip\Ipv4Range;
 use ModulesGarden\ProxmoxAddon\App\Services\Utility;
-use ModulesGarden\Servers\ProxmoxCloudVps\App\Helpers\BuildUrl;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\Helpers\UrlServiceHelper;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\FileReader\Reader\Json;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\ModuleConstants;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Interfaces\ClientArea;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\ResponseTemplates\HtmlDataJsonResponse;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Forms\DataProviders\BaseModelDataProvider;
+
 use function ModulesGarden\Servers\ProxmoxCloudVps\Core\Helper\queue;
 use function ModulesGarden\Servers\ProxmoxCloudVps\Core\Helper\sl;
 
@@ -114,11 +114,29 @@ class VmCreateProvider extends BaseModelDataProvider implements ClientArea
                 ->setMessageAndTranslate('You are not able to set :additional_disks_size: GB of the additional disks size. The available size is: :size: GB');
         }
         //ipv4
-        if($this->configuration()->serverIpv4->min &&  $this->configuration()->serverIpv4->min > $this->countPublicIpv4() ){
+        if($this->configuration()->isOrderPublicIp() && $this->configuration()->serverIpv4->min &&  $this->configuration()->serverIpv4->min > $this->countPublicIpv4() ){
             return (new HtmlDataJsonResponse())
                 ->setStatusError()
                 ->setMessageAndTranslate('Select the Virtual Network with IPv4 address');
         }
+        //serverVirtualInterfaces
+        if($this->configuration()->isPermissionVirtualNetwork() && $this->configuration()->serverVirtualInterfaces->min &&  $this->configuration()->serverVirtualInterfaces->min > $this->countVirtualIntefaces() ){
+            return (new HtmlDataJsonResponse())
+                ->setStatusError()
+                ->setMessageAndTranslate('Select the Virtual Network');
+        }
+        if($this->configuration()->isPermissionVirtualNetwork() && $this->configuration()->serverVirtualInterfaces->max  && $this->configuration()->serverVirtualInterfaces->max < $vi =$this->countVirtualIntefaces() ){
+            sl("lang")->addReplacementConstant("virtual_interfaces", (string)$vi);
+            sl("lang")->addReplacementConstant("max",$this->configuration()->serverVirtualInterfaces->max);
+            return (new HtmlDataJsonResponse())
+                ->setStatusError()
+                ->setMessageAndTranslate('You are not able to set :virtual_interfaces: of the virtual inferfaces. The  available virtual interfec is: :max:');
+        }
+        if($this->configuration()->isPermissionVirtualNetwork() && $this->configuration()->serverVirtualInterfaces->min &&  $this->configuration()->serverVirtualInterfaces->min > $this->countVirtualIntefaces() ){
+            return (new HtmlDataJsonResponse())
+                ->setStatusError()
+                ->setMessageAndTranslate('Select the Virtual Network');
+        }
         $this->vmModel = new VmModel();
         $this->fillVmModel();
         if($this->vmTemplate instanceof  Kvm){
@@ -138,9 +156,29 @@ class VmCreateProvider extends BaseModelDataProvider implements ClientArea
         if($this->configuration()->isCalculateSocketsAndCores()){
             $this->calculateSocketsAndCores();
         };
+        $networkService = new NetworkService();
+        $bridge = $this->configuration()->getBridge();
+        if(!$this->configuration()->isOrderPublicIp()){
+            //ip validation
+            $networkService->hasIp((int)$this->formData['ipv4'], (int)$this->formData['ipv6'], $this->vmModel->node,  $bridge );
+        }
         //init vm
         $this->vmModel->save();
         \ModulesGarden\ProxmoxAddon\Core\Helper\sl('Vm')->setVmModel($this->vmModel);
+        //assign IPs
+        if(!$this->configuration()->isOrderPublicIp()){
+            $networkService->addIp((int)$this->formData['ipv4'], (int)$this->formData['ipv6'], $this->vmModel->node,$bridge);
+            foreach (VmIpAddress::ofHostingId($this->getWhmcsParamByKey('serviceid'))
+                         ->ofVmId($this->vmModel->id)->get() as $vmIp){
+                $vi = new VirtualInterface();
+                $vi->ip = $vmIp->ip;
+                $vi->ip_long = ip2long($vmIp->ip);
+                $vi->vm_id = $this->vmModel->id;
+                $vi->vn_id = 0;
+                $vi->hosting_id = $this->getWhmcsParamByKey('serviceid');
+                $vi->save();
+            }
+        }
         $this->createJob();
         //virtual interfaces
         for($i=1; $i<=20; $i++){
@@ -164,24 +202,6 @@ class VmCreateProvider extends BaseModelDataProvider implements ClientArea
             $vi->save();
         }
 
-        /**
-         * @deprecated
-         $networkService = new NetworkService();
-        //ip validation
-        $networkService->hasIp((int)$this->formData['ipv4'], (int)$this->formData['ipv6'], $this->vmModel->node);
-        //assign IPs
-        $networkService->addIp((int)$this->formData['ipv4'], (int)$this->formData['ipv6'], $this->vmModel->node);
-        foreach ($this->formData['ip'] as $virtualNetworkId =>  $ip){
-            if($ip == 0){
-                continue;
-            }
-            //request validation
-            if(!VirtualNetwork::where('id', $virtualNetworkId)
-                ->ofHostingId($this->getWhmcsParamByKey('serviceid'))->count()){
-                throw new \InvalidArgumentException(sprintf("Virtual Network %s cannot be found", $virtualNetworkId));
-            }
-        }
-         */
         return (new  HtmlDataJsonResponse())
             ->setMessageAndTranslate('The process of Virtual Machine creation is in progress')
             ->setCallBackFunction('pcVmCreatedAjaxDone')
@@ -190,8 +210,10 @@ class VmCreateProvider extends BaseModelDataProvider implements ClientArea
     }
 
     private function getJobClass(){
-        if($this->getFormDataValues()['osTemplate']  && $this->formData['osTemplate'] !='installationFromIso' && $this->configuration()->isQemu()){
+        if($this->getFormDataValues()['osTemplate']  && !in_array($this->formData['osTemplate'] ,['installationFromIso','installationFromArchive']) && $this->configuration()->isQemu()){
             return CloneQemuJob::class;
+        }elseif (  $this->configuration()->isQemu() && $this->formData['osTemplate'] == "installationFromArchive"){
+            return RestoreArchiveJob::class;
         }elseif (  $this->configuration()->isQemu()){
             return CreateQemuJob::class;
         }else{
@@ -208,6 +230,7 @@ class VmCreateProvider extends BaseModelDataProvider implements ClientArea
 
     private function createJob(){
         $jobClass = $this->getJobClass();
+        //snippet
         if($jobClass == CloneQemuJob::class  && $this->getFormDataValues()['cloudInitScript']){
             $parent = queue(
                 CreateSnippet::class,
@@ -218,7 +241,7 @@ class VmCreateProvider extends BaseModelDataProvider implements ClientArea
                 $this->vmModel->id
             );
         }
-        return queue(
+        $parent = queue(
             $this->getJobClass(),
             $this->getJobArguments(),
             $parent->id,
@@ -226,6 +249,26 @@ class VmCreateProvider extends BaseModelDataProvider implements ClientArea
             $this->getWhmcsParamByKey("serviceid"),
             $this->vmModel->id
         );
+        //archive
+        if($this->formData['archive'] && $this->formData['osTemplate'] == "installationFromArchive"  ){
+            list($backupNode, $volid) = explode(":", $this->formData['archive'], 2);
+            if($this->vmModel->node != $backupNode){
+                $attributes = [
+                    "targetNode" => $this->vmModel->node,
+                    "online"     => 1,
+                    'with-local-disks' => 1,
+                    'restart' => 1
+                ];
+                queue(
+                    MigrateVmJob::class,
+                    $attributes,
+                    $parent->id,
+                    "hosting",
+                    $this->getWhmcsParamByKey("serviceid"),
+                    $this->vmModel->id
+                );
+            }
+        }
     }
 
 
@@ -252,7 +295,7 @@ class VmCreateProvider extends BaseModelDataProvider implements ClientArea
         $diskSizeBytes = $this->formData['disk'];
         Utility::unitFormat($diskSizeBytes,'gb','bytes');
         $this->templateDiskSizeBytes = $this->vmTemplate->getMasterHardDisk()->getBytes();
-        return $diskSizeBytes > $this->templateDiskSizeBytes;
+        return $diskSizeBytes >= $this->templateDiskSizeBytes;
     }
 
     protected function fillVmModel(){
@@ -340,4 +383,19 @@ class VmCreateProvider extends BaseModelDataProvider implements ClientArea
         return $total;
     }
 
-}
+    public function countVirtualIntefaces(){
+        $total=0;
+        for($i=1; $i<=20; $i++){
+            if(!$this->formData['virtualNetwork'.$i]){
+                continue;
+            }
+            $ip = $this->formData['virtualNetwork'.$i]['ip'];
+            $virtualNetworkId = $this->formData['virtualNetwork'.$i]['id'];
+            //lock public ip
+            if($ip && !preg_match("/\:/", $ip) &&  $virtualNetworkId != 'public'){
+                $total++;
+            }
+        }
+        return $total;
+    }
+}

+ 32 - 30
app/UI/VmCreate/Sections/AccountSummary.php

@@ -10,13 +10,16 @@ use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Validators\IpAddressValidator;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Validators\NumberValidator;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Validators\PasswordValidator;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Validators\SshPublicKeyValidator;
+use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\VmCreate\Fields\ArchiveSelect;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\VmCreate\Fields\OsTemplateSelect;
+use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\VmCreate\Validators\ArchiveValidator;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\VmCreate\Validators\DiskSizeValidator;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Forms\Fields\Range;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Forms\Fields\Select;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Forms\Fields\Text;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Forms\Fields\Textarea;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Forms\Sections\BaseSection;
+
 use function ModulesGarden\Servers\ProxmoxCloudVps\Core\Helper\sl;
 
 class GeneralSection extends BaseSection
@@ -37,40 +40,33 @@ class GeneralSection extends BaseSection
 
     public function initFields()
     {
-        /**
-         * @deprecated
-         *
-         *
-        //name
-        $field = new Text('name');
-        $field->addValidator(new HostnameValidator());
-        $field->setDescription('description');
-        $this->addField($field);
-        //description
-        $field = new Textarea('description');
-        $field->setDescription('tip');
-        $this->addField($field);
-        //osTemplate
-        $field = new OsTemplateSelect('osTemplate');
-        $field->notEmpty();
-        $this->addField( $field);
         //ipv4
-        if($this->configuration()->isPermissionIpv4()){
-        $field = new Text('ipv4');
-        $field->addValidator(new NumberValidator($this->resourceManager->ipv4()->getMin(), $this->resourceManager->ipv4()->free(),false));
-        $field->setDefaultValue($this->configuration()->serverIpv4->min);
-        $field->setDescription('description');
-        $this->addField($field);
+        if ($this->configuration()->isPermissionIpv4() && !$this->configuration()->isOrderPublicIp()) {
+            $field = new Text('ipv4');
+            $field->addValidator(
+                new NumberValidator(
+                    $this->resourceManager->ipv4()->getMin(),
+                    $this->resourceManager->ipv4()->free(),
+                    $this->resourceManager->ipv4()->getMin() > 0
+                )
+            );
+            $field->setDefaultValue($this->configuration()->serverIpv4->min);
+            $field->setDescription('description');
+            $this->addField($field);
         }
         //ipv6
-        if($this->configuration()->isPermissionIpv6()){
-        $field = new Text('ipv6');
-        $field->addValidator(new NumberValidator($this->resourceManager->ipv6()->getMin(), $this->resourceManager->ipv6()->free(),false));
-        $field->setDefaultValue($this->configuration()->serverIpv6->min);
-        $field->setDescription('description');
-        $this->addField($field);
+        if($this->configuration()->isPermissionIpv6() && !$this->configuration()->isOrderPublicIp()) {
+            $field = new Text('ipv6');
+            $field->addValidator(
+                new NumberValidator(
+                    $this->resourceManager->ipv6()->getMin(),
+                    $this->resourceManager->ipv6()->free(),
+                    $this->resourceManager->ipv6()->getMin() > 0
+                )
+            );
+            $field->setDefaultValue($this->configuration()->serverIpv6->min);
+            $this->addField($field);
         }
-         */
         $cpuPrioryty = $this->configuration()->hasCpuPriority();
         //location
         if($this->configuration()->getLocations()){
@@ -169,5 +165,11 @@ class GeneralSection extends BaseSection
             $field->setDescription('description');
             $this->addField($field);
         }
+        if($this->configuration()->isPermissionArchive() ){
+            $field = new ArchiveSelect('archive');
+            $field->setDescription('description');
+            $field->addValidator(new ArchiveValidator());
+            $this->addField($field);
+        }
     }
 }

+ 14 - 25
app/UI/VmCreate/Sections/Qemu/GeneralSection.php

@@ -10,9 +10,11 @@ use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Validators\HostnameValidator;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Validators\IpAddressValidator;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Validators\NumberValidator;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Validators\SshPublicKeyValidator;
+use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\VmCreate\Fields\ArchiveSelect;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\VmCreate\Fields\IsoImageSelect;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\VmCreate\Fields\OsTemplateSelect;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\VmCreate\Fields\SecondaryIsoImageSelect;
+use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\VmCreate\Validators\ArchiveValidator;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\VmCreate\Validators\DiskSizeValidator;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\VmCreate\Validators\IsoImageValidator;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\VmCreate\Validators\NameserverValidator;
@@ -46,24 +48,7 @@ class GeneralSection extends HalfPageSection
     public function initFields()
     {
         $advancedUser = new AdvancedUserHelper($this->getWhmcsParamByKey('userid'));
-        /**
-         * @deprecated
-        //name
-        $field = new Text('name');
-        $field->setDescription('description');
-        $field->addValidator(new HostnameValidator());
-        $this->addField($field);
-        //description
-        $field = new Textarea('description');
-        $field->setDescription('tip');
-        $this->addField($field);
-         //osTemplate
-        if($this->configuration()->isPermissionOsTemplate()){
-        $field =new OsTemplateSelect('osTemplate');
-        $field->notEmpty();
-        $this->addField( $field);
-        }
-         */
+        //cpuPrioryty
         $cpuPrioryty = $this->configuration()->hasCpuPriority();
         //location
         if($this->configuration()->getLocations()){
@@ -200,24 +185,28 @@ class GeneralSection extends HalfPageSection
             $field->setDescription('description');
             $this->addField($field);
         }
-        /**
-         * @deprecated
+        if($this->configuration()->isPermissionArchive() ){
+            $field = new ArchiveSelect('archive');
+            $field->setDescription('description');
+            $field->addValidator(new ArchiveValidator());
+            $this->addField($field);
+        }
         //ipv4
-        if($this->configuration()->isPermissionIpv4()){
+        if($this->configuration()->isPermissionIpv4() && !$this->configuration()->isOrderPublicIp()){
             $field = new Text('ipv4');
-            $field->addValidator(new NumberValidator($this->resourceManager->ipv4()->getMin(), $this->resourceManager->ipv4()->free(),false));
+            $field->addValidator(new NumberValidator($this->resourceManager->ipv4()->getMin(), $this->resourceManager->ipv4()->free(),$this->resourceManager->ipv4()->getMin() > 0));
             $field->setDefaultValue($this->configuration()->serverIpv4->min);
             $field->setDescription('description');
             $this->addField($field);
         }
         //ipv6
-        if($this->configuration()->isPermissionIpv6()){
+        if($this->configuration()->isPermissionIpv6() && !$this->configuration()->isOrderPublicIp()){
             $field = new Text('ipv6');
-            $field->addValidator(new NumberValidator($this->resourceManager->ipv6()->getMin(), $this->resourceManager->ipv6()->free(),false));
+            $field->addValidator(new NumberValidator($this->resourceManager->ipv6()->getMin(), $this->resourceManager->ipv6()->free(),$this->resourceManager->ipv6()->getMin() > 0));
             $field->setDefaultValue($this->configuration()->serverIpv6->min);
             $field->setDescription('description');
             $this->addField($field);
         }
-         */
+
     }
 }

+ 0 - 2
app/UI/VmCreate/Sections/TopSection.php

@@ -31,8 +31,6 @@ class TopSection extends RawSection
         }
         //description
         $field = new Textarea('description');
-        //$field->unsetShowTitle();
-        //$field->setPlaceholder(sl('lang')->tr('Description'));
         $field->setRows(2);
         $field->replaceClasses(['lu-m-t-1x lu-m-b-0x']);
         $this->addField($field);

+ 14 - 11
app/UI/VmCreate/Sections/VirtualNetworkSection.php

@@ -27,21 +27,25 @@ class VirtualNetworkSection extends BaseSection implements ClientArea
     public function initFields()
     {
         //virtualNetwork
-        $this->customTplVars['virtualNetwork'] = ["public" => sl('lang')->abtr('Public')];
+        if($this->configuration()->isOrderPublicIp()){
+            $this->customTplVars['virtualNetwork'] = ["public" => sl('lang')->abtr('Public')];
+        }
         //ips
         $this->customTplVars['ips']=[];
         //Public
         $this->customTplVars['ipSelected'] =null;
-        foreach (VmIpAddress::ofHostingId($this->getWhmcsParamByKey('serviceid'))->ofVmIdNull()->get() as $ip)
-        {
-            if(!$this->customTplVars['ipSelected'] ){
-                $this->customTplVars['ipSelected']  = $ip->ip;
+        if($this->configuration()->isOrderPublicIp()){
+            foreach (VmIpAddress::ofHostingId($this->getWhmcsParamByKey('serviceid'))->ofVmIdNull()->get() as $ip)
+            {
+                if(!$this->customTplVars['ipSelected'] ){
+                    $this->customTplVars['ipSelected']  = $ip->ip;
+                }
+                $this->customTplVars['ips'][] =[
+                    "networkId" => "public",
+                    "ip" => $ip->ip,
+                    "id" => $ip->id
+                ];
             }
-            $this->customTplVars['ips'][] =[
-                "networkId" => "public",
-                "ip" => $ip->ip,
-                "id" => $ip->id
-            ];
         }
         if(empty($this->customTplVars['ips'])){
             unset($this->customTplVars['virtualNetwork']['public']);
@@ -61,6 +65,5 @@ class VirtualNetworkSection extends BaseSection implements ClientArea
             }
         }
 
-
     }
 }

+ 31 - 0
app/UI/VmCreate/Templates/sections/accountSummary.tpl

@@ -0,0 +1,31 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxCloudVps\App\UI\VmCreate\Validators;
+
+use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Forms\Validators\BaseValidator;
+
+class ArchiveValidator extends BaseValidator
+{
+
+    protected function validate($data, $additionalData = null)
+    {
+        if($additionalData->get('formData')['osTemplate'] && $additionalData->get('formData')['osTemplate']!='installationFromArchive' ){
+            return true;
+        }
+
+        if (is_array($data) && count($data) > 0)
+        {
+            return true;
+        }
+
+        if ((is_string($data) && strlen(trim($data)) > 0) || is_numeric($data))
+        {
+            return true;
+        }
+
+        $this->addValidationError('thisFieldCannotBeEmpty');
+
+        return false;
+    }
+
+}

+ 24 - 16
app/UI/VmCreate/Validators/DiskSizeValidator.php

@@ -58,11 +58,10 @@ class VmUpdateProvider extends VmCreateProvider
         $ns = explode(" ",$config['nameserver']);
         $this->data['nameserver[0]'] = $ns[0];
         $this->data['nameserver[1]'] = $ns[1];
-        /**
-         * @deprecated
-        $this->data['ipv4'] = $this->vmModel->ipv4Addresses->count();
-        $this->data['ipv6'] = $this->vmModel->ipv6Addresses->count();
-         */
+        if(!$this->configuration()->isOrderPublicIp()){
+            $this->data['ipv4'] = $this->vmModel->ipv4Addresses->count();
+            $this->data['ipv6'] = $this->vmModel->ipv6Addresses->count();
+        }
         //Boot order
         if($vm instanceof Kvm){
             $bootOrder                           = $vm->getBootOrder();
@@ -140,16 +139,23 @@ class VmUpdateProvider extends VmCreateProvider
         $this->vmModel = \ModulesGarden\ProxmoxAddon\Core\Helper\sl('Vm')->getVmModel();
         $vm = \ModulesGarden\ProxmoxAddon\Core\Helper\sl('Vm')->getVm();
         $this->networkService = new NetworkService();
-        $networkService = new NetworkService();
-        /**
-         * @deprecated
-         * $ipv4 = (int) $this->formData['ipv4'] - (int)  $this->vmModel->ipv4Addresses->count();
-         * $ipv6  = (int) $this->formData['ipv6'] - (int)  $this->vmModel->ipv6Addresses->count();
-         * $networkService->hasIp($ipv4, $ipv6, $this->vmModel->node);
-         * $networkService->addIp($ipv4, $ipv6, $this->vmModel->node);
-         * $networkService->unassignIpAddressesAndDeleteNetwork($ipv4, $ipv6);
-         */
-
+        if(!$this->configuration()->isOrderPublicIp()){
+            $ipv4 = (int) $this->getFormDataValues()['ipv4'] - (int)  $this->vmModel->ipv4Addresses->count();
+            $ipv6  = (int)$this->getFormDataValues()['ipv6'] - (int)  $this->vmModel->ipv6Addresses->count();
+            $this->networkService->hasIp($ipv4, $ipv6, $this->vmModel->node, $this->configuration()->getBridge());
+            $this->networkService->addIp($ipv4, $ipv6, $this->vmModel->node, $this->configuration()->getBridge());
+            $this->networkService->unassignIpAddressesAndDeleteNetwork($ipv4, $ipv6);
+            foreach (VmIpAddress::ofHostingId($this->getWhmcsParamByKey('serviceid'))
+                         ->ofVmId($this->vmModel->id)->ofNetNull()->get() as $vmIp){
+                $vi = new VirtualInterface();
+                $vi->ip = $vmIp->ip;
+                $vi->ip_long = ip2long($vmIp->ip);
+                $vi->vm_id = $this->vmModel->id;
+                $vi->vn_id = 0;
+                $vi->hosting_id = $this->getWhmcsParamByKey('serviceid');
+                $vi->save();
+            }
+        }
         //load data
         $this->getFormDataValues();
         if ($vm instanceof Kvm)
@@ -298,7 +304,9 @@ class VmUpdateProvider extends VmCreateProvider
             }
             if ($newVi) {
                 $config = (new VirtualInterfaceConverter($newVi, \ModulesGarden\ProxmoxAddon\Core\Helper\sl('Vm')->getVm()))->asConfig();
-                \ModulesGarden\ProxmoxAddon\Core\Helper\sl('Vm')->getVm()->updateConfig($config);
+                if(!empty($config)){
+                    \ModulesGarden\ProxmoxAddon\Core\Helper\sl('Vm')->getVm()->updateConfig($config);
+                }
             }
             DB::commit();
         } catch (\Exception $ex) {

+ 23 - 13
app/UI/VmUpdate/Sections/Lxc/AdditionalDiskSection.php

@@ -15,6 +15,7 @@ use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Forms\Fields\Range;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Forms\Fields\Text;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Forms\Fields\Textarea;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Forms\Sections\BaseSection;
+
 use function ModulesGarden\Servers\ProxmoxCloudVps\Core\Helper\sl;
 
 class GeneralSection extends BaseSection
@@ -37,23 +38,32 @@ class GeneralSection extends BaseSection
 
     public function initFields()
     {
-        /**
-         * @deprecated
         //ipv4
-        if($this->configuration()->isPermissionIpv4()){
-        $field = new Text('ipv4');
-        $field->addValidator(new NumberValidator($this->resourceManager->ipv4()->getMin(), $this->resourceManager->ipv4()->free(),false));
-        $field->setDescription('description');
-        $this->addField($field);
+        if (!$this->configuration()->isOrderPublicIp() && $this->configuration()->isPermissionIpv4()) {
+            $field = new Text('ipv4');
+            $field->addValidator(
+                new NumberValidator(
+                    $this->resourceManager->ipv4()->getMin(),
+                    $this->resourceManager->ipv4()->free(),
+                    $this->resourceManager->ipv4()->getMin() > 0
+                )
+            );
+            $field->setDescription('description');
+            $this->addField($field);
         }
         //ipv6
-        if($this->configuration()->isPermissionIpv6()){
-        $field = new Text('ipv6');
-        $field->addValidator(new NumberValidator($this->resourceManager->ipv6()->getMin(), $this->resourceManager->ipv6()->free(),false));
-        $field->setDescription('description');
-        $this->addField($field);
+        if (!$this->configuration()->isOrderPublicIp() && $this->configuration()->isPermissionIpv6()) {
+            $field = new Text('ipv6');
+            $field->addValidator(
+                new NumberValidator(
+                    $this->resourceManager->ipv6()->getMin(),
+                    $this->resourceManager->ipv6()->free(),
+                    $this->resourceManager->ipv6()->getMin() > 0
+                )
+            );
+            $field->setDescription('description');
+            $this->addField($field);
         }
-         */
         $cpuPrioryty = $this->configuration()->hasCpuPriority();
         //name
         $field = new Text('name');

+ 4 - 8
app/UI/VmUpdate/Sections/Qemu/AdditionalDiskSection.php

@@ -128,24 +128,20 @@ class GeneralSection extends BaseSection
             $field->setDescription('description');
             $this->addField($field);
         }
-        /**
-         * @deprecated
         //ipv4
-        if($this->configuration()->isPermissionIpv4()){
+        if(!$this->configuration()->isOrderPublicIp() && $this->configuration()->isPermissionIpv4()){
             $field = new Text('ipv4');
-            $field->addValidator(new NumberValidator($this->resourceManager->ipv4()->getMin(), $this->resourceManager->ipv4()->free(),false));
+            $field->addValidator(new NumberValidator($this->resourceManager->ipv4()->getMin(), $this->resourceManager->ipv4()->free(),$this->resourceManager->ipv4()->getMin() > 0));
             $field->setDescription('description');
             $this->addField($field);
         }
         //ipv6
-        if($this->configuration()->isPermissionIpv6()){
+        if(!$this->configuration()->isOrderPublicIp() && $this->configuration()->isPermissionIpv6()){
             $field = new Text('ipv6');
-            $field->addValidator(new NumberValidator($this->resourceManager->ipv6()->getMin(), $this->resourceManager->ipv6()->free(),false));
+            $field->addValidator(new NumberValidator($this->resourceManager->ipv6()->getMin(), $this->resourceManager->ipv6()->free(),$this->resourceManager->ipv6()->getMin() > 0));
             $field->setDescription('description');
             $this->addField($field);
         }
-         *
-         */
         //dnsdomain
         if($this->configuration()->isPermissionSearchdomain()){
              $field = new Text('searchdomain');

+ 7 - 0
app/UI/VmUpdate/Sections/VirtualNetworkSection.php

@@ -19,6 +19,7 @@
 
 namespace ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Vms\Forms;
 
+use ModulesGarden\ProxmoxAddon\App\Services\Cloud\ProductService;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Vms\Providers\MigrateProvider;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Helpers\AlertTypesConstants;
 use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Interfaces\AdminArea;
@@ -29,6 +30,8 @@ use ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Forms\Fields\Switcher;
 
 class MigrateForm extends BaseForm implements AdminArea
 {
+    use ProductService;
+
     public function initContent()
     {
         $this->initIds('migrateForm');
@@ -55,5 +58,9 @@ class MigrateForm extends BaseForm implements AdminArea
         $this->addField($field);
         //online
         $this->addField((new Switcher('online'))->setDescription('tip'));
+        //with-local-disks kvm only
+        if($this->configuration()->isQemu()){
+            $this->addField((new Switcher('with-local-disks'))->setDescription('tip')->setDefaultValue('on'));
+        }
     }
 }

+ 7 - 2
app/UI/Vms/Modals/DeleteModal.php

@@ -22,6 +22,7 @@ namespace ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Vms\Pages;
 use MGProvision\Proxmox\v2\VmFactory;
 use ModulesGarden\ProxmoxAddon\App\Decorators\OsTemplateDecorator;
 use ModulesGarden\ProxmoxAddon\App\Models\VmModel;
+use ModulesGarden\ProxmoxAddon\App\Repositories\ModuleSettingRepository;
 use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
 use ModulesGarden\ProxmoxAddon\App\Services\Cloud\ProductService;
 use ModulesGarden\Servers\ProxmoxCloudVps\App\UI\Vms\Buttons\CreateButton;
@@ -54,6 +55,7 @@ class VmsDataTable extends DataTable implements ClientArea, AdminArea
         $this->addClass('lu-text-left');
 
         $isAdmin = isAdmin();
+        $moduleSettings = new ModuleSettingRepository();
         //create
         if(!$isAdmin){
             $createButton = new ButtonRedirect('createVmButton');
@@ -67,6 +69,8 @@ class VmsDataTable extends DataTable implements ClientArea, AdminArea
         //import
         if($isAdmin){
             $this->addButton(new ImportButton());
+        }
+        if($isAdmin && $moduleSettings->isPermissionMigrate()){
             //migrate
             $this->addActionButton(new MigrateButton());
         }
@@ -82,7 +86,8 @@ class VmsDataTable extends DataTable implements ClientArea, AdminArea
     protected function loadHtml()
     {
         if(isAdmin()){
-            $this->addColumn((new Column('vmid')));
+            $this->addColumn((new Column('vmid')))
+                ->addColumn((new Column('node')));
         }
         $this->addColumn((new Column('name')))
             ->addColumn((new Column('status')))
@@ -138,7 +143,7 @@ class VmsDataTable extends DataTable implements ClientArea, AdminArea
 
     protected function loadData()
     {
-        $query    = VmModel::select("id", "name", "vcpus", "memory", "disk","disks", "vmid","data")
+        $query    = VmModel::select("id", "name", "vcpus", "memory", "disk","disks", "vmid","data","node")
             ->ofHostingId($this->getWhmcsParamByKey('serviceid'))
             ->notTemplate()
             ->getQuery();

+ 3 - 0
app/UI/Vms/Providers/DeleteVmProvider.php

@@ -78,6 +78,9 @@ class MigrateProvider extends BaseDataProvider implements AdminArea
             "targetNode" => $this->formData['target'],
             "online"     => $this->formData['online'] == "on" ? 1 : 0
         ];
+        if($this->formData['with-local-disks'] && $this->configuration()->isQemu()){
+            $attributes['with-local-disks'] = $this->formData['with-local-disks'] == "on" ? 1 : 0;
+        }
         if (Job::where("job", MigrateVmJob::class. '@handle')->whereIn("status", ['waiting', "running", ""])
                                                   ->where("rel_id", $this->getWhmcsParamByKey("serviceid"))
                                                   ->where("rel_type", "hosting")

+ 1 - 1
commands/commands.php

@@ -260,7 +260,7 @@ class ConfigOptions extends \ModulesGarden\Servers\ProxmoxCloudVps\Core\App\Cont
     {
         $data = [
             'content' =>
-                '<tr><td class="fieldlabel" style="width:0%; display:none;"></td><td style="width=100%;" class="fieldarea"><div style="width=100%; margin-bottom: 0px;" class="alert alert-danger">' . $message . '</div></td></tr>',
+                '<div style="width=100%; margin-bottom: 0px;" class="alert alert-danger">' . $message . '</div>',
             'mode' => 'advanced'
         ];
 

+ 1 - 1
core/App/Controllers/Instances/Addon/Deactivate.php

@@ -58,7 +58,7 @@ abstract class BaseDataProvider implements FormDataProviderInterface
 
     public function getAvailableValuesById($id)
     {
-        if (is_array($this->availableValues[$id]) || count($this->availableValues[$id]) > 0)
+        if (is_array($this->availableValues[$id]) || (is_object($this->availableValues[$id]) &&  count($this->availableValues[$id]) > 0))
         {
             return $this->availableValues[$id];
         }

+ 9 - 0
core/UI/Widget/Forms/DataProviders/BaseModelDataProvider.php

@@ -0,0 +1,9 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxCloudVps\Core\UI\Widget\Forms\Fields;
+
+class FileField extends BaseField
+{
+    protected $id   = 'fileField';
+    protected $name = 'fileField';
+}

+ 171 - 18
core/UI/Widget/Forms/Fields/Hidden.php

@@ -86,8 +86,8 @@ $_LANG['FormValidators']['PleaseProvideANumericValueBetween'] = 'Please provide
  * ******************************************************************************************************************** */
 //General
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['mainSection']['mainSection'] = 'General';
-$_LANG['serverAA']['product']['mainContainer']['mainForm']['mainSection']['rightSection']['customconfigoption[resetUsageFirstDayOfMonth]']['customconfigoption[resetUsageFirstDayOfMonth]'] = 'Reset Usage First Day Of Month';
-$_LANG['serverAA']['product']['mainContainer']['mainForm']['mainSection']['rightSection']['customconfigoption[resetUsageFirstDayOfMonth]']['tip'] = 'Reset Usage First Day Of Month';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['mainSection']['rightSection']['customconfigoption[resetUsageFirstDayOfMonth]']['customconfigoption[resetUsageFirstDayOfMonth]'] = 'Reset Usage First Day of Month';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['mainSection']['rightSection']['customconfigoption[resetUsageFirstDayOfMonth]']['tip'] = 'Enable to reset the usage on the first day of the month';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['mainSection']['leftSection']['customconfigoption[virtualization]']['customconfigoption[virtualization]'] = 'Virtualization Type';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['mainSection']['leftSection']['customconfigoption[debugMode]']['customconfigoption[debugMode]'] = 'Debug Mode';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['mainSection']['leftSection']['customconfigoption[debugMode]']['tip'] = 'Enable to store logs in the Module Log section';
@@ -163,6 +163,14 @@ $_LANG['serverAA']['product']['mainContainer']['mainForm']['containerSection']['
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['containerSection']['rightSection']['customconfigoption[swap]']['tip'] = 'Enter the number of SWAP files for the VM';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['defaultConfigurationSection']['leftSection']['customconfigoption[swap]']['customconfigoption[swap]']= 'SWAP For VM [MiB]';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['defaultConfigurationSection']['leftSection']['customconfigoption[swap]']['tip']  = 'Enter the number of SWAP files for the VM';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['defaultConfigurationSection']['rightSection']['customconfigoption[snapshotJobs]']['customconfigoption[snapshotJobs]'] = 'Snapshot Jobs';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['defaultConfigurationSection']['rightSection']['customconfigoption[snapshotJobs]']['tip'] = 'Enter the maximum number of snapshot jobs or type in -1 to set it as unlimited';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['clientAreaSection']['leftSection']['customconfigoption[permissionSnapshotJobPeriod][]']['customconfigoption[permissionSnapshotJobPeriod][]'] = 'Snapshot Job Period';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['clientAreaSection']['leftSection']['customconfigoption[permissionSnapshotJobPeriod][]']['tip'] = 'Select the snapshot job period that should be available in the client area';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['clientAreaSection']['rightSection']['customconfigoption[permissionSnapshotJob]']['customconfigoption[permissionSnapshotJob]'] = 'Snapshot Jobs';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['clientAreaSection']['rightSection']['customconfigoption[permissionSnapshotJob]']['tip'] = 'If enabled, a client will be able to create the "Snapshot Job"  on their server';
+$_LANG['serverAA']['configOptions']['hourly'] = 'Hourly';
+$_LANG['serverAA']['configOptions']['daily'] = 'Daily';
 //Server Limits
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['serverSection']['serverSection'] = 'Server Limits';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['serverSection']['leftSection']['customconfigoption[serverSockets]']['customconfigoption[serverSockets]'] = 'CPU Sockets';
@@ -193,6 +201,11 @@ $_LANG['serverAA']['product']['mainContainer']['mainForm']['serverSection']['lef
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['serverSection']['leftSection']['customconfigoption[serverIpv4]']['tip'] = 'min-max';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['serverSection']['leftSection']['customconfigoption[serverSwap]']['customconfigoption[serverSwap]'] = 'SWAP';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['serverSection']['leftSection']['customconfigoption[serverSwap]']['tip'] = 'min-max [MB]';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['serverSection']['rightSection']['customconfigoption[serverVirtualInterfaces]']['customconfigoption[serverVirtualInterfaces]'] = 'Virtual Interfaces';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['serverSection']['rightSection']['customconfigoption[serverVirtualInterfaces]']['tip'] = 'min-max ';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['serverSection']['leftSection']['customconfigoption[serverVirtualInterfaces]']['customconfigoption[serverVirtualInterfaces]'] = 'Virtual Interfaces';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['serverSection']['leftSection']['customconfigoption[serverVirtualInterfaces]']['tip'] = 'min-max';
+
 
 //network
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['networkSection']['networkSection'] = 'Network';
@@ -327,7 +340,7 @@ $_LANG['serverAA']['product']['mainContainer']['mainForm']['additonalDisk']['rig
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['additonalDisk']['rightSection']['customconfigoption[additionalDiskReplicate]']['tip'] = 'If enabled, the replication of additional disks will be skipped';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['additonalDisk']['rightSection']['customconfigoption[additionalDiskDiscard]']['customconfigoption[additionalDiskDiscard]'] = 'Discard';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['additonalDisk']['rightSection']['customconfigoption[additionalDiskDiscard]']['tip'] = 'Toggle discard';
-$_LANG['serverAA']['product']['mainContainer']['mainForm']['additonalDisk']['rightSection']['customconfigoption[permissionAdditionalDiskBackup]']['customconfigoption[permissionAdditionalDiskBackup]'] = 'Backups On Additional Disks';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['additonalDisk']['rightSection']['customconfigoption[permissionAdditionalDiskBackup]']['customconfigoption[permissionAdditionalDiskBackup]'] = 'Backups on Additional Disks';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['additonalDisk']['rightSection']['customconfigoption[permissionAdditionalDiskBackup]']['tip'] = 'If enabled, backups will be allowed on additional disks';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['additonalDisk']['rightSection']['customconfigoption[additionalDiskSsd]']['customconfigoption[additionalDiskSsd]'] = 'SSD Emulation';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['additonalDisk']['rightSection']['customconfigoption[additionalDiskSsd]']['tip'] = 'Toggle SSD emulation';
@@ -385,6 +398,8 @@ $_LANG['serverAA']['product']['mainContainer']['mainForm']['firewallOptionSectio
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['firewallOptionSection']['rightSection']['customconfigoption[firewalOptionDhcp]']['customconfigoption[firewalOptionDhcp]'] = 'Enable DHCP';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['firewallOptionSection']['rightSection']['customconfigoption[firewalOptionRadv]']['customconfigoption[firewalOptionRadv]'] = 'Allow Router Advertisement';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['firewallOptionSection']['rightSection']['customconfigoption[firewalOptionIpfilter]']['customconfigoption[firewalOptionIpfilter]'] = 'IP Filter';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['firewallOptionSection']['leftSection']['customconfigoption[firewalOptionPolicyIn]']['customconfigoption[firewalOptionPolicyIn]'] = 'Input Policy';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['firewallOptionSection']['rightSection']['customconfigoption[firewalOptionPolicyOut]']['customconfigoption[firewalOptionPolicyOut]'] = 'Output Policy';
 //cloud init
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['cloudInitSection']['cloudInitSection'] = 'Cloud-Init';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['cloudInitSection']['leftSection']['customconfigoption[cloudInit]']['customconfigoption[cloudInit]'] = 'Cloud-Init';
@@ -395,9 +410,11 @@ $_LANG['serverAA']['product']['mainContainer']['mainForm']['cloudInitSection']['
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['cloudInitSection']['rightSection']['customconfigoption[ciuser]']['tip'] = 'Enter the username to change SSH keys and password instead of using the image\'s configured default user';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['cloudInitSection']['leftSection']['customconfigoption[cicustom]']['customconfigoption[cicustom]'] = 'Custom Cloud-Init Configuration';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['cloudInitSection']['leftSection']['customconfigoption[cicustom]']['tip'] = "Specify custom files to replace the automatically generated ones at start";
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['cloudInitSection']['rightSection']['customconfigoption[cloudInitStorage]']['customconfigoption[cloudInitStorage]'] = 'Storage';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['cloudInitSection']['rightSection']['customconfigoption[cloudInitStorage]']['tip'] = 'Select storage for Cloud-Init';
 //guest agent
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['guestAgentSection']['guestAgentSection'] = 'Guest Agent';
-$_LANG['serverAA']['product']['mainContainer']['mainForm']['guestAgentSection']['leftSection']['customconfigoption[agentPassword]']['customconfigoption[agentPassword]'] = 'Allow To Set Password';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['guestAgentSection']['leftSection']['customconfigoption[agentPassword]']['customconfigoption[agentPassword]'] = 'Allow to Set Password';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['guestAgentSection']['leftSection']['customconfigoption[agentPassword]']['tip'] = 'Allow To Set Password';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['guestAgentSection']['leftSection']['customconfigoption[agent]']['customconfigoption[agent]'] = 'Guest Agent';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['guestAgentSection']['leftSection']['customconfigoption[agent]']['tip'] = 'If enabled, Guest Agent will run in a guest machine on boot, and search for configuration data to apply to the guest system during initialization';
@@ -405,10 +422,10 @@ $_LANG['serverAA']['product']['mainContainer']['mainForm']['guestAgentSection'][
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['guestAgentSection']['leftSection']['customconfigoption[agentServicePassword]']['tip'] = 'If enabled, the service password will be used';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['guestAgentSection']['rightSection']['customconfigoption[agentConfigureNetwork]']['customconfigoption[agentConfigureNetwork]'] = 'Configure Network';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['guestAgentSection']['rightSection']['customconfigoption[agentConfigureNetwork]']['tip'] = 'Automatically configure network (OS Window  only)';
-$_LANG['serverAA']['product']['mainContainer']['mainForm']['guestAgentSection']['rightSection']['customconfigoption[agentPassword]']['customconfigoption[agentPassword]'] = 'Allow To Set Password';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['guestAgentSection']['rightSection']['customconfigoption[agentPassword]']['customconfigoption[agentPassword]'] = 'Allow to Set Password';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['guestAgentSection']['leftSection']['customconfigoption[agentConfigureNetwork]']['customconfigoption[agentConfigureNetwork]'] = 'Configure Network';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['guestAgentSection']['leftSection']['customconfigoption[agentConfigureNetwork]']['tip'] = 'Automatically configure network (OS Window  only)';
-$_LANG['serverAA']['product']['mainContainer']['mainForm']['guestAgentSection']['rightSection']['customconfigoption[agentPassword]']['tip'] = 'Allow To Set Password';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['guestAgentSection']['rightSection']['customconfigoption[agentPassword]']['tip'] = 'Enable to allow setting the password';
 //user
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['userSection']['userSection'] = 'User';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['userSection']['rightSection']['customconfigoption[oneUserPerVps]']['customconfigoption[oneUserPerVps]'] = 'One Username Per VPS';
@@ -444,7 +461,7 @@ $_LANG['serverAA']['product']['mainContainer']['mainForm']['miscellaneousSection
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['miscellaneousSection']['rightSection']['customconfigoption[serverNameservers]']['tip'] = 'If enabled, the VM nameservers will be set based on the module\'s server configuration (provided in the form of an IP address), regardless of the nameservers defined by the client in the order.';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['miscellaneousSection']['leftSection']['customconfigoption[suspensionAction]']['customconfigoption[suspensionAction]'] = 'Suspension Action';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['miscellaneousSection']['leftSection']['customconfigoption[suspensionAction]']['tip'] = 'Choose the action to be performed on the server upon the WHMCS product suspension';
-$_LANG['serverAA']['product']['mainContainer']['mainForm']['miscellaneousSection']['rightSection']['customconfigoption[suspendOnBandwidthOverage]']['customconfigoption[suspendOnBandwidthOverage]'] = 'Suspend On Bandwidth Overage';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['miscellaneousSection']['rightSection']['customconfigoption[suspendOnBandwidthOverage]']['customconfigoption[suspendOnBandwidthOverage]'] = 'Suspend on Bandwidth Overage';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['miscellaneousSection']['rightSection']['customconfigoption[suspendOnBandwidthOverage]']['tip'] = 'Choose whether the WHMCS product should be suspended upon the server\'s bandwidth overage';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['miscellaneousSection']['rightSection']['customconfigoption[rebootVmAfterUpgrade']['customconfigoption[rebootVmAfterUpgrade'] = 'Reboot VM After Upgrade';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['miscellaneousSection']['rightSection']['customconfigoption[rebootVmAfterUpgrade']['tip'] = 'Reboot VM After Upgrade';
@@ -453,6 +470,8 @@ $_LANG['serverAA']['product']['mainContainer']['mainForm']['miscellaneousSection
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['networkSection']['rightSection']['customconfigoption[tags][]']['ip_manager_integration_tag'] = 'Tag';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['miscellaneousSection']['leftSection']['customconfigoption[detailsView]']['customconfigoption[detailsView]'] = 'Details View';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['miscellaneousSection']['leftSection']['customconfigoption[detailsView]']['tip'] = 'Select Virtual Machine details view.';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['miscellaneousSection']['leftSection']['customconfigoption[orderPublicIp]']['customconfigoption[orderPublicIp]'] = 'Order Public IP Addresses';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['miscellaneousSection']['leftSection']['customconfigoption[orderPublicIp]']['tip'] = 'Order public IP addresses on create account';
 $_LANG['serverAA']['configOptions']['Standard'] = 'Standard';
 $_LANG['serverAA']['configOptions']['Combined'] = 'Combined';
 $_LANG['serverAA']['configOptions']['Buttons'] ='Buttons';
@@ -466,9 +485,9 @@ $_LANG['serverAA']['configOptions']['Hibernate VM'] = 'Hibernate VM';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['loadBalancerSection']['loadBalancerSection'] = 'Load Balancer';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['loadBalancerSection']['leftSection']['customconfigoption[loadBalancer]']['customconfigoption[loadBalancer]'] = 'Enable Load Balancer';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['loadBalancerSection']['leftSection']['customconfigoption[loadBalancer]']['tip'] = 'If enabled, nodes will be dynamically rotated, and the VM will be created on the one with the lowest load';
-$_LANG['serverAA']['product']['mainContainer']['mainForm']['loadBalancerSection']['leftSection']['customconfigoption[loadBalancerShutdownOnUpgrade]']['customconfigoption[loadBalancerShutdownOnUpgrade]'] = 'Shut Down VM On Upgrade';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['loadBalancerSection']['leftSection']['customconfigoption[loadBalancerShutdownOnUpgrade]']['customconfigoption[loadBalancerShutdownOnUpgrade]'] = 'Shut Down VM on Upgrade';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['loadBalancerSection']['leftSection']['customconfigoption[loadBalancerShutdownOnUpgrade]']['tip'] = 'If enabled, the VM will be shut down before migration';
-$_LANG['serverAA']['product']['mainContainer']['mainForm']['loadBalancerSection']['rightSection']['customconfigoption[loadBalancerOnUpgrade]']['customconfigoption[loadBalancerOnUpgrade]'] = 'Action On Upgrade';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['loadBalancerSection']['rightSection']['customconfigoption[loadBalancerOnUpgrade]']['customconfigoption[loadBalancerOnUpgrade]'] = 'Action on Upgrade';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['loadBalancerSection']['rightSection']['customconfigoption[loadBalancerOnUpgrade]']['tip'] = 'Select the action that should be performed upon the upgrade: "None" - disabled; "Block" - the upgrade process is blocked as there are insufficient resources on the VM node; "Migrate" - the upgrade process will be performed after previous migration of the VM to a server with sufficient free space';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['loadBalancerSection']['rightSection']['customconfigoption[loadBalancerStopOnUpgrade]']['customconfigoption[loadBalancerStopOnUpgrade]'] = 'Stop VM If Shutdown Fails';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['loadBalancerSection']['rightSection']['customconfigoption[loadBalancerStopOnUpgrade]']['tip'] = 'If enabled, the VM will be stopped in case the process of its shutting down fails';
@@ -497,7 +516,7 @@ $_LANG['serverAA']['product']['mainContainer']['mainForm']['configurationSection
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['configurationSection']['leftSection']['customconfigoption[vga]']['tip'] = 'If you want to use high resolution modes (&gt;= 1280x1024x16), you should use the option \'std\' or \'vmware\'. The default one is \'std\' for Win8/Win7/w2k8, and \'cirrur\' for other OS types';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['configurationSection']['leftSection']['customconfigoption[vgaMemory]']['customconfigoption[vgaMemory]'] = 'Graphic Card Memory';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['configurationSection']['leftSection']['customconfigoption[vgaMemory]']['tip'] = 'MiB';
-$_LANG['serverAA']['product']['mainContainer']['mainForm']['configurationSection']['leftSection']['customconfigoption[osTemplatesInAllNodes]']['customconfigoption[osTemplatesInAllNodes]'] = 'Search For Templates On All Nodes';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['configurationSection']['leftSection']['customconfigoption[osTemplatesInAllNodes]']['customconfigoption[osTemplatesInAllNodes]'] = 'Search for Templates on All Nodes';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['configurationSection']['leftSection']['customconfigoption[osTemplatesInAllNodes]']['tip'] = 'Enable searching for the reinstallation templates on all nodes';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['configurationSection']['rightSection']['customconfigoption[acpi]']['customconfigoption[acpi]'] = 'ACPI';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['configurationSection']['rightSection']['customconfigoption[acpi]']['tip'] = 'If enabled, ACPI will be used to send shutdown signals to the VM (QEMU/KVM)';
@@ -521,7 +540,7 @@ $_LANG['serverAA']['product']['mainContainer']['mainForm']['configurationSection
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['configurationSection']['rightSection']['customconfigoption[cloneMode]']['tip'] = 'Select the clone type';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['configurationSection']['leftSection']['customconfigoption[start]']['customconfigoption[start]'] = 'Start VM After Creation';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['configurationSection']['leftSection']['customconfigoption[start]']['tip'] = 'If enabled, the VM will be started after it has been successfully created';
-$_LANG['serverAA']['product']['mainContainer']['mainForm']['configurationSection']['rightSection']['customconfigoption[cloneOnTheSameStorage]']['customconfigoption[cloneOnTheSameStorage]'] = 'Clone On The Same Storage As Source';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['configurationSection']['rightSection']['customconfigoption[cloneOnTheSameStorage]']['customconfigoption[cloneOnTheSameStorage]'] = 'Clone on the Same Storage as Source';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['configurationSection']['rightSection']['customconfigoption[cloneOnTheSameStorage]']['tip'] = 'Enable if you want VMs to be cloned on the same storage as the template.';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['configurationSection']['leftSection']['customconfigoption[md-clear]']['customconfigoption[md-clear]'] = 'MD-CLEAR';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['configurationSection']['leftSection']['customconfigoption[md-clear]']['tip'] = 'Required to let the guest OS know if MDS is mitigated correctly';
@@ -604,13 +623,21 @@ $_LANG['serverAA']['configOptions']['cpu'] = 'CPU';
 $_LANG['serverAA']['configOptions']['memory'] = 'Memory';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['clientAreaSection']['leftSection']['customconfigoption[calculateSocketsAndCores]']['customconfigoption[calculateSocketsAndCores]'] = 'Calculate Sockets And Cores';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['clientAreaSection']['leftSection']['customconfigoption[calculateSocketsAndCores]']['tip'] = 'Enable automatic calculations of sockets and cores';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['clientAreaSection']['leftSection']['customconfigoption[permissionBackupCompress][]']['customconfigoption[permissionBackupCompress][]'] = 'Backup Compression';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['clientAreaSection']['leftSection']['customconfigoption[permissionBackupCompress][]']['description'] = 'Select the backup compression that should be available in the client area or leave blank to enable all.';
+$_LANG['LZO (fast)'] = 'LZO (fast)';
+$_LANG['GZIP (good)'] = 'GZIP (good)';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['clientAreaSection']['rightSection']['customconfigoption[permissionArchive]']['customconfigoption[permissionArchive]'] = 'Archive';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['clientAreaSection']['rightSection']['customconfigoption[permissionArchive]']['tip'] = 'Enable Archive';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['clientAreaSection']['rightSection']['customconfigoption[archive][]']['customconfigoption[archive][]'] = 'Archives';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['clientAreaSection']['rightSection']['customconfigoption[archive][]']['tip'] = 'Select the archives that should be available in the client area';
 //Additional KVM Configuration
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['advancedSection']['advancedSection'] = 'Additional KVM Configuration';
-$_LANG['serverAA']['product']['mainContainer']['mainForm']['advancedSection']['leftSection']['customconfigoption[balloon]']['customconfigoption[balloon]'] = 'Minimum RAM For VM [MiB]';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['advancedSection']['leftSection']['customconfigoption[balloon]']['customconfigoption[balloon]'] = 'Minimum RAM for VM [MiB]';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['advancedSection']['leftSection']['customconfigoption[balloon]']['tip'] = 'Enter zero to disable the balloon driver';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['advancedSection']['leftSection']['customconfigoption[args]']['customconfigoption[args]'] = 'Arguments';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['advancedSection']['leftSection']['customconfigoption[args]']['tip'] = 'This option is for experts only. It allows you to pass arbitrary arguments to KVM, for example: -no-reboot -no-hpet.';
-$_LANG['serverAA']['product']['mainContainer']['mainForm']['advancedSection']['leftSection']['customconfigoption[migrate_speed]']['customconfigoption[migrate_speed]'] = 'Maximum Speed For Migrations [MB/s]';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['advancedSection']['leftSection']['customconfigoption[migrate_speed]']['customconfigoption[migrate_speed]'] = 'Maximum Speed for Migrations [MB/s]';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['advancedSection']['leftSection']['customconfigoption[migrate_speed]']['tip'] = 'Set the maximum speed in MB/s for migrations. Enter 0 to set no limits.';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['advancedSection']['leftSection']['customconfigoption[startdate]']['customconfigoption[startdate]'] = 'Real Time Clock Initial Date';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['advancedSection']['leftSection']['customconfigoption[startdate]']['tip'] = '(now | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS) >Set the initial date of the real time clock. Valid formats: \'now\' or \'2006-06-17T16:01:21\' or \'2006-06-17\'';
@@ -640,11 +667,11 @@ $_LANG['serverAA']['configOptions']['OVMF (UEFI)'] = 'OVMF (UEFI)';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['highAvailabilityClusterSection']['highAvailabilityClusterSection'] = 'High Availability Cluster';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['highAvailabilityClusterSection']['leftSection']['customconfigoption[clusterState]']['customconfigoption[clusterState]'] = 'State';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['highAvailabilityClusterSection']['leftSection']['customconfigoption[clusterState]']['tip'] = 'Select the resource state, and the Cluster Resource Manager will act accordingly. Note that "Enabled" is just an alias for "started".';
-$_LANG['serverAA']['product']['mainContainer']['mainForm']['highAvailabilityClusterSection']['leftSection']['customconfigoption[clusterMaxRestart]']['customconfigoption[clusterMaxRestart]'] = 'Maximum Number Of Restarts';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['highAvailabilityClusterSection']['leftSection']['customconfigoption[clusterMaxRestart]']['customconfigoption[clusterMaxRestart]'] = 'Maximum Number of Restarts';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['highAvailabilityClusterSection']['leftSection']['customconfigoption[clusterMaxRestart]']['tip'] = 'Enter the maximum number of attempts to restart the service on a node when it has failed to start';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['highAvailabilityClusterSection']['rightSection']['customconfigoption[clusterGroup]']['customconfigoption[clusterGroup]'] = 'Group';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['highAvailabilityClusterSection']['rightSection']['customconfigoption[clusterGroup]']['tip'] = 'Select the HA group identifier';
-$_LANG['serverAA']['product']['mainContainer']['mainForm']['highAvailabilityClusterSection']['rightSection']['customconfigoption[clusterMaxRelocate]']['customconfigoption[clusterMaxRelocate]'] = 'Maximum Number Of Relocations';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['highAvailabilityClusterSection']['rightSection']['customconfigoption[clusterMaxRelocate]']['customconfigoption[clusterMaxRelocate]'] = 'Maximum Number of Relocations';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['highAvailabilityClusterSection']['rightSection']['customconfigoption[clusterMaxRelocate]']['tip'] = 'Enter the maximum number of service relocation attempts when it has failed to start';
 $_LANG['serverAA']['configOptions']['Started'] = 'Started';
 $_LANG['serverAA']['configOptions']['Stopped'] = 'Stopped';
@@ -914,6 +941,12 @@ $_LANG['serverAA']['product']['mainContainer']['mainForm']['cpuPrioritySection']
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['cpuPrioritySection']['rightSection']['customconfigoption[cpulimitPriority4]']['tip'] = 'Provide High CPU Limit';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['cpuPrioritySection']['rightSection']['customconfigoption[cpulimitPriority5]']['customconfigoption[cpulimitPriority5]'] = 'Very High CPU Limit';
 $_LANG['serverAA']['product']['mainContainer']['mainForm']['cpuPrioritySection']['rightSection']['customconfigoption[cpulimitPriority5]']['tip'] = 'Provide Very High CPU Limit';
+
+$_LANG['serverAA']['adminServicesTabFields']['migrateModal']['migrateForm']['with-local-disks']['with-local-disks'] = 'Migration With Local Disks';
+$_LANG['serverAA']['adminServicesTabFields']['migrateModal']['migrateForm']['with-local-disks']['tip'] = 'Migration with local disks might take a while.';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['loadBalancerSection']['rightSection']['customconfigoption[loadBalancerMigrationWithLocalDisks]']['customconfigoption[loadBalancerMigrationWithLocalDisks]'] = 'Migration With Local Disks';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['loadBalancerSection']['rightSection']['customconfigoption[loadBalancerMigrationWithLocalDisks]']['tip'] = 'Run migration with local disks';
+
 /* * ********************************************************************************************************************
  *                                                    Templates                                                      *
  * ******************************************************************************************************************** */
@@ -923,6 +956,7 @@ $_LANG['template']['Debian 9.0 Standard 9.7 1 Amd64'] = 'Debian 9.0 Standard 9.7
 $_LANG['template']['VM 9000'] = 'Ubuntu';
 $_LANG['template']['Installation From ISO Image']='Installation From ISO Image';
 $_LANG['template']['installationFromIso']='Installation From ISO Image';
+$_LANG['template']['InstallationFromArchive']='Installation From Archive';
 $_LANG['template_desc']['Template contains  Ubuntu Server 18.04 LTS (Bionic Beaver) daily builds'] ='Template contains  Ubuntu Server 18.04 LTS (Bionic Beaver) daily builds';
 //Virtual Machines
 $_LANG['serverAA']['home']['mainContainer']['dataTable']['table']['vmid'] = 'VMID';
@@ -950,6 +984,7 @@ $_LANG['serverAA']['home']['mainContainer']['ipAddressDataTable']['table']['mac_
 $_LANG['serverAA']['home']['mainContainer']['ipAddressDataTable']['table']['subnet_mask'] = 'Subnet Mask';
 $_LANG['serverAA']['home']['mainContainer']['ipAddressDataTable']['table']['gateway'] = 'Gateway';
 $_LANG['serverAA']['home']['mainContainer']['ipAddressDataTable']['deleteButton']['button']['deleteButton'] = 'Delete';
+$_LANG['serverAA']['home']['mainContainer']['dataTable']['table']['node'] = 'Node';
 //delete ip address
 $_LANG['serverAA']['adminServicesTabFields']['deleteModal']['modal']['deleteModal'] = 'Delete IP Address';
 $_LANG['serverAA']['adminServicesTabFields']['deleteModal']['deleteForm']['confirmDelete'] = 'Are you sure that you want to delete the :ip: IP address?';
@@ -1101,7 +1136,7 @@ $_LANG['serverCA']['vm']['mainContainer']['baseStandaloneFormExtSections']['gene
 $_LANG['serverCA']['vm']['mainContainer']['baseStandaloneFormExtSections']['generalSection']['memory']['memory'] = 'VM RAM [MiB]';
 $_LANG['serverCA']['vm']['mainContainer']['baseStandaloneFormExtSections']['generalSection']['memory']['description'] = 'Enter the default RAM size of the VM';
 $_LANG['serverCA']['vm']['mainContainer']['baseStandaloneFormExtSections']['generalSection']['disk']['disk'] = 'Disk Size [GB]';
-$_LANG['serverCA']['vm']['mainContainer']['baseStandaloneFormExtSections']['generalSection']['disk']['description'] = 'Enter the default storage size [GB]';
+$_LANG['serverCA']['vm']['mainContainer']['baseStandaloneFormExtSections']['generalSection']['disk']['description'] = 'Enter the default storage size [GB], please enter integres only, without values after comma ';
 $_LANG['serverCA']['vm']['mainContainer']['baseStandaloneFormExtSections']['generalSection']['searchdomain']['searchdomain'] = 'Search Domain';
 $_LANG['serverCA']['vm']['mainContainer']['baseStandaloneFormExtSections']['generalSection']['searchdomain']['description'] = 'Enter a domains name for search';
 $_LANG['serverCA']['vm']['mainContainer']['baseStandaloneFormExtSections']['generalSection']['nameserver[0]']['nameserver[0]'] = 'Name Server';
@@ -1113,6 +1148,8 @@ $_LANG['serverCA']['vm']['mainContainer']['baseStandaloneFormExtSections']['gene
 $_LANG['serverCA']['vm']['mainContainer']['baseStandaloneFormExtSections']['generalSection']['sshkeys']['sshkeys'] = 'SSH Key';
 $_LANG['serverCA']['vm']['mainContainer']['baseStandaloneFormExtSections']['generalSection']['sshkeys']['description'] = 'Enter a SSH key';
 $_LANG['serverCA']['vm']['mainContainer']['baseStandaloneFormExtSections']['baseSubmitButton']['button']['submit'] = 'Save Changes';
+$_LANG['serverCA']['vm']['mainContainer']['baseStandaloneFormExtSections']['generalSection']['archive']['archive'] = 'Archive';
+$_LANG['serverCA']['vm']['mainContainer']['baseStandaloneFormExtSections']['generalSection']['archive']['desciption'] = 'Select archive ';
 $_LANG['serverCA']['vm']['mainContainer']['baseStandaloneFormExtSections']['netdisk']['virtualNetworkSection']['virtualNetworkSection']        = 'Virtual Networks'   ;
 $_LANG['serverCA']['vm']['mainContainer']['baseStandaloneFormExtSections']['netdisk']['virtualNetworkSection']['Add New Virtual Network']='Add New Virtual Network';
 $_LANG['serverCA']['vm']['mainContainer']['baseStandaloneFormExtSections']['netdisk']['virtualNetworkSection']['Virtual Network']='Virtual Network';
@@ -1128,7 +1165,7 @@ $_LANG['serverCA']['vm']['mainContainer']['baseStandaloneFormExtSections']['netd
 $_LANG['serverCA']['vm']['mainContainer']['baseStandaloneFormExtSections']['netdisk']['additionalDiskSection']['additionalDiskBackup']['additionalDiskBackup'] = 'Backup';
 $_LANG['serverCA']['vm']['mainContainer']['baseStandaloneFormExtSections']['netdisk']['additionalDiskSection']['additional_disk_add_info'] = 'Click on blue button to add additional disk';
 $_LANG['serverCA']['vm']['mainContainer']['baseStandaloneFormExtSections']['generalSection']['swap']['swap'] ='SWAP';
-$_LANG['serverCA']['vm']['mainContainer']['baseStandaloneFormExtSections']['generalSection']['swap']['description']='SWAP';
+$_LANG['serverCA']['vm']['mainContainer']['baseStandaloneFormExtSections']['generalSection']['swap']['description']='Allows the container to use additional swap memory from the host swap space. This corresponds to the memory.memsw.limit_in_bytes cgroup setting, which is set to the sum of both value (memory + swap)';
 $_LANG['serverCA']['vm']['mainContainer']['baseStandaloneFormExtSections']['generalSection']['cloudInitScript']['cloudInitScript']= 'Cloud-Init Script';
 $_LANG['serverCA']['vm']['mainContainer']['baseStandaloneFormExtSections']['generalSection']['cloudInitScript']['description'] = 'Select Cloud-Init Script ';
 $_LANG['serverCA']['vm']['mainContainer']['baseStandaloneFormExtSections']['netdisk']['additionalDiskSection']['additionalDiskMp']['additionalDiskMp'] ='Path';
@@ -1143,6 +1180,14 @@ $_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['isoDataTable'] = 'ISO I
 $_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['dataTable']['Select the template for reinstallation. If you proceed, all data located on the virtual machine will be lost.'] = 'Select the template for reinstallation. If you proceed, all data located on the virtual machine will be lost.';
 $_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['dataTable']['table']['name'] = 'Name';
 $_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['dataTable']['isoInstallButton']['button']['isoInstallButton'] = 'Install';
+$_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['detailTab']['baseStandaloneFormExtSections']['generalSection']['ipv4']['ipv4'] = 'IPv4 Addresses';
+$_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['detailTab']['baseStandaloneFormExtSections']['generalSection']['ipv4']['description'] = 'Number of IPv4 addresses for VM';
+$_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['detailTab']['baseStandaloneFormExtSections']['generalSection']['ipv6']['ipv6'] = 'IPv6 Addresses';
+$_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['detailTab']['baseStandaloneFormExtSections']['generalSection']['ipv6']['description'] = 'Number of IPv6 addresses for VM';
+$_LANG['serverCA']['vm']['mainContainer']['baseStandaloneFormExtSections']['generalSection']['ipv4']['ipv4'] = 'IPv4 Addresses';
+$_LANG['serverCA']['vm']['mainContainer']['baseStandaloneFormExtSections']['generalSection']['ipv4']['description'] = 'Number of IPv4 addresses for VM';
+$_LANG['serverCA']['vm']['mainContainer']['baseStandaloneFormExtSections']['generalSection']['ipv6']['ipv6'] = 'IPv6 Addresses';
+$_LANG['serverCA']['vm']['mainContainer']['baseStandaloneFormExtSections']['generalSection']['ipv6']['description'] = 'Number of IPv6 addresses for VM';
 $_LANG['Enable'] = 'Enable';
 $_LANG['Disable'] = 'Disable';
 $_LANG['serverCA']['vm']['mainContainer']['baseStandaloneFormExtSections']['generalSection']['cpuPriority']['cpuPriority'] = 'CPU Priority';
@@ -1312,7 +1357,7 @@ $_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['diskDataTable']['table'
 $_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['diskDataTable']['table']['bytes'] = 'Size';
 $_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['diskDataTable']['updateDiskButton']['button']['updateDiskButton'] = 'Edit';
 $_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['diskDataTable']['deleteDiskButton']['button']['deleteDiskButton'] = 'Delete';
-$_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['detailTab']['baseStandaloneFormExtSections']['generalSection']['swap']['description'] = 'generalSection swap description';
+$_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['detailTab']['baseStandaloneFormExtSections']['generalSection']['swap']['description'] = 'Allows the container to use additional swap memory from the host swap space. This corresponds to the memory.memsw.limit_in_bytes cgroup setting, which is set to the sum of both value (memory + swap)';
 $_LANG['Disk :id:'] = 'Disk :id:';
 //MP
 $_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['mountPointDataTable']['Adding, editing or removing disk will reboot the virtual machine.'] = 'Adding, editing or removing disk will reboot the virtual machine.';
@@ -1394,6 +1439,8 @@ $_LANG['serverCA']['vm']['createVirtualInterfaceModal']['createForm']['vn_id']['
 $_LANG['serverCA']['vm']['createVirtualInterfaceModal']['createForm']['ip']['ip'] = 'Select IP Address';
 $_LANG['serverCA']['vm']['createVirtualInterfaceModal']['baseAcceptButton']['title'] = 'Add';
 $_LANG['serverCA']['vm']['createVirtualInterfaceModal']['baseCancelButton']['title'] = 'Cancel';
+$_LANG['Select the Virtual Network'] = 'Select the Virtual Network';
+$_LANG['You are not able to set :virtual_interfaces: of the virtual inferfaces. The  available virtual interfec is: :max:'] = 'You are not able to set :virtual_interfaces: of the virtual interfaces. The available number of virtual interfaces is: :max:';
 //delete
 $_LANG['serverCA']['vm']['deletevirtualInterfaceModal']['modal']['deletevirtualInterfaceModal'] = 'Delete Virtual Network';
 $_LANG['serverCA']['vm']['deletevirtualInterfaceModal']['deleteForm']['confirmDelete'] = 'Are you sure that you want to remove this virtual network?';
@@ -1448,6 +1495,89 @@ $_LANG['serverCA']['vm']['deleteMassModal']['deleteMassForm']['confirmDeleteMass
 $_LANG['serverCA']['vm']['deleteMassModal']['baseAcceptButton']['title'] = 'Confirm';
 $_LANG['serverCA']['vm']['deleteMassModal']['baseCancelButton']['title']  = 'Cancel';
 $_LANG['The snapshots have been deleted successfully'] = 'The selected snapshots have been deleted successfully';
+//snapshot jobs
+
+
+$_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['snapshotTabTitle'] = 'Snapshots';
+$_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['snapshotTab']['snapshotTabTitle'] = 'Snapshots';
+$_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['snapshotTab']['snapshotDataTable'] = 'Snapshots';
+$_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['snapshotTab']['jobDataTable'] = 'Jobs';
+$_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['snapshotTab']['dataTable']['createSnapshotButton']['button']['createSnapshotButton'] = 'Take Snapshot';
+$_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['snapshotTab']['dataTable']['deleteMassButton']['button']['deleteMassButton'] = 'Delete';
+$_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['snapshotTab']['dataTable']['table']['status'] = 'Status';
+$_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['snapshotTab']['dataTable']['table']['vmstate'] = 'RAM';
+$_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['snapshotTab']['dataTable']['table']['snaptime'] = 'Data/Status';
+$_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['snapshotTab']['dataTable']['table']['description'] = 'Description';
+$_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['snapshotTab']['dataTable']['rollbackButton ']['button']['rollbackButton'] = 'Rollback';
+$_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['snapshotTab']['dataTable']['updateButton']['button']['updateButton'] = 'Edit';
+$_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['snapshotTab']['dataTable']['deleteButton']['button']['deleteButton'] = 'Delete';
+$_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['snapshotTab']['dataTable']['createJobButton']['button']['createJobButton'] = 'New Job';
+$_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['snapshotTab']['dataTable']['deleteJobMassButton']['button']['deleteJobMassButton'] = 'Delete';
+$_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['snapshotTab']['dataTable']['table']['days'] = 'Days';
+$_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['snapshotTab']['dataTable']['table']['created_at'] = 'Created At';
+$_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['snapshotTab']['dataTable']['updateJobButton']['button']['updateJobButton'] = 'Edit';
+$_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['snapshotTab']['dataTable']['deleteJobButton']['button']['deleteJobButton'] = 'Delete';
+$_LANG['serverCA']['vm']['The maximum number of snapshot jobs has been exceeded. Please remove the old snapshot jobs.'] = 'The maximum number of snapshot jobs has been exceeded. Please remove the old snapshot jobs.';
+$_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['snapshotTab']['dataTable']['table']['name'] = 'Name';
+$_LANG['serverCA']['vm']['Your snapshot limit is :snapshotFilesLimit:. When you exceed this limit, the last snapshot will be replaced with a new one.'] = 'Your snapshot limit is :snapshotFilesLimit:. When you exceed this limit, the last snapshot will be replaced with a new one.';
+$_LANG['serverCA']['vm']['hourly'] = 'Hourly';
+$_LANG['serverCA']['vm']['daily'] = 'Daily';
+$_LANG['serverCA']['vm']['Monday'] = 'Monday';
+$_LANG['serverCA']['vm']['Tuesday'] = 'Tuesday';
+$_LANG['serverCA']['vm']['Wednesday'] = 'Wednesday';
+$_LANG['serverCA']['vm']['Thursday'] = 'Thursday';
+$_LANG['serverCA']['vm']['Friday'] = 'Friday';
+$_LANG['serverCA']['vm']['Saturday'] = 'Saturday';
+$_LANG['serverCA']['vm']['Sunday'] = 'Sunday';
+$_LANG['serverCA']['vm']['createJobModal']['hourly'] = 'Hourly';
+$_LANG['serverCA']['vm']['createJobModal']['daily'] = 'Daily';
+$_LANG['serverCA']['vm']['createJobModal']['Monday'] = 'Monday';
+$_LANG['serverCA']['vm']['createJobModal']['Tuesday'] = 'Tuesday';
+$_LANG['serverCA']['vm']['createJobModal']['Wednesday'] = 'Wednesday';
+$_LANG['serverCA']['vm']['createJobModal']['Thursday'] = 'Thursday';
+$_LANG['serverCA']['vm']['createJobModal']['Friday'] = 'Friday';
+$_LANG['serverCA']['vm']['createJobModal']['Saturday'] = 'Saturday';
+$_LANG['serverCA']['vm']['createJobModal']['Sunday'] = 'Sunday';
+$_LANG['serverCA']['vm']['createJobModal']['createJobForm']['days']['days'] = 'Days';
+$_LANG['serverCA']['vm']['createJobModal']['createJobForm']['start_time']['start_time'] = 'Start Time';
+$_LANG['serverCA']['vm']['createJobModal']['modal']['createJobModal'] = 'New Snapshot Job';
+$_LANG['serverCA']['vm']['createJobModal']['createJobForm']['period']['period'] = 'Period';
+$_LANG['serverCA']['vm']['createJobModal']['createJobForm']['run_every']['run_every'] = 'Run Every';
+$_LANG['serverCA']['vm']['createJobModal']['createJobForm']['name']['name'] = 'Name';
+$_LANG['serverCA']['vm']['createJobModal']['createJobForm']['vmstate']['vmstate'] = 'Include RAM';
+$_LANG['serverCA']['vm']['createJobModal']['createJobForm']['description']['description'] = 'Description';
+$_LANG['serverCA']['vm']['createJobModal']['baseAcceptButton']['title'] = 'Confirm';
+$_LANG['serverCA']['vm']['createJobModal']['baseCancelButton']['title'] = 'Cancel';
+//update
+$_LANG['serverCA']['vm']['updateJobModal']['modal']['updateJobModal'] = 'Edit Snapshot Job';
+$_LANG['serverCA']['vm']['updateJobModal']['updateJobForm']['days']['days'] = 'Days';
+$_LANG['serverCA']['vm']['updateJobModal']['updateJobForm']['start_time']['start_time'] = 'Start Time';
+$_LANG['serverCA']['vm']['updateJobModal']['updateJobForm']['period']['period'] = 'Period';
+$_LANG['serverCA']['vm']['updateJobModal']['updateJobForm']['run_every']['run_every'] = 'Run Every';
+$_LANG['serverCA']['vm']['updateJobModal']['updateJobForm']['name']['name'] = 'Name';
+$_LANG['serverCA']['vm']['updateJobModal']['updateJobForm']['vmstate']['vmstate'] = 'Include RAM';
+$_LANG['serverCA']['vm']['updateJobModal']['updateJobForm']['description']['description'] = 'Description';
+$_LANG['serverCA']['vm']['updateJobModal']['baseAcceptButton']['title'] = 'Save Changes';
+$_LANG['serverCA']['vm']['updateJobModal']['baseCancelButton']['title'] = 'Cancel';
+$_LANG['serverCA']['vm']['Every :run_every: hour']='Every :run_every: hour';
+$_LANG['serverCA']['vm']['Every :run_every: hours']='Every :run_every: hours';
+//delete
+$_LANG['serverCA']['vm']['deleteJobModal']['modal']['deleteJobModal'] = 'Delete Snapshot Job';
+$_LANG['serverCA']['vm']['deleteJobModal']['deleteJobForm']['conforimJobDelete'] = 'Are you sure that you want to delete the :name: snapshot job?';
+$_LANG['serverCA']['vm']['deleteJobModal']['baseAcceptButton']['title'] =  'Confirm';
+$_LANG['serverCA']['vm']['deleteJobModal']['baseCancelButton']['title'] = 'Cancel';
+//delete mass
+$_LANG['serverCA']['vm']['deleteJobMassModal']['modal']['deleteJobMassModal'] = 'Delete Jobs';
+$_LANG['serverCA']['vm']['deleteJobMassModal']['deleteJobMassForm']['confirmDeleteJobMass']  = 'Are you sure that you want to delete the selected snapshot jobs?';
+$_LANG['serverCA']['vm']['deleteJobMassModal']['baseAcceptButton']['title'] =  'Confirm';
+$_LANG['serverCA']['vm']['deleteJobMassModal']['baseCancelButton']['title'] =  'Cancel';
+//messages
+$_LANG['Snapshot Job :name: has been created successfully']='Snapshot Job :name: has been created successfully';
+$_LANG['Snapshot Job :name: has updated successfully']='Snapshot Job :name: has updated successfully';
+$_LANG['Snapshot Job :name: has been deleted successfully']='Snapshot Job :name: has been deleted successfully';
+$_LANG['The selected snapshot jobs have been deleted successfully']='The selected snapshot jobs have been deleted successfully';
+
+$_LANG['serverCA']['vm']['Every :run_every: hours']='Every :run_every: hour';
 /**********************************************************************************************************************
  *                                                 VM Backups                                          *
  ********************************************************************************************************************* */
@@ -1544,6 +1674,10 @@ $_LANG['serverCA']['vm']['deleteBackupJobModal']['deleteForm']['confirmDelete']
 $_LANG['serverCA']['vm']['deleteBackupJobModal']['baseAcceptButton']['title'] = 'Confirm';
 $_LANG['serverCA']['vm']['deleteBackupJobModal']['baseCancelButton']['title'] = 'Cancel';
 $_LANG['The backup job has been deleted successfully'] = 'The backup job has been deleted successfully';
+$_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['backupTabName']['resourcesContainer'] = 'Available Resources';
+$_LANG['serverCA']['vm']['backupSize'] = 'Backup Size:';
+$_LANG['serverCA']['vm']['backupFiles']= 'Backup Files:';
+$_LANG['The maximum number of backup files has been exceeded. Please remove the old backup files.'] = 'The maximum number of backup files has been exceeded. Please remove the old backup files.';
 /**********************************************************************************************************************
  *                                                 VM Firewall                                         *
  ********************************************************************************************************************* */
@@ -1561,6 +1695,9 @@ $_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['firewallTab']['dataTabl
 $_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['firewallTab']['dataTable']['table']['comment'] = 'Comment';
 $_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['firewallTab']['dataTable']['updateButton']['button']['updateButton'] = 'Update';
 $_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['firewallTab']['dataTable']['deleteButton']['button']['deleteButton'] = 'Delete';
+$_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['firewallTab']['firewallDataTable']['table']['pos'] = 'Position';
+$_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['firewallTab']['firewallDataTable']['upRuleButton']['button']['upRuleButton'] = 'Move Up';
+$_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['firewallTab']['firewallDataTable']['downRuleButton']['button']['downRuleButton'] = 'Move Down';
 //options
 $_LANG['serverCA']['vm']['log_level_in'] = 'Log Level In';
 $_LANG['serverCA']['vm']['log_level_out'] = 'Log Level Out';
@@ -1613,6 +1750,15 @@ $_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['firewallTab']['firewall
 $_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['firewallTab']['firewallDataTable']['table']['comment'] = 'Comment';
 $_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['firewallTab']['firewallDataTable']['updateButton']['button']['updateButton'] = 'Edit';
 $_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['firewallTab']['firewallDataTable']['deleteButton']['button']['deleteButton'] = 'Delete';
+$_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['firewallTab']['firewallDataTable']['buttonBase']['downloadButton']['button']['downloadButton'] = 'Download Rules';
+$_LANG['serverCA']['vm']['mainContainer']['tabsWidget']['firewallTab']['firewallDataTable']['buttonBase']['restoreButton']['button']['restoreButton'] = 'Restore Rules';
+$_LANG['serverCA']['vm']['restoreModal']['modal']['restoreModal'] = 'Restore Firewall Rules';
+$_LANG['serverCA']['vm']['restoreModal']['restoreForm']['rules']['rules'] = 'Backup File';
+$_LANG['serverCA']['vm']['restoreModal']['baseAcceptButton']['title'] = 'Save Changes';
+$_LANG['serverCA']['vm']['restoreModal']['baseCancelButton']['title'] = 'Cancel';
+$_LANG['The file with firewall rules is empty or invalid']= 'The file with firewall rules is empty or invalid';
+$_LANG['The firewall rules have been restored successfully'] = 'The firewall rules have been restored successfully';
+$_LANG['errorCodeMessage']['The maximum number of firewall rules has been exceeded. Please remove the old firewall rules.'] ='The maximum number of firewall rules has been exceeded. Please remove the old firewall rules.';
 //create
 $_LANG['serverCA']['vm']['venet'] = 'Venet';
 $_LANG['serverCA']['vm']['Microsoft Remote Desktop Protocol traffic'] = 'Microsoft Remote Desktop Protocol traffic';
@@ -1908,3 +2054,10 @@ $_LANG['serverCA']['customTemplate']['deleteModal']['deleteForm']['confirmDelete
 $_LANG['serverCA']['customTemplate']['deleteModal']['baseAcceptButton']['title'] = 'Confirm';
 $_LANG['serverCA']['customTemplate']['deleteModal']['baseCancelButton']['title'] = 'Cancel';
 $_LANG['The Template has been deleted successfully']='The selected template has been deleted successfully';
+$_LANG['VM not running']='VM not running';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['loadBalancerSection']['leftSection']['customconfigoption[serverGroup][]']['customconfigoption[serverGroup][]'] = 'Group';
+$_LANG['serverAA']['product']['mainContainer']['mainForm']['loadBalancerSection']['leftSection']['customconfigoption[serverGroup][]']['tip'] = 'Select a preferred group or groups of nodes. If you do not have any groups created, proceed to Proxmox Addon -> Servers List -> Details ->Node Groups and add a new group.';
+$_LANG['gb'] = 'GB';
+$_LANG['tb'] = 'TB';
+$_LANG['serverCA']['vm']['OpenPGP HTTP key server protocol traffic'] = 'OpenPGP HTTP key server protocol traffic';
+$_LANG['serverCA']['vm']['Ceph Storage Cluster traffic (Ceph Monitors, OSD & MDS Daemons)'] = 'Ceph Storage Cluster traffic (Ceph Monitors, OSD & MDS Daemons)';

+ 2 - 2
logo.png


+ 4 - 1
packages/Provisioning/Config/PackageConfiguration.php

@@ -360,4 +360,7 @@
 #layers .selectize-control.single .selectize-dropdown.single .option {
     white-space: normal;
 }
-/* end of add multiline for long selectize option values(dropdown)*/
+/* end of add multiline for long selectize option values(dropdown)*/
+form[name='frm2'] .selectize-control {
+    height: inherit!important;
+}

+ 1 - 1
templates/admin/assets/fonts/icons/Material-Design-Iconic-Font.eot

@@ -24553,6 +24553,6 @@ table.lu-dataTable {
     width: 56px;
     border-width: 4px;
 }
-#layers .table.dataTable>thead .sorting:before, table.dataTable>thead .sorting_asc:before, table.dataTable>thead .sorting_asc_disabled:before, table.dataTable>thead .sorting_desc:before, table.dataTable>thead .sorting_desc_disabled:before {
+#layers .lu-table.dataTable>thead .sorting:before, table.dataTable>thead .sorting_asc:before, table.dataTable>thead .sorting_asc_disabled:before, table.dataTable>thead .sorting_desc:before, table.dataTable>thead .sorting_desc_disabled:before {
   content: "" !important;
 }

+ 9 - 3
templates/client/default/assets/css/mg_styles.css

@@ -465,7 +465,7 @@ var mgDefauleVueObject = {
                         console.log('Action Failed');
                     }
                 },
-                ajaxAction : function(event, targetId, namespace, index, postData) {
+                ajaxAction : function(event, targetId, namespace, index, postData, addSpinner=false) {
                     var self = this;
                     self.refreshUrl();
                     self.initRefreshActions(event, targetId);
@@ -474,8 +474,14 @@ var mgDefauleVueObject = {
                     self.addUrlComponent('index', index);
                     self.getActionId(event);
                     self.addUrlComponent('ajax', '1');
+                    if (addSpinner) {
+                        self.showSpinner(event);
+                    }
                     $.post(self.targetUrl, postData)
                         .done(function( data ) {
+                            if (addSpinner) {
+                                self.hideSpinner(event);
+                            }
                             data = data.data;
                             self.addAlert(data.status, data.message);
                             self.$nextTick(function() {
@@ -483,8 +489,8 @@ var mgDefauleVueObject = {
                                     window[data.callBackFunction](data, targetId, event);
                                 }
                             });
-                            if(data.status === 'success'){
-
+                            if(data.status === 'success'  &&  data.refreshIds !== undefined ){
+                                self.runRefreshActions((data && typeof data.refreshIds !== undefined) ? data.refreshIds : null, data);
                             }
                     }, 'json');
                     self.refreshUrl();               

+ 3 - 1
templates/client/default/assets/js/defaultComponents/ajaxFieldForDataTable.js

@@ -92,7 +92,6 @@ mgJsComponentHandler.addDefaultComponent('mg-datatable', {
             }
         },
         updateProjects: function(){
-            console.log('Update!');
             this.loaded = true;
             if (this.searchEnabled === false) {
                 return;
@@ -305,6 +304,9 @@ mgJsComponentHandler.addDefaultComponent('mg-datatable', {
         },
         getFilters: function () {
             return this.$store.getters.getComponentData(this.component_id, 'filters');
+        },
+        buttonAction: function(event, targetId){
+            mgPageControler.vueLoader.ajaxAction(event, targetId, getItemNamespace(targetId), getItemIndex(targetId),null,true);
         }
     }
 });

+ 36 - 0
templates/client/default/assets/js/defaultComponents/dataTableSelectFilter.js

@@ -0,0 +1,36 @@
+{**********************************************************************
+* ProxmoxVps product developed. (2017-10-30)
+* *
+*
+*  CREATED BY MODULESGARDEN       ->       http://modulesgarden.com
+*  CONTACT                        ->       contact@modulesgarden.com
+*
+*
+* This software is furnished under a license and may be used and copied
+* only  in  accordance  with  the  terms  of such  license and with the
+* inclusion of the above copyright notice.  This software  or any other
+* copies thereof may not be provided or otherwise made available to any
+* other person.  No title to and  ownership of the  software is  hereby
+* transferred.
+*
+*
+**********************************************************************}
+
+{**
+* @author Sławomir Miśkowicz <slawomir@modulesgarden.com>
+*}
+
+<div class="lu-form-group">
+    <label class="lu-form-label">
+        {if $rawObject->isRawTitle()}{$rawObject->getRawTitle()}{elseif $rawObject->getTitle()}{$MGLANG->T($rawObject->getTitle())}{/if}
+        {if $rawObject->getDescription()}
+            <i data-title="{$MGLANG->T($rawObject->getDescription())}" data-toggle="lu-tooltip" class="lu-i-c-2x lu-zmdi lu-zmdi-help-outline lu-form-tooltip-helper"></i>
+        {/if}
+    </label>
+    <input class="lu-form-control" type="file" placeholder="{$rawObject->getPlaceholder()}" name="{$rawObject->getName()}"
+           id="{$rawObject->getId()}"
+           value="{$rawObject->getValue()}" {if $rawObject->isDisabled()}disabled="disabled"{/if}
+           {foreach $htmlAttributes as $aValue} {$aValue@key}="{$aValue}" {/foreach}>
+    <div class="lu-form-feedback lu-form-feedback--icon" hidden="hidden">
+    </div>    
+</div>

+ 2 - 2
templates/client/default/ui/core/default/widget/forms/fields/hidden.tpl

@@ -5,10 +5,10 @@
   "license": "proprietary",
   "category": "provisioning",
   "description": {
-    "name": "Proxmox Cloud VPS",
+    "name": "Proxmox VE Cloud  VPS",
     "tagline": "Grant your clients permission to create and modify multiple virtual servers plus enable them to manage all server components remotely.",
     "short": "Grant your clients permission to create and modify multiple virtual servers plus enable them to manage all server components remotely.",
-    "long": "Proxmox Cloud VPS For WHMCS enables your customers to create and manage multiple virtual servers at virtual data centers in your WHMCS. You simply set the resource limits as ready products, and offer them to your clients who can then create any number of servers within the purchased limit. In the client area, where the real magic of Proxmox Cloud VPS For WHMCS happens, your customers can find all essential tools to freely create, modify and remove virtual machines. With the same set of resources, they will be able to create either one powerful server, or multiple smaller ones - the way resources are used is entirely up to a client, restricted only by the limits of products you offer. Along with it, your customers will be granted permission to manage private networks, backups and firewall, access noVNC, SPICE, or Xterm.js console, as well as inspect usage graphs and statistics - all these directly on your website. Another detail to be valued highly is support for Cloud-Init for the KVM virtualization type, providing utilities for early initialization of your cloud instances. What is more, the module includes an amazing Proxmox Addon owing to which you can carefully handle your servers, IP addresses and clusters. Eager to bring even greater automation into your business? You can boost the module's potential with Proxmox Cloud VPS Autoscaling For WHMCS to introduce a completely automated mechanism of servers' resizing and cloning adjusted to their current load."
+    "long": "Proxmox VE Cloud VPS For WHMCS enables your customers to create and manage multiple virtual servers at virtual data centers in your WHMCS. You simply set the resource limits as ready products, and offer them to your clients who can then create any number of servers within the purchased limit. In the client area, where the real magic of Proxmox VE Cloud VPS For WHMCS happens, your customers can find all essential tools to freely create, modify and remove virtual machines. With the same set of resources, they will be able to create either one powerful server, or multiple smaller ones - the way resources are used is entirely up to a client, restricted only by the limits of products you offer. Along with it, your customers will be granted permission to manage private networks, backups and firewall, access noVNC, SPICE, or Xterm.js console, as well as inspect usage graphs and statistics - all these directly on your website. Another detail to be valued highly is support for Cloud-Init for the KVM virtualization type, providing utilities for early initialization of your cloud instances. What is more, the module includes an amazing Proxmox Addon owing to which you can carefully handle your servers, IP addresses and clusters. Eager to bring even greater automation into your business? You can boost the module's potential with Proxmox VE Cloud  VPS Autoscaling For WHMCS to introduce a completely automated mechanism of servers' resizing and cloning adjusted to their current load."
   },
   "logo": {
     "filename": "logo.png"