瀏覽代碼

init with origin modulsgarden source

root 4 年之前
當前提交
5d84bb4575
共有 500 個文件被更改,包括 29686 次插入0 次删除
  1. 14 0
      app/Config/Packages/Provisioning.php
  2. 528 0
      app/Config/Packages/WhmcsService.php
  3. 7 0
      app/Config/configuration.yml
  4. 1 0
      app/Config/cron.yml
  5. 1 0
      app/Config/di/buildWithDefaultMethod.yml
  6. 1 0
      app/Config/di/interface.yml
  7. 2 0
      app/Config/di/register.yml
  8. 9 0
      app/Config/di/rewrite.yml
  9. 0 0
      app/Config/di/services.yml
  10. 3 0
      app/Config/events.php
  11. 3 0
      app/Config/hooks.yml
  12. 7 0
      app/Config/menu/admin.yml
  13. 1 0
      app/Config/menu/client.yml
  14. 31 0
      app/Config/sidebars.yml
  15. 1 0
      app/Config/ui/admin/home/index.yml
  16. 23 0
      app/Configuration/Addon/Activate/After.php
  17. 23 0
      app/Configuration/Addon/Activate/Before.php
  18. 23 0
      app/Configuration/Addon/Config/After.php
  19. 23 0
      app/Configuration/Addon/Config/Before.php
  20. 23 0
      app/Configuration/Addon/Deactivate/After.php
  21. 23 0
      app/Configuration/Addon/Deactivate/Before.php
  22. 0 0
      app/Configuration/Addon/Others/.gitkeep
  23. 22 0
      app/Configuration/Addon/Update/After.php
  24. 22 0
      app/Configuration/Addon/Update/Before.php
  25. 29 0
      app/Configuration/Addon/Update/Patch/M2M7P0.php
  26. 31 0
      app/Cron/MainCron.php
  27. 0 0
      app/Database/data.sql
  28. 0 0
      app/Database/schema.sql
  29. 31 0
      app/Enum/ConfigurableOption.php
  30. 19 0
      app/Enum/CustomField.php
  31. 15 0
      app/Enum/JobPeriod.php
  32. 20 0
      app/Helpers/AppParams.php
  33. 37 0
      app/Helpers/BuildUrl.php
  34. 15 0
      app/Helpers/ErrorCodesLib.php
  35. 11 0
      app/Helpers/ProxmoxAddonNotInstalledException.php
  36. 30 0
      app/Helpers/ProxmoxAddonValidator.php
  37. 65 0
      app/Helpers/UrlServiceHelper.php
  38. 40 0
      app/Hooks/AdminAreaFooterOutput.php
  39. 31 0
      app/Hooks/AdminProductConfigFieldsSave.php
  40. 364 0
      app/Hooks/ClientAreaHeadOutput.php
  41. 63 0
      app/Hooks/ClientAreaPrimarySidebar.php
  42. 31 0
      app/Hooks/ProductDelete.php
  43. 44 0
      app/Hooks/ServiceDelete.php
  44. 64 0
      app/Http/Actions/AdminServicesTabFields.php
  45. 331 0
      app/Http/Actions/ChangePackage.php
  46. 86 0
      app/Http/Actions/ChangePassword.php
  47. 71 0
      app/Http/Actions/ChangeUserRole.php
  48. 53 0
      app/Http/Actions/ConfigOptions.php
  49. 555 0
      app/Http/Actions/CreateAccount.php
  50. 37 0
      app/Http/Actions/MetaData.php
  51. 64 0
      app/Http/Actions/ResetBandwidth.php
  52. 92 0
      app/Http/Actions/SuspendAccount.php
  53. 182 0
      app/Http/Actions/TerminateAccount.php
  54. 69 0
      app/Http/Actions/TestConnection.php
  55. 94 0
      app/Http/Actions/UnsuspendAccount.php
  56. 138 0
      app/Http/Admin/Home.php
  57. 20 0
      app/Http/Admin/LoggerManager.php
  58. 53 0
      app/Http/Admin/Product.php
  59. 23 0
      app/Http/Client/Backup.php
  60. 23 0
      app/Http/Client/BackupJob.php
  61. 45 0
      app/Http/Client/BaseClientController.php
  62. 134 0
      app/Http/Client/Console.php
  63. 34 0
      app/Http/Client/Disk.php
  64. 23 0
      app/Http/Client/Firewall.php
  65. 22 0
      app/Http/Client/FirewallOption.php
  66. 32 0
      app/Http/Client/Graph.php
  67. 93 0
      app/Http/Client/Home.php
  68. 37 0
      app/Http/Client/Network.php
  69. 59 0
      app/Http/Client/Reinstall.php
  70. 29 0
      app/Http/Client/Snapshot.php
  71. 41 0
      app/Http/Client/TaskHistory.php
  72. 89 0
      app/UI/Admin/IpSet/Pages/IpSetDataTable.php
  73. 34 0
      app/UI/Admin/Product/Buttons/VirtualizationChangButton.php
  74. 137 0
      app/UI/Admin/Product/Forms/MainForm.php
  75. 35 0
      app/UI/Admin/Product/Forms/VirtualizationChangeForm.php
  76. 53 0
      app/UI/Admin/Product/Modals/VirtualizationChangeModal.php
  77. 524 0
      app/UI/Admin/Product/Providers/ProductProvider.php
  78. 50 0
      app/UI/Admin/Product/Sections/AdminNotificationSection.php
  79. 52 0
      app/UI/Admin/Product/Sections/BackupSection.php
  80. 46 0
      app/UI/Admin/Product/Sections/ClientNotificationSection.php
  81. 43 0
      app/UI/Admin/Product/Sections/ConfigurableOptionUnitSection.php
  82. 42 0
      app/UI/Admin/Product/Sections/ConsoleSection.php
  83. 70 0
      app/UI/Admin/Product/Sections/FirewallOptionSection.php
  84. 53 0
      app/UI/Admin/Product/Sections/FirewallSection.php
  85. 54 0
      app/UI/Admin/Product/Sections/HighAvailabilityClusterSection.php
  86. 55 0
      app/UI/Admin/Product/Sections/LoadBalancerSection.php
  87. 154 0
      app/UI/Admin/Product/Sections/Lxc/ClientAreaSection.php
  88. 57 0
      app/UI/Admin/Product/Sections/Lxc/ConfigurableOptionUnitsSection.php
  89. 122 0
      app/UI/Admin/Product/Sections/Lxc/ConfigurationSection.php
  90. 120 0
      app/UI/Admin/Product/Sections/Lxc/ContainerSection.php
  91. 71 0
      app/UI/Admin/Product/Sections/Lxc/MountPointSection.php
  92. 82 0
      app/UI/Admin/Product/Sections/Lxc/NetworkSection.php
  93. 65 0
      app/UI/Admin/Product/Sections/MainSection.php
  94. 65 0
      app/UI/Admin/Product/Sections/MiscellaneousSection.php
  95. 88 0
      app/UI/Admin/Product/Sections/Qemu/AdditonalDisk.php
  96. 63 0
      app/UI/Admin/Product/Sections/Qemu/AdditonalDiskSpeedSection.php
  97. 92 0
      app/UI/Admin/Product/Sections/Qemu/AdvancedSection.php
  98. 54 0
      app/UI/Admin/Product/Sections/Qemu/BootSection.php
  99. 171 0
      app/UI/Admin/Product/Sections/Qemu/ClientAreaSection.php
  100. 98 0
      app/UI/Admin/Product/Sections/Qemu/CloudInitSection.php
  101. 52 0
      app/UI/Admin/Product/Sections/Qemu/ConfigurableOptionUnitsSection.php
  102. 186 0
      app/UI/Admin/Product/Sections/Qemu/ConfigurationSection.php
  103. 124 0
      app/UI/Admin/Product/Sections/Qemu/ContainerSection.php
  104. 79 0
      app/UI/Admin/Product/Sections/Qemu/DiskSection.php
  105. 61 0
      app/UI/Admin/Product/Sections/Qemu/DiskSpeedSection.php
  106. 75 0
      app/UI/Admin/Product/Sections/Qemu/GuestAgentSection.php
  107. 88 0
      app/UI/Admin/Product/Sections/Qemu/NetworkSection.php
  108. 65 0
      app/UI/Admin/Product/Sections/UserSection.php
  109. 96 0
      app/UI/Admin/QemuGuestAgent/Pages/NetworkInterfacesDataTable.php
  110. 25 0
      app/UI/Admin/Templates/assets/css/integration.css
  111. 3 0
      app/UI/Admin/Templates/assets/css/module_styles.css
  112. 二進制
      app/UI/Admin/Templates/assets/img/buttons/backup.png
  113. 二進制
      app/UI/Admin/Templates/assets/img/buttons/backupJob.png
  114. 二進制
      app/UI/Admin/Templates/assets/img/buttons/disk.png
  115. 二進制
      app/UI/Admin/Templates/assets/img/buttons/firewall.png
  116. 二進制
      app/UI/Admin/Templates/assets/img/buttons/firewallOption.png
  117. 二進制
      app/UI/Admin/Templates/assets/img/buttons/graph.png
  118. 二進制
      app/UI/Admin/Templates/assets/img/buttons/network.png
  119. 二進制
      app/UI/Admin/Templates/assets/img/buttons/novnc.png
  120. 二進制
      app/UI/Admin/Templates/assets/img/buttons/rebootButton.png
  121. 二進制
      app/UI/Admin/Templates/assets/img/buttons/reinstall.png
  122. 二進制
      app/UI/Admin/Templates/assets/img/buttons/shutdownButton.png
  123. 二進制
      app/UI/Admin/Templates/assets/img/buttons/snapshot.png
  124. 二進制
      app/UI/Admin/Templates/assets/img/buttons/spice.png
  125. 二進制
      app/UI/Admin/Templates/assets/img/buttons/startButton.png
  126. 二進制
      app/UI/Admin/Templates/assets/img/buttons/stopButton.png
  127. 二進制
      app/UI/Admin/Templates/assets/img/buttons/taskHistory.png
  128. 二進制
      app/UI/Admin/Templates/assets/img/buttons/vnc.png
  129. 二進制
      app/UI/Admin/Templates/assets/img/buttons/xtermjs.png
  130. 37 0
      app/UI/Admin/Templates/assets/js/home/index.js
  131. 51 0
      app/UI/Admin/Templates/assets/js/product/index.js
  132. 113 0
      app/UI/Admin/User/Pages/UserDataTable.php
  133. 35 0
      app/UI/Backup/Buttons/CreateButton.php
  134. 36 0
      app/UI/Backup/Buttons/DeleteButton.php
  135. 36 0
      app/UI/Backup/Buttons/DeleteMassButton.php
  136. 36 0
      app/UI/Backup/Buttons/RestoreButton.php
  137. 85 0
      app/UI/Backup/Forms/CreateForm.php
  138. 52 0
      app/UI/Backup/Forms/DeleteForm.php
  139. 48 0
      app/UI/Backup/Forms/DeleteMassForm.php
  140. 51 0
      app/UI/Backup/Forms/RestoreForm.php
  141. 36 0
      app/UI/Backup/Modals/CreateModal.php
  142. 35 0
      app/UI/Backup/Modals/DeleteMassModal.php
  143. 35 0
      app/UI/Backup/Modals/DeleteModal.php
  144. 35 0
      app/UI/Backup/Modals/RestoreModal.php
  145. 87 0
      app/UI/Backup/Pages/BackupDataTable.php
  146. 115 0
      app/UI/Backup/Providers/BackupProvider.php
  147. 35 0
      app/UI/BackupJob/Buttons/CreateButton.php
  148. 36 0
      app/UI/BackupJob/Buttons/DeleteButton.php
  149. 81 0
      app/UI/BackupJob/Buttons/MailtoSwitchButton.php
  150. 35 0
      app/UI/BackupJob/Buttons/UpdateButton.php
  151. 116 0
      app/UI/BackupJob/Forms/CreateForm.php
  152. 51 0
      app/UI/BackupJob/Forms/DeleteForm.php
  153. 124 0
      app/UI/BackupJob/Forms/UpdateForm.php
  154. 36 0
      app/UI/BackupJob/Modals/CreateModal.php
  155. 35 0
      app/UI/BackupJob/Modals/DeleteModal.php
  156. 36 0
      app/UI/BackupJob/Modals/UpdateModal.php
  157. 122 0
      app/UI/BackupJob/Pages/BackupJobDataTable.php
  158. 130 0
      app/UI/BackupJob/Providers/BackupJobProvider.php
  159. 21 0
      app/UI/Client/Templates/assets/css/integration.css
  160. 13 0
      app/UI/Client/Templates/assets/css/module_styles.css
  161. 二進制
      app/UI/Client/Templates/assets/img/buttons/backup.png
  162. 二進制
      app/UI/Client/Templates/assets/img/buttons/backupJob.png
  163. 二進制
      app/UI/Client/Templates/assets/img/buttons/disk.png
  164. 二進制
      app/UI/Client/Templates/assets/img/buttons/firewall.png
  165. 二進制
      app/UI/Client/Templates/assets/img/buttons/firewallOption.png
  166. 二進制
      app/UI/Client/Templates/assets/img/buttons/graph.png
  167. 二進制
      app/UI/Client/Templates/assets/img/buttons/network.png
  168. 二進制
      app/UI/Client/Templates/assets/img/buttons/novnc.png
  169. 二進制
      app/UI/Client/Templates/assets/img/buttons/rebootButton.png
  170. 二進制
      app/UI/Client/Templates/assets/img/buttons/reinstall.png
  171. 二進制
      app/UI/Client/Templates/assets/img/buttons/shutdownButton.png
  172. 二進制
      app/UI/Client/Templates/assets/img/buttons/snapshot.png
  173. 二進制
      app/UI/Client/Templates/assets/img/buttons/spice.png
  174. 二進制
      app/UI/Client/Templates/assets/img/buttons/startButton.png
  175. 二進制
      app/UI/Client/Templates/assets/img/buttons/stopButton.png
  176. 二進制
      app/UI/Client/Templates/assets/img/buttons/taskHistory.png
  177. 二進制
      app/UI/Client/Templates/assets/img/buttons/vnc.png
  178. 二進制
      app/UI/Client/Templates/assets/img/buttons/xtermjs.png
  179. 17 0
      app/UI/Client/Templates/assets/js/backup/index.js
  180. 18 0
      app/UI/Client/Templates/assets/js/backupJob/index.js
  181. 12 0
      app/UI/Client/Templates/assets/js/disk/index.js
  182. 44 0
      app/UI/Client/Templates/assets/js/firewall/index.js
  183. 33 0
      app/UI/Client/Templates/assets/js/graph/index.js
  184. 12 0
      app/UI/Client/Templates/assets/js/home/index.js
  185. 12 0
      app/UI/Client/Templates/assets/js/mountPoint/index.js
  186. 13 0
      app/UI/Client/Templates/assets/js/network/index.js
  187. 10 0
      app/UI/Client/Templates/assets/js/reinstall/index.js
  188. 24 0
      app/UI/Client/Templates/assets/js/snapshot/index.js
  189. 61 0
      app/UI/Disk/Buttons/BackupSwitchButton.php
  190. 35 0
      app/UI/Disk/Buttons/CreateButton.php
  191. 37 0
      app/UI/Disk/Buttons/DeleteButton.php
  192. 36 0
      app/UI/Disk/Buttons/UpdateButton.php
  193. 83 0
      app/UI/Disk/Forms/CreateForm.php
  194. 51 0
      app/UI/Disk/Forms/DeleteForm.php
  195. 65 0
      app/UI/Disk/Forms/UpdateForm.php
  196. 35 0
      app/UI/Disk/Modals/CreateModal.php
  197. 35 0
      app/UI/Disk/Modals/DeleteModal.php
  198. 34 0
      app/UI/Disk/Modals/UpdateModal.php
  199. 137 0
      app/UI/Disk/Pages/DiskDataTable.php
  200. 169 0
      app/UI/Disk/Providers/DiskProvider.php
  201. 37 0
      app/UI/Firewall/Buttons/CreateGroupButton.php
  202. 33 0
      app/UI/Firewall/Buttons/CreateRuleButton.php
  203. 36 0
      app/UI/Firewall/Buttons/DeleteButton.php
  204. 56 0
      app/UI/Firewall/Buttons/EnableSwitchButton.php
  205. 54 0
      app/UI/Firewall/Buttons/UpdateRuleButton.php
  206. 44 0
      app/UI/Firewall/Forms/CreateGroupForm.php
  207. 42 0
      app/UI/Firewall/Forms/CreateRuleForm.php
  208. 50 0
      app/UI/Firewall/Forms/DeleteForm.php
  209. 81 0
      app/UI/Firewall/Forms/GroupForm.php
  210. 202 0
      app/UI/Firewall/Forms/RuleForm.php
  211. 45 0
      app/UI/Firewall/Forms/UpdateGroupForm.php
  212. 44 0
      app/UI/Firewall/Forms/UpdateRuleForm.php
  213. 36 0
      app/UI/Firewall/Modals/CreateGroupModal.php
  214. 36 0
      app/UI/Firewall/Modals/CreateRuleModal.php
  215. 35 0
      app/UI/Firewall/Modals/DeleteModal.php
  216. 36 0
      app/UI/Firewall/Modals/UpdateGroupModal.php
  217. 36 0
      app/UI/Firewall/Modals/UpdateRuleModal.php
  218. 175 0
      app/UI/Firewall/Pages/FirewallDataTable.php
  219. 105 0
      app/UI/Firewall/Providers/FirewallProvider.php
  220. 38 0
      app/UI/FirewallOption/Buttons/UpdateButton.php
  221. 121 0
      app/UI/FirewallOption/Forms/UpdateForm.php
  222. 35 0
      app/UI/FirewallOption/Modals/CreateModal.php
  223. 35 0
      app/UI/FirewallOption/Modals/DeleteModal.php
  224. 36 0
      app/UI/FirewallOption/Modals/UpdateModal.php
  225. 81 0
      app/UI/FirewallOption/Pages/FirewallOption.php
  226. 81 0
      app/UI/FirewallOption/Providers/FirewallOptionProvider.php
  227. 5 0
      app/UI/FirewallOption/Templates/pages/firewallOption.tpl
  228. 56 0
      app/UI/FirewallOption/Templates/pages/firewallOption_components.js
  229. 48 0
      app/UI/FirewallOption/Templates/pages/firewallOption_components.tpl
  230. 100 0
      app/UI/Graph/Pages/CpuGraph.php
  231. 108 0
      app/UI/Graph/Pages/DiskGraph.php
  232. 62 0
      app/UI/Graph/Pages/GraphData.php
  233. 106 0
      app/UI/Graph/Pages/MemoryGraph.php
  234. 109 0
      app/UI/Graph/Pages/NetworkGraph.php
  235. 41 0
      app/UI/Home/Buttons/MigrateButton.php
  236. 42 0
      app/UI/Home/Buttons/RebootButton.php
  237. 83 0
      app/UI/Home/Buttons/RedirectButton.php
  238. 42 0
      app/UI/Home/Buttons/ShutdownButton.php
  239. 42 0
      app/UI/Home/Buttons/StartButton.php
  240. 42 0
      app/UI/Home/Buttons/StopButton.php
  241. 54 0
      app/UI/Home/Forms/MigrateForm.php
  242. 42 0
      app/UI/Home/Forms/RebootForm.php
  243. 42 0
      app/UI/Home/Forms/ShutdownForm.php
  244. 42 0
      app/UI/Home/Forms/StartForm.php
  245. 42 0
      app/UI/Home/Forms/StopForm.php
  246. 36 0
      app/UI/Home/Modals/MigrateModal.php
  247. 36 0
      app/UI/Home/Modals/RebootModal.php
  248. 36 0
      app/UI/Home/Modals/ShutdownModal.php
  249. 36 0
      app/UI/Home/Modals/StartModal.php
  250. 36 0
      app/UI/Home/Modals/StopModal.php
  251. 108 0
      app/UI/Home/Pages/ServiceActions.php
  252. 107 0
      app/UI/Home/Pages/ServiceManagement.php
  253. 89 0
      app/UI/Home/Pages/VpsBuild.php
  254. 81 0
      app/UI/Home/Providers/MigrateProvider.php
  255. 103 0
      app/UI/Home/Providers/StatusProvider.php
  256. 15 0
      app/UI/Home/Templates/pages/manageService.tpl
  257. 17 0
      app/UI/Home/Templates/pages/serviceActions.tpl
  258. 17 0
      app/UI/Home/Templates/pages/serviceManagement.tpl
  259. 5 0
      app/UI/Home/Templates/pages/vpsBuild.tpl
  260. 55 0
      app/UI/Home/Templates/pages/vpsBuild_components.js
  261. 16 0
      app/UI/Home/Templates/pages/vpsBuild_components.tpl
  262. 35 0
      app/UI/IpAddress/Buttons/CreateButton.php
  263. 37 0
      app/UI/IpAddress/Buttons/DeleteButton.php
  264. 78 0
      app/UI/IpAddress/Forms/CreateForm.php
  265. 53 0
      app/UI/IpAddress/Forms/DeleteForm.php
  266. 35 0
      app/UI/IpAddress/Modals/CreateModal.php
  267. 35 0
      app/UI/IpAddress/Modals/DeleteModal.php
  268. 95 0
      app/UI/IpAddress/Pages/IpAddressDataTable.php
  269. 121 0
      app/UI/IpAddress/Providers/IpAddressProvider.php
  270. 63 0
      app/UI/MountPoint/Buttons/BackupSwitchButton.php
  271. 35 0
      app/UI/MountPoint/Buttons/CreateButton.php
  272. 37 0
      app/UI/MountPoint/Buttons/DeleteButton.php
  273. 36 0
      app/UI/MountPoint/Buttons/UpdateButton.php
  274. 67 0
      app/UI/MountPoint/Forms/CreateForm.php
  275. 51 0
      app/UI/MountPoint/Forms/DeleteForm.php
  276. 65 0
      app/UI/MountPoint/Forms/UpdateForm.php
  277. 35 0
      app/UI/MountPoint/Modals/CreateModal.php
  278. 35 0
      app/UI/MountPoint/Modals/DeleteModal.php
  279. 35 0
      app/UI/MountPoint/Modals/UpdateModal.php
  280. 125 0
      app/UI/MountPoint/Pages/MountPointDataTable.php
  281. 135 0
      app/UI/MountPoint/Providers/MountPointProvider.php
  282. 35 0
      app/UI/Network/Buttons/CreateButton.php
  283. 40 0
      app/UI/Network/Buttons/DeleteButton.php
  284. 38 0
      app/UI/Network/Buttons/InfoButton.php
  285. 51 0
      app/UI/Network/Forms/CreateForm.php
  286. 50 0
      app/UI/Network/Forms/DeleteForm.php
  287. 35 0
      app/UI/Network/Modals/CreateModal.php
  288. 35 0
      app/UI/Network/Modals/DeleteModal.php
  289. 68 0
      app/UI/Network/Modals/InfoModal.php
  290. 162 0
      app/UI/Network/Pages/NetworkLxcDataTable.php
  291. 166 0
      app/UI/Network/Pages/NetworkQemuDataTable.php
  292. 128 0
      app/UI/Network/Providers/NetworkProvider.php
  293. 142 0
      app/UI/Network/Templates/modals/infoModal.tpl
  294. 38 0
      app/UI/Reinstall/Buttons/IsoInstallButton.php
  295. 38 0
      app/UI/Reinstall/Buttons/TemplateInstallButton.php
  296. 52 0
      app/UI/Reinstall/Forms/IsoInstallForm.php
  297. 68 0
      app/UI/Reinstall/Forms/TemplateInstallForm.php
  298. 36 0
      app/UI/Reinstall/Modals/IsoInstallModal.php
  299. 37 0
      app/UI/Reinstall/Modals/TemplateInstallModal.php
  300. 42 0
      app/UI/Reinstall/Pages/IsoDataTable.php
  301. 38 0
      app/UI/Reinstall/Pages/IsoRawDataTable.php
  302. 70 0
      app/UI/Reinstall/Pages/IsoTrait.php
  303. 40 0
      app/UI/Reinstall/Pages/ReinstallTab.php
  304. 39 0
      app/UI/Reinstall/Pages/TemplateDataTable.php
  305. 19 0
      app/UI/Reinstall/Pages/TemplateRawDataTable.php
  306. 101 0
      app/UI/Reinstall/Pages/TemplateTrait.php
  307. 142 0
      app/UI/Reinstall/Providers/IsoInstallProvider.php
  308. 145 0
      app/UI/Reinstall/Providers/TemplateInstallProvider.php
  309. 36 0
      app/UI/ServiceInformation/Buttons/SshPrivateKeyDownloadButton.php
  310. 37 0
      app/UI/ServiceInformation/Buttons/UpdateButton.php
  311. 33 0
      app/UI/ServiceInformation/Forms/SshPublicKeyDownloadForm.php
  312. 89 0
      app/UI/ServiceInformation/Forms/UpdateForm.php
  313. 68 0
      app/UI/ServiceInformation/Modals/SshPublicKeyDownloadModal.php
  314. 37 0
      app/UI/ServiceInformation/Modals/UpdateModal.php
  315. 206 0
      app/UI/ServiceInformation/Pages/ServiceInformation.php
  316. 167 0
      app/UI/ServiceInformation/Providers/UpdateProvider.php
  317. 5 0
      app/UI/ServiceInformation/Templates/pages/serviceInformation.tpl
  318. 54 0
      app/UI/ServiceInformation/Templates/pages/serviceInformation_components.js
  319. 172 0
      app/UI/ServiceInformation/Templates/pages/serviceInformation_components.tpl
  320. 35 0
      app/UI/Snapshot/Buttons/CreateButton.php
  321. 35 0
      app/UI/Snapshot/Buttons/CreateJobButton.php
  322. 36 0
      app/UI/Snapshot/Buttons/DeleteButton.php
  323. 36 0
      app/UI/Snapshot/Buttons/DeleteJobButton.php
  324. 36 0
      app/UI/Snapshot/Buttons/DeleteJobMassButton.php
  325. 36 0
      app/UI/Snapshot/Buttons/DeleteMassButton.php
  326. 36 0
      app/UI/Snapshot/Buttons/RollbackButton.php
  327. 35 0
      app/UI/Snapshot/Buttons/UpdateButton.php
  328. 35 0
      app/UI/Snapshot/Buttons/UpdateJobButton.php
  329. 73 0
      app/UI/Snapshot/Forms/CreateForm.php
  330. 59 0
      app/UI/Snapshot/Forms/CreateJobForm.php
  331. 50 0
      app/UI/Snapshot/Forms/DeleteForm.php
  332. 52 0
      app/UI/Snapshot/Forms/DeleteJobForm.php
  333. 50 0
      app/UI/Snapshot/Forms/DeleteJobMassForm.php
  334. 49 0
      app/UI/Snapshot/Forms/DeleteMassForm.php
  335. 102 0
      app/UI/Snapshot/Forms/JobForm.php
  336. 49 0
      app/UI/Snapshot/Forms/RollbackForm.php
  337. 54 0
      app/UI/Snapshot/Forms/UpdateForm.php
  338. 53 0
      app/UI/Snapshot/Forms/UpdateJobForm.php
  339. 37 0
      app/UI/Snapshot/Modals/CreateJobModal.php
  340. 36 0
      app/UI/Snapshot/Modals/CreateModal.php
  341. 36 0
      app/UI/Snapshot/Modals/DeleteJobMassModal.php
  342. 36 0
      app/UI/Snapshot/Modals/DeleteJobModal.php
  343. 35 0
      app/UI/Snapshot/Modals/DeleteMassModal.php
  344. 35 0
      app/UI/Snapshot/Modals/DeleteModal.php
  345. 36 0
      app/UI/Snapshot/Modals/RollbackModal.php
  346. 37 0
      app/UI/Snapshot/Modals/UpdateJobModal.php
  347. 36 0
      app/UI/Snapshot/Modals/UpdateModal.php
  348. 134 0
      app/UI/Snapshot/Pages/JobRawDataTable.php
  349. 46 0
      app/UI/Snapshot/Pages/SnapshotDataTable.php
  350. 19 0
      app/UI/Snapshot/Pages/SnapshotRawDataTable.php
  351. 39 0
      app/UI/Snapshot/Pages/SnapshotTab.php
  352. 116 0
      app/UI/Snapshot/Pages/SnapshotTrait.php
  353. 121 0
      app/UI/Snapshot/Providers/JobProvider.php
  354. 138 0
      app/UI/Snapshot/Providers/SnapshotProvider.php
  355. 37 0
      app/UI/TaskHistory/Buttons/InfoButton.php
  356. 50 0
      app/UI/TaskHistory/Forms/InfoForm.php
  357. 46 0
      app/UI/TaskHistory/Modals/InfoModal.php
  358. 115 0
      app/UI/TaskHistory/Pages/TaskHistoryDataTable.php
  359. 45 0
      app/UI/TaskHistory/Providers/TaskHistoryProvider.php
  360. 76 0
      app/UI/Validators/CidrValidator.php
  361. 57 0
      app/UI/Validators/HostnameValidator.php
  362. 59 0
      app/UI/Validators/IpAddressValidator.php
  363. 94 0
      app/UI/Validators/NumberValidator.php
  364. 59 0
      app/UI/Validators/PasswordValidator.php
  365. 90 0
      app/UI/Validators/PortValidator.php
  366. 57 0
      app/UI/Validators/ShhPublicKeyValidator.php
  367. 57 0
      app/UI/Validators/SnapshotValidator.php
  368. 57 0
      app/UI/Validators/StartTimeValidator.php
  369. 20 0
      commands/commands.php
  370. 40 0
      composer.json
  371. 912 0
      composer.lock
  372. 25 0
      core/Api/AbstractApi.php
  373. 158 0
      core/Api/AbstractApi/Curl.php
  374. 193 0
      core/Api/AbstractApi/Curl/Request.php
  375. 92 0
      core/Api/AbstractApi/Curl/Response.php
  376. 22 0
      core/Api/AbstractApi/Parser.php
  377. 186 0
      core/Api/Http.php
  378. 90 0
      core/Api/Whmcs.php
  379. 172 0
      core/App/AppContext.php
  380. 53 0
      core/App/AppParamsContainer.php
  381. 94 0
      core/App/Application.php
  382. 19 0
      core/App/Controllers/AppController.php
  383. 36 0
      core/App/Controllers/AppControllers/Addon.php
  384. 13 0
      core/App/Controllers/AppControllers/Api.php
  385. 13 0
      core/App/Controllers/AppControllers/Cron.php
  386. 13 0
      core/App/Controllers/AppControllers/Hooks.php
  387. 34 0
      core/App/Controllers/AppControllers/Http.php
  388. 71 0
      core/App/Controllers/Instances/Addon/Activate.php
  389. 149 0
      core/App/Controllers/Instances/Addon/Config.php
  390. 319 0
      core/App/Controllers/Instances/Addon/ConfigOptions.php
  391. 44 0
      core/App/Controllers/Instances/Addon/Deactivate.php
  392. 48 0
      core/App/Controllers/Instances/Addon/Upgrade.php
  393. 119 0
      core/App/Controllers/Instances/AddonController.php
  394. 11 0
      core/App/Controllers/Instances/Api/ApiController.php
  395. 40 0
      core/App/Controllers/Instances/Http/AddonIntegration.php
  396. 11 0
      core/App/Controllers/Instances/Http/AdminPageController.php
  397. 39 0
      core/App/Controllers/Instances/Http/AdminServicesTabFieldsIntegration.php
  398. 23 0
      core/App/Controllers/Instances/Http/ClientPageController.php
  399. 50 0
      core/App/Controllers/Instances/Http/ConfigOptionsIntegration.php
  400. 82 0
      core/App/Controllers/Instances/Http/ErrorPage.php
  401. 38 0
      core/App/Controllers/Instances/Http/Integration.php
  402. 31 0
      core/App/Controllers/Instances/Http/PageNotFound.php
  403. 189 0
      core/App/Controllers/Instances/HttpController.php
  404. 8 0
      core/App/Controllers/Interfaces/AddonController.php
  405. 8 0
      core/App/Controllers/Interfaces/AdminArea.php
  406. 8 0
      core/App/Controllers/Interfaces/AppController.php
  407. 8 0
      core/App/Controllers/Interfaces/ClientArea.php
  408. 10 0
      core/App/Controllers/Interfaces/DefaultController.php
  409. 137 0
      core/App/Controllers/ResponseResolver.php
  410. 103 0
      core/App/Controllers/Router.php
  411. 46 0
      core/App/ErrorHandler.php
  412. 104 0
      core/App/Installer/DatabaseInstaller.php
  413. 76 0
      core/App/Installer/ModuleInstaller.php
  414. 91 0
      core/App/LowLevelLog.php
  415. 39 0
      core/App/Packages/AppPackageConfiguration.php
  416. 88 0
      core/App/Packages/BasePackageConfiguration.php
  417. 9 0
      core/App/Packages/PackageConfigurationConst.php
  418. 103 0
      core/App/Packages/PackageManager.php
  419. 96 0
      core/App/Requirements/Checker.php
  420. 35 0
      core/App/Requirements/Handler.php
  421. 13 0
      core/App/Requirements/HandlerInterface.php
  422. 49 0
      core/App/Requirements/Handlers/Classes.php
  423. 114 0
      core/App/Requirements/Handlers/Files.php
  424. 47 0
      core/App/Requirements/Handlers/PhpExtensions.php
  425. 20 0
      core/App/Requirements/Instances/Classes.php
  426. 30 0
      core/App/Requirements/Instances/Files.php
  427. 21 0
      core/App/Requirements/Instances/PhpExtensions.php
  428. 13 0
      core/App/Requirements/RequirementInterface.php
  429. 26 0
      core/App/Requirements/RequirementsList.php
  430. 64 0
      core/App/TemplateDisplayWrapper.php
  431. 56 0
      core/Bootstrap.php
  432. 209 0
      core/Cache/CacheManager.php
  433. 107 0
      core/CommandLine/AbstractCommand.php
  434. 43 0
      core/CommandLine/AbstractCronController.php
  435. 218 0
      core/CommandLine/AbstractCronControllerWithoutThread.php
  436. 54 0
      core/CommandLine/Application.php
  437. 53 0
      core/CommandLine/Command.php
  438. 86 0
      core/CommandLine/CommandLoop.php
  439. 8 0
      core/CommandLine/CommandManager.php
  440. 8 0
      core/CommandLine/CronManager.php
  441. 348 0
      core/CommandLine/CronManager.php_old
  442. 253 0
      core/CommandLine/Hypervisor.php
  443. 8 0
      core/CommandLine/Job.php
  444. 86 0
      core/CommandLine/JobsLoop.php
  445. 64 0
      core/CommandLine/ReaderCronTask.php
  446. 68 0
      core/CommandLine/Tick.php
  447. 8 0
      core/Config/configuration.yml
  448. 1 0
      core/Config/cron.yml
  449. 5 0
      core/Config/di/buildWithDefaultMethod.yml
  450. 1 0
      core/Config/di/interface.yml
  451. 30 0
      core/Config/di/register.yml
  452. 8 0
      core/Config/di/services.php
  453. 5 0
      core/Config/di/services.yml
  454. 18 0
      core/Configuration/Addon/AbstractAfter.php
  455. 17 0
      core/Configuration/Addon/AbstractBefore.php
  456. 22 0
      core/Configuration/Addon/Activate/After.php
  457. 34 0
      core/Configuration/Addon/Activate/Before.php
  458. 24 0
      core/Configuration/Addon/Config/After.php
  459. 23 0
      core/Configuration/Addon/Config/Before.php
  460. 24 0
      core/Configuration/Addon/Deactivate/After.php
  461. 24 0
      core/Configuration/Addon/Deactivate/Before.php
  462. 24 0
      core/Configuration/Addon/Update/After.php
  463. 22 0
      core/Configuration/Addon/Update/Before.php
  464. 78 0
      core/Configuration/Addon/Update/Patch/AbstractPatch.php
  465. 105 0
      core/Configuration/Addon/Update/PatchManager.php
  466. 122 0
      core/Configuration/Data.php
  467. 13 0
      core/Configuration/Data/Version.php
  468. 30 0
      core/Configuration/Requirements/Files.php
  469. 0 0
      core/Database/data.sql
  470. 0 0
      core/Database/schema.sql
  471. 14 0
      core/DependencyInjection.php
  472. 76 0
      core/DependencyInjection/Builder.php
  473. 204 0
      core/DependencyInjection/Container.php
  474. 57 0
      core/DependencyInjection/DependencyInjection.php
  475. 63 0
      core/DependencyInjection/Services.php
  476. 36 0
      core/Enum/Enum.php
  477. 33 0
      core/Enum/Level.php
  478. 37 0
      core/Enum/Status.php
  479. 47 0
      core/Enum/StatusColor.php
  480. 80 0
      core/Events/Dispatcher.php
  481. 8 0
      core/Events/Event.php
  482. 8 0
      core/Events/Listener.php
  483. 41 0
      core/FileReader/Directory.php
  484. 68 0
      core/FileReader/File.php
  485. 85 0
      core/FileReader/PathValidator.php
  486. 84 0
      core/FileReader/Reader.php
  487. 49 0
      core/FileReader/Reader/AbstractType.php
  488. 36 0
      core/FileReader/Reader/Css.php
  489. 36 0
      core/FileReader/Reader/Html.php
  490. 35 0
      core/FileReader/Reader/Ini.php
  491. 36 0
      core/FileReader/Reader/Js.php
  492. 33 0
      core/FileReader/Reader/Json.php
  493. 36 0
      core/FileReader/Reader/Php.php
  494. 70 0
      core/FileReader/Reader/Sql.php
  495. 23 0
      core/FileReader/Reader/Xml.php
  496. 46 0
      core/FileReader/Reader/Yml.php
  497. 109 0
      core/HandlerError/ErrorCodes/ErrorCode.php
  498. 73 0
      core/HandlerError/ErrorCodes/ErrorCodes.php
  499. 122 0
      core/HandlerError/ErrorCodes/ErrorCodesLib.php
  500. 263 0
      core/HandlerError/ErrorManager.php

+ 14 - 0
app/Config/Packages/Provisioning.php

@@ -0,0 +1,14 @@
+<?php
+
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\Config\Packages;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Packages\AppPackageConfiguration;
+
+class Provisioning extends AppPackageConfiguration
+{
+    const APP_CONFIGURATION =
+        [
+            self::PACKAGE_STATUS => self::PACKAGE_STATUS_ACTIVE
+        ];
+}

+ 528 - 0
app/Config/Packages/WhmcsService.php

@@ -0,0 +1,528 @@
+<?php
+
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\Config\Packages;
+
+use MGProvision\Proxmox\v2\ProxmoxApiException;
+use MGProvision\Proxmox\v2\repository\ClusterResourcesRepository;
+use MGProvision\Proxmox\v2\repository\FileRepository;
+use MGProvision\Proxmox\v2\repository\StorageRepository;
+use ModulesGarden\ProxmoxAddon\App\Models\CloudInitScript;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\Libs\AwsIntegration\ClientWrapper;
+use ModulesGarden\Servers\ProxmoxVps\App\Models\AvailableImages\Repository;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\ProductConfig\Providers\Config;
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Packages\AppPackageConfiguration;
+use ModulesGarden\Servers\ProxmoxVps\Core\FileReader\Reader\Json;
+use ModulesGarden\Servers\ProxmoxVps\Core\ModuleConstants;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Traits\RequestObjectHandler;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Traits\WhmcsParams;
+use ModulesGarden\Servers\ProxmoxVps\Packages\WhmcsService\Config\Enum;
+
+class WhmcsService extends AppPackageConfiguration
+{
+    use RequestObjectHandler;
+    use WhmcsParams;
+    use ProductService;
+    use ApiService;
+
+    const APP_CONFIGURATION =
+        [
+            self::PACKAGE_STATUS => self::PACKAGE_STATUS_ACTIVE,
+
+            Enum::CUSTOM_FIELDS => [
+                [
+                    Enum::FIELD_NAME       => 'vmid|VMID',
+                    Enum::FIELD_TYPE       => Enum::FIELD_TYPE_TEXT_BOX,
+                    Enum::FIELD_ADMIN_ONLY => Enum::FIELD_ADMIN_ONLY_ON
+                ],
+                [
+                    Enum::FIELD_NAME       => 'node|Node',
+                    Enum::FIELD_TYPE       => Enum::FIELD_TYPE_TEXT_BOX,
+                    Enum::FIELD_ADMIN_ONLY => Enum::FIELD_ADMIN_ONLY_ON
+                ],
+                [
+                    Enum::FIELD_NAME       => 'VLAN Tag|VLAN Tag',
+                    Enum::FIELD_TYPE       => Enum::FIELD_TYPE_TEXT_BOX,
+                    Enum::FIELD_ADMIN_ONLY => Enum::FIELD_ADMIN_ONLY_ON
+                ],
+                [
+                    Enum::FIELD_NAME       => 'userName|Username',
+                    Enum::FIELD_TYPE       => Enum::FIELD_TYPE_TEXT_BOX,
+                    Enum::FIELD_ADMIN_ONLY => Enum::FIELD_ADMIN_ONLY_ON
+                ],
+                [
+                    Enum::FIELD_NAME       => 'ciuser|Cloud-Init User',
+                    Enum::FIELD_TYPE       => Enum::FIELD_TYPE_TEXT_BOX,
+                    Enum::FIELD_ADMIN_ONLY => Enum::FIELD_ADMIN_ONLY_ON
+                ],
+                [
+                    Enum::FIELD_NAME       => 'cipassword|Cloud-Init Password',
+                    Enum::FIELD_TYPE       => Enum::FIELD_TYPE_PASSWORD,
+                    Enum::FIELD_ADMIN_ONLY => Enum::FIELD_ADMIN_ONLY_OFF,
+                ],
+                [
+                    Enum::FIELD_NAME        => 'sshkeys|SSH Public Key',
+                    Enum::FIELD_TYPE        => Enum::FIELD_TYPE_TEXTAREA,
+                    Enum::FIELD_ADMIN_ONLY  => Enum::FIELD_ADMIN_ONLY_ON,
+                    Enum::FIELD_REG_EXPR    => '#ssh-rsa AAAA[0-9A-Za-z+/]+[=]{0,3}( [^@]+@[^@]+)?#',
+                    Enum::FIELD_SHOW_ORDER  => Enum::FIELD_SHOW_ORDER_ON,
+                    Enum::FIELD_DESCRIPTION => 'Enter your public key in the OpenSSH format here (e.g. ssh-rsa).'
+                ]
+            ],
+        ];
+
+    public function VMTemplateGetSubOptions()
+    {
+        $subOptions = [];
+        try
+        {
+            //kvm
+            if ($this->configuration()->isQemu())
+            {
+                $subOptions[]               = [
+                    Enum::OPTION_SUB_NAME  => '0|Disabled',
+                    Enum::OPTION_SUB_ORDER => Enum::OPTION_SUB_ORDER_DEFAULT,
+                ];
+                $clusterResourcesRepository = new ClusterResourcesRepository();
+                $clusterResourcesRepository->setApi($this->api());
+                $clusterResourcesRepository->findKvmTemplate();
+                $templates = [];
+                foreach ($clusterResourcesRepository->fetch() as $resurce)
+                {
+                    if (preg_match('/^custom[0-9]*/', $resurce->getName()))
+                    {
+                        continue;
+                    }
+                    if (in_array($resurce->getName(), $templates))
+                    {
+                        continue;
+                    }
+                    $subOptions[] = [
+                        Enum::OPTION_SUB_NAME  => $resurce->getName() . '|' . $resurce->getName(),
+                        Enum::OPTION_SUB_ORDER => Enum::OPTION_SUB_ORDER_DEFAULT,
+                    ];
+                }
+                unset($templates);
+            }
+            else
+            {
+                if ($this->configuration()->isLxc())
+                { //lxc
+                    //node
+                    $node = $this->getDefaultNode();
+                    //storages
+                    $storageRepository = new StorageRepository();
+                    $storageRepository->findByNodes([$node->getNode()])
+                        ->findEnabed();
+                    //osTemplates
+                    $fileRepository = new FileRepository();
+                    $fileRepository->setApi($this->api());
+                    $fileRepository->findLxcTemplates();
+                    $fileRepository->findByNode($node);
+                    $fileRepository->findByStorages($storageRepository->fetchAsArray());
+                    foreach ($fileRepository->fetch() as $file)
+                    {
+                        $subOptions[] = [
+                            Enum::OPTION_SUB_NAME  => $file->getVolid() . '|' . $file->getFriendlyName(),
+                            Enum::OPTION_SUB_ORDER => Enum::OPTION_SUB_ORDER_DEFAULT,
+                        ];
+                    }
+                }
+            }
+        }
+        catch (ProxmoxApiException $ex)
+        {
+            return $subOptions;
+        }
+        return $subOptions;
+    }
+
+    public function NetworkRateGetSubOptions()
+    {
+        return [
+            [
+                Enum::OPTION_SUB_NAME  => "0|Unlimited",
+                Enum::OPTION_SUB_ORDER => Enum::OPTION_SUB_ORDER_DEFAULT,
+            ],
+            [
+                Enum::OPTION_SUB_NAME  => '5|5 (MB/s) (' . (5 * 8) . ' Mbps)',
+                Enum::OPTION_SUB_ORDER => Enum::OPTION_SUB_ORDER_DEFAULT,
+            ],
+            [
+                Enum::OPTION_SUB_NAME  => '10|10 (MB/s) (' . (10 * 8) . ' Mbps)',
+                Enum::OPTION_SUB_ORDER => Enum::OPTION_SUB_ORDER_DEFAULT,
+            ],
+            [
+                Enum::OPTION_SUB_NAME  => '20|20 (MB/s) (' . (20 * 8) . ' Mbps)',
+                Enum::OPTION_SUB_ORDER => Enum::OPTION_SUB_ORDER_DEFAULT,
+            ],
+            [
+                Enum::OPTION_SUB_NAME  => '30|30 (MB/s) (' . (30 * 8) . ' Mbps)',
+                Enum::OPTION_SUB_ORDER => Enum::OPTION_SUB_ORDER_DEFAULT,
+            ],
+            [
+                Enum::OPTION_SUB_NAME  => '40|40 (MB/s) (' . (40 * 8) . ' Mbps)',
+                Enum::OPTION_SUB_ORDER => Enum::OPTION_SUB_ORDER_DEFAULT,
+            ],
+            [
+                Enum::OPTION_SUB_NAME  => '50|50 (MB/s) (' . (50 * 8) . ' Mbps)',
+                Enum::OPTION_SUB_ORDER => Enum::OPTION_SUB_ORDER_DEFAULT,
+            ],
+        ];
+    }
+
+    public function vcpusGetSubOptions()
+    {
+        return [
+            [
+                Enum::OPTION_SUB_NAME  => "0|Unlimited",
+                Enum::OPTION_SUB_ORDER => Enum::OPTION_SUB_ORDER_DEFAULT,
+            ],
+            [
+                Enum::OPTION_SUB_NAME  => '1|1',
+                Enum::OPTION_SUB_ORDER => Enum::OPTION_SUB_ORDER_DEFAULT,
+            ]
+        ];
+    }
+
+    public function ISOImageGetSubOptions()
+    {
+        $subOptions = [
+            [
+                Enum::OPTION_SUB_NAME  => 'none|None',
+                Enum::OPTION_SUB_ORDER => Enum::OPTION_SUB_ORDER_DEFAULT,
+            ]
+        ];
+        try
+        {
+            //node
+            $node = $this->getDefaultNode();
+            //storages
+            $storageRepository = new StorageRepository();
+            $storageRepository->findByNodes([$node->getNode()])
+                ->findEnabed();
+            //file  repository
+            $fileRepository = new FileRepository();
+            $fileRepository->setApi($this->api());
+            $fileRepository->findIso();
+            $fileRepository->findByNode($node);
+            $fileRepository->findByStorages($storageRepository->fetchAsArray());
+            foreach ($fileRepository->fetch() as $file)
+            {
+                $subOptions[] = [
+                    Enum::OPTION_SUB_NAME  => $file->getVolid() . '|' . $file->getFriendlyName(),
+                    Enum::OPTION_SUB_ORDER => Enum::OPTION_SUB_ORDER_DEFAULT,
+                ];
+            }
+        }
+        catch (ProxmoxApiException $ex)
+        {
+            return $subOptions;
+        }
+        return $subOptions;
+    }
+
+    public function osTypeGetSubOptions()
+    {
+        $subOptions = [];
+        $ostype     = new Json('ostype.json', ModuleConstants::getFullPathWhmcs('modules', 'addons', 'proxmoxAddon', 'storage', 'app'));
+        foreach ($ostype->get() as $k => $ostype)
+        {
+            $subOptions[] = [
+                Enum::OPTION_SUB_NAME  => $k . '|' . $ostype,
+                Enum::OPTION_SUB_ORDER => Enum::OPTION_SUB_ORDER_DEFAULT,
+            ];
+        }
+        return $subOptions;
+    }
+
+    public function getConfigurableOptions()
+    {
+        $configOptions = [];
+        if ($this->configuration()->isQemu())
+        {
+            $configOptions[] = [
+                Enum::OPTION_NAME         => 'The number of CPU sockets|CPU Sockets',
+                Enum::OPTION_TYPE         => Enum::OPTION_TYPE_QUANTITY,
+                Enum::OPTION_QUANTITY_MIN => 1,
+                Enum::OPTION_QUANTITY_MAX => 100,
+                Enum::CONFIG_SUB_OPTIONS  => [
+                    [
+                        Enum::OPTION_SUB_NAME  => 'Unit|Unit',
+                        Enum::OPTION_SUB_ORDER => Enum::OPTION_SUB_ORDER_DEFAULT,
+                    ]
+                ]
+            ];
+            $configOptions[] = [
+                Enum::OPTION_NAME         => 'The number of cores per socket|CPU Cores',
+                Enum::OPTION_TYPE         => Enum::OPTION_TYPE_QUANTITY,
+                Enum::OPTION_QUANTITY_MIN => 1,
+                Enum::OPTION_QUANTITY_MAX => 10,
+                Enum::CONFIG_SUB_OPTIONS  => [
+                    [
+                        Enum::OPTION_SUB_NAME  => 'Unit|Unit',
+                        Enum::OPTION_SUB_ORDER => Enum::OPTION_SUB_ORDER_DEFAULT,
+                    ]
+                ]
+            ];
+        }
+        if ($this->configuration()->isLxc())
+        {
+            $configOptions[] = [
+                Enum::OPTION_NAME         => 'cores|CPU Cores',
+                Enum::OPTION_TYPE         => Enum::OPTION_TYPE_QUANTITY,
+                Enum::OPTION_QUANTITY_MIN => 1,
+                Enum::OPTION_QUANTITY_MAX => 10,
+                Enum::CONFIG_SUB_OPTIONS  => [
+                    [
+                        Enum::OPTION_SUB_NAME  => 'Unit|Unit',
+                        Enum::OPTION_SUB_ORDER => Enum::OPTION_SUB_ORDER_DEFAULT,
+                    ]
+                ]
+            ];
+        }
+        $configOptions[] = [
+            Enum::OPTION_NAME         => 'cpulimit|Limit Of CPU',
+            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,
+                ]
+            ]
+        ];
+        $configOptions[] = [
+            Enum::OPTION_NAME         => 'CPU weight for a VM|CPU Weight For The VM',
+            Enum::OPTION_TYPE         => Enum::OPTION_TYPE_QUANTITY,
+            Enum::OPTION_QUANTITY_MIN => 1024,
+            Enum::OPTION_QUANTITY_MAX => 99999,
+            Enum::CONFIG_SUB_OPTIONS  => [
+                [
+                    Enum::OPTION_SUB_NAME  => 'Unit|Unit',
+                    Enum::OPTION_SUB_ORDER => Enum::OPTION_SUB_ORDER_DEFAULT,
+                ]
+            ]
+        ];
+        $unit            = strtoupper($this->configuration()->getMemoryUnit());
+        $min             = 128;
+        $max             = 1024 * 10;
+        if ($this->configuration()->getMemoryUnit() == 'gb')
+        {
+            $min = 1;
+            $max = 10;
+        }
+        $configOptions[] = [
+            Enum::OPTION_NAME         => 'Amount of RAM|Amount Of RAM',
+            Enum::OPTION_TYPE         => Enum::OPTION_TYPE_QUANTITY,
+            Enum::OPTION_QUANTITY_MIN => $min,
+            Enum::OPTION_QUANTITY_MAX => $max,
+            Enum::CONFIG_SUB_OPTIONS  => [
+                [
+                    Enum::OPTION_SUB_NAME  => "{$unit}|{$unit}",
+                    Enum::OPTION_SUB_ORDER => Enum::OPTION_SUB_ORDER_DEFAULT,
+                ]
+            ]
+        ];
+        if ($this->configuration()->isLxc())
+        {
+            $unit = strtoupper($this->configuration()->getSwapUnit());
+            $min  = 128;
+            $max  = 1024 * 10;
+            if ($this->configuration()->getSwapUnit() == 'gb')
+            {
+                $min = 1;
+                $max = 10;
+            }
+            $configOptions[] = [
+                Enum::OPTION_NAME         => 'Amount of SWAP|Amount Of SWAP',
+                Enum::OPTION_TYPE         => Enum::OPTION_TYPE_QUANTITY,
+                Enum::OPTION_QUANTITY_MIN => $min,
+                Enum::OPTION_QUANTITY_MAX => $max,
+                Enum::CONFIG_SUB_OPTIONS  => [
+                    [
+                        Enum::OPTION_SUB_NAME  => "{$unit}|{$unit}",
+                        Enum::OPTION_SUB_ORDER => Enum::OPTION_SUB_ORDER_DEFAULT,
+                    ]
+                ]
+            ];
+        }
+        $unit = strtoupper($this->configuration()->getDiskUnit());
+        $min  = 128;
+        $max  = 1024 * 1000;
+        if ($this->configuration()->getDiskUnit() == 'gb' || $this->configuration()->getDiskUnit() == 'tb')
+        {
+            $min = 1;
+            $max = 1000;
+        }
+        $configOptions[] = [
+            Enum::OPTION_NAME         => 'Disk Space|Disk Space',
+            Enum::OPTION_TYPE         => Enum::OPTION_TYPE_QUANTITY,
+            Enum::OPTION_QUANTITY_MIN => $min,
+            Enum::OPTION_QUANTITY_MAX => $max,
+            Enum::CONFIG_SUB_OPTIONS  => [
+                [
+                    Enum::OPTION_SUB_NAME  => "{$unit}|{$unit}",
+                    Enum::OPTION_SUB_ORDER => Enum::OPTION_SUB_ORDER_DEFAULT,
+                ]
+            ]
+        ];
+        $unit            = strtoupper($this->configuration()->getAdditionalDiskUnit());
+        $max             = 1024 * 1000;
+        if ($this->configuration()->getAdditionalDiskUnit() == 'gb' || $this->configuration()->getAdditionalDiskUnit() == 'tb')
+        {
+            $max = 1000;
+        }
+        $configOptions[] = [
+            Enum::OPTION_NAME         => 'additionalDisksSpace|Additional Disks Space',
+            Enum::OPTION_TYPE         => Enum::OPTION_TYPE_QUANTITY,
+            Enum::OPTION_QUANTITY_MIN => 0,
+            Enum::OPTION_QUANTITY_MAX => $max,
+            Enum::CONFIG_SUB_OPTIONS  => [
+                [
+                    Enum::OPTION_SUB_NAME  => "{$unit}|{$unit}",
+                    Enum::OPTION_SUB_ORDER => Enum::OPTION_SUB_ORDER_DEFAULT,
+                ]
+            ]
+        ];
+        $configOptions[] = [
+            Enum::OPTION_NAME         => 'IP Addresses|IPv4 Addresses',
+            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,
+                ]
+            ]
+        ];
+        $configOptions[] = [
+            Enum::OPTION_NAME         => 'IPv6 Addresses|IPv6 Addresses',
+            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,
+                ]
+            ]
+        ];
+        $configOptions[] = [
+            Enum::OPTION_NAME         => 'Backups Limit|Backups Size',
+            Enum::OPTION_TYPE         => Enum::OPTION_TYPE_QUANTITY,
+            Enum::OPTION_QUANTITY_MIN => 0,
+            Enum::OPTION_QUANTITY_MAX => 10 * 100,
+            Enum::CONFIG_SUB_OPTIONS  => [
+                [
+                    Enum::OPTION_SUB_NAME  => 'GB|GB',
+                    Enum::OPTION_SUB_ORDER => Enum::OPTION_SUB_ORDER_DEFAULT,
+                ]
+            ]
+        ];
+        $configOptions[] = [
+            Enum::OPTION_NAME         => 'Backups Files Limit|Backup Files',
+            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,
+                ]
+            ]
+        ];
+        $configOptions[] = [
+            Enum::OPTION_NAME         => 'snapshots|Snapshots',
+            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,
+                ]
+            ]
+        ];
+        $configOptions[] = [
+            Enum::OPTION_NAME         => 'snapshotJobs|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,
+                ]
+            ]
+        ];
+        $configOptions[] = [
+            Enum::OPTION_NAME         => 'Bandwidth|Bandwidth',
+            Enum::OPTION_TYPE         => Enum::OPTION_TYPE_QUANTITY,
+            Enum::OPTION_QUANTITY_MIN => 0,
+            Enum::OPTION_QUANTITY_MAX => 10 * 100,
+            Enum::CONFIG_SUB_OPTIONS  => [
+                [
+                    Enum::OPTION_SUB_NAME  => 'GB|GB',
+                    Enum::OPTION_SUB_ORDER => Enum::OPTION_SUB_ORDER_DEFAULT,
+                ]
+            ]
+        ];
+        $configOptions[] = [
+            Enum::OPTION_NAME => 'VM Template|VM Template',
+            Enum::OPTION_TYPE => Enum::OPTION_TYPE_DROPDOWN,
+        ];
+        $configOptions[] = [
+            Enum::OPTION_NAME => 'Network Rate|Network Rate',
+            Enum::OPTION_TYPE => Enum::OPTION_TYPE_DROPDOWN,
+        ];
+        if ($this->configuration()->isQemu())
+        {
+            $configOptions[] = [
+                Enum::OPTION_NAME => 'vcpus|VCPUs',
+                Enum::OPTION_TYPE => Enum::OPTION_TYPE_DROPDOWN,
+            ];
+            $configOptions[] = [
+                Enum::OPTION_NAME => 'ISO Image|ISO Image',
+                Enum::OPTION_TYPE => Enum::OPTION_TYPE_DROPDOWN,
+            ];
+            $configOptions[] = [
+                Enum::OPTION_NAME => 'osType|OS Type',
+                Enum::OPTION_TYPE => Enum::OPTION_TYPE_DROPDOWN,
+            ];
+            $configOptions[] = [
+                Enum::OPTION_NAME => 'cicustom|Custom Cloud-Init Configuration',
+                Enum::OPTION_TYPE => Enum::OPTION_TYPE_DROPDOWN,
+            ];
+            $configOptions[] = [
+                Enum::OPTION_NAME => 'ciscript|Cloud-Init Script',
+                Enum::OPTION_TYPE => Enum::OPTION_TYPE_DROPDOWN,
+            ];
+        }
+        return $configOptions;
+    }
+
+    public function cloudInitScriptGetSubOptions()
+    {
+        $subOptions = [];
+        //kvm
+        if ($this->configuration()->isQemu())
+        {
+            $subOptions[]               = [
+                Enum::OPTION_SUB_NAME  => '0|Disabled',
+                Enum::OPTION_SUB_ORDER => Enum::OPTION_SUB_ORDER_DEFAULT,
+            ];
+            foreach (CloudInitScript::get()  as $item){
+                $subOptions[] = [
+                    Enum::OPTION_SUB_NAME  => $item->id . '|' . $item->name,
+                    Enum::OPTION_SUB_ORDER => Enum::OPTION_SUB_ORDER_DEFAULT,
+                ];
+            }
+        }
+        return $subOptions;
+    }
+}

+ 7 - 0
app/Config/configuration.yml

@@ -0,0 +1,7 @@
+version: '2.7.0'
+systemName: 'proxmoxVPS'
+name: 'Proxmox VPS'
+description: 'Proxmox 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'

+ 1 - 0
app/Config/cron.yml

@@ -0,0 +1 @@
+list:

+ 1 - 0
app/Config/di/buildWithDefaultMethod.yml

@@ -0,0 +1 @@
+class: []

+ 1 - 0
app/Config/di/interface.yml

@@ -0,0 +1 @@
+interface: []

+ 2 - 0
app/Config/di/register.yml

@@ -0,0 +1,2 @@
+class:
+  - {namespace: '\\ModulesGarden\\WordpressManager\\Core\\UI\\Widget\\Sidebar\\SidebarService',                               alias: "sidebar", singleton: true ,auto: false}

+ 9 - 0
app/Config/di/rewrite.yml

@@ -0,0 +1,9 @@
+class:
+  - {old: 'ModulesGarden\\Servers\\ProxmoxVps\\Core\\Configuration\\Addon\\Config\\After',     new: 'ModulesGarden\\Servers\\ProxmoxVps\\App\\Configuration\\Addon\\Config\\After'}
+  - {old: 'ModulesGarden\\Servers\\ProxmoxVps\\Core\\Configuration\\Addon\\Activate\\After',   new: 'ModulesGarden\\Servers\\ProxmoxVps\\App\\Configuration\\Addon\\Activate\\After'}
+  - {old: 'ModulesGarden\\Servers\\ProxmoxVps\\Core\\Configuration\\Addon\\Deactivate\\After', new: 'ModulesGarden\\Servers\\ProxmoxVps\\App\\Configuration\\Addon\\Deactivate\\After'}
+  - {old: 'ModulesGarden\\Servers\\ProxmoxVps\\Core\\Configuration\\Addon\\Update\\After',     new: 'ModulesGarden\\Servers\\ProxmoxVps\\App\\Configuration\\Addon\\Update\\After'}
+  - {old: 'ModulesGarden\\Servers\\ProxmoxVps\\Core\\Configuration\\Addon\\Config\\Before',    new: 'ModulesGarden\\Servers\\ProxmoxVps\\App\\Configuration\\Addon\\Config\\Before'}
+  - {old: 'ModulesGarden\\Servers\\ProxmoxVps\\Core\\Configuration\\Addon\\Activate\\Before',  new: 'ModulesGarden\\Servers\\ProxmoxVps\\App\\Configuration\\Addon\\Activate\\Before'}
+  - {old: 'ModulesGarden\\Servers\\ProxmoxVps\\Core\\Configuration\\Addon\\Deactivate\\Before',new: 'ModulesGarden\\Servers\\ProxmoxVps\\App\\Configuration\\Addon\\Deactivate\\Before'}
+  - {old: 'ModulesGarden\\Servers\\ProxmoxVps\\Core\\Configuration\\Addon\\Update\\Before',    new: 'ModulesGarden\\Servers\\ProxmoxVps\\App\\Configuration\\Addon\\Update\\Before'}

+ 0 - 0
app/Config/di/services.yml


+ 3 - 0
app/Config/events.php

@@ -0,0 +1,3 @@
+<?php
+
+return [];

+ 3 - 0
app/Config/hooks.yml

@@ -0,0 +1,3 @@
+name:
+  AdminAreaFooterOutput: false,
+  ClientAreaPrimarySidebar: true

+ 7 - 0
app/Config/menu/admin.yml

@@ -0,0 +1,7 @@
+home:
+  icon: 'lu-nav__link-icon lu-zmdi lu-zmdi-home'
+LoggerManager:
+  icon: 'lu-nav__link-icon lu-zmdi lu-zmdi-assignment'
+documentation:
+  icon: 'lu-nav__link-icon lu-zmdi lu-zmdi-file-text'
+  externalUrl: "https://www.docs.modulesgarden.com/Domain_Orders_Extended_For_WHMCS"

+ 1 - 0
app/Config/menu/client.yml

@@ -0,0 +1 @@
+[]

+ 31 - 0
app/Config/sidebars.yml

@@ -0,0 +1,31 @@
+managementProxmoxVps:
+  reinstall:
+    uri: 'clientarea.php?action=productdetails&id={$hostingId}&modop=custom&a=management&mg-page=reinstall'
+    order: 701
+  backup:
+    order: 702
+    uri: 'clientarea.php?action=productdetails&id={$hostingId}&modop=custom&a=management&mg-page=backup'
+  backupJob:
+    order: 703
+    uri: 'clientarea.php?action=productdetails&id={$hostingId}&modop=custom&a=management&mg-page=backupJob'
+  graph:
+    order: 704
+    uri: 'clientarea.php?action=productdetails&id={$hostingId}&modop=custom&a=management&mg-page=graph'
+  taskHistory:
+    order: 705
+    uri: 'clientarea.php?action=productdetails&id={$hostingId}&modop=custom&a=management&mg-page=taskHistory'
+  network:
+    order: 706
+    uri: 'clientarea.php?action=productdetails&id={$hostingId}&modop=custom&a=management&mg-page=network'
+  snapshot:
+    order: 707
+    uri: 'clientarea.php?action=productdetails&id={$hostingId}&modop=custom&a=management&mg-page=snapshot'
+  firewall:
+    order: 708
+    uri: 'clientarea.php?action=productdetails&id={$hostingId}&modop=custom&a=management&mg-page=firewall'
+  firewallOption:
+    order: 709
+    uri: 'clientarea.php?action=productdetails&id={$hostingId}&modop=custom&a=management&mg-page=firewallOption'
+  disk:
+    order: 710
+    uri: 'clientarea.php?action=productdetails&id={$hostingId}&modop=custom&a=management&mg-page=disk'

+ 1 - 0
app/Config/ui/admin/home/index.yml

@@ -0,0 +1 @@
+

+ 23 - 0
app/Configuration/Addon/Activate/After.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\Configuration\Addon\Activate;
+
+/**
+ * Runs after module activation actions
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class After extends \ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Addon\Activate\After
+{
+
+    /**
+     * @param array $params
+     * @return array
+     */
+    public function execute(array $params = [])
+    {
+        $return = parent::execute($params);
+
+        return $return;
+    }
+}

+ 23 - 0
app/Configuration/Addon/Activate/Before.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\Configuration\Addon\Activate;
+
+/**
+ * Runs before module activation actions
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Before extends \ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Addon\Activate\Before
+{
+
+    /**
+     * @param array $params
+     * @return array
+     */
+    public function execute(array $params = [])
+    {
+        $return = parent::execute($params);
+
+        return $return;
+    }
+}

+ 23 - 0
app/Configuration/Addon/Config/After.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\Configuration\Addon\Config;
+
+/**
+ * Runs after loading module configuration
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class After extends \ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Addon\Config\After
+{
+
+    /**
+     * @param array $params
+     * @return array
+     */
+    public function execute(array $params = [])
+    {
+        $return = parent::execute($params);
+
+        return $return;
+    }
+}

+ 23 - 0
app/Configuration/Addon/Config/Before.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\Configuration\Addon\Config;
+
+/**
+ * Runs before loading module configuration
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Before extends \ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Addon\Config\Before
+{
+
+    /**
+     * @param array $params
+     * @return array
+     */
+    public function execute(array $params = [])
+    {
+        $return = parent::execute($params);
+
+        return $return;
+    }
+}

+ 23 - 0
app/Configuration/Addon/Deactivate/After.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\Configuration\Addon\Deactivate;
+
+/**
+ * Runs after addon deactivation
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class After extends \ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Addon\Deactivate\After
+{
+
+    /**
+     * @param array $params
+     * @return array
+     */
+    public function execute(array $params = [])
+    {
+        $return = parent::execute($params);
+
+        return $return;
+    }
+}

+ 23 - 0
app/Configuration/Addon/Deactivate/Before.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\Configuration\Addon\Deactivate;
+
+/**
+ * Runs before addon deactivation
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Before extends \ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Addon\Deactivate\Before
+{
+
+    /**
+     * @param array $params
+     * @return array
+     */
+    public function execute(array $params = [])
+    {
+        $return = parent::execute($params);
+
+        return $return;
+    }
+}

+ 0 - 0
app/Configuration/Addon/Others/.gitkeep


+ 22 - 0
app/Configuration/Addon/Update/After.php

@@ -0,0 +1,22 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\Configuration\Addon\Update;
+
+/**
+ * runs after module update actions
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class After extends \ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Addon\Update\After
+{
+
+    /**
+     * @param array $params
+     * @return array
+     */
+    public function execute(array $params = [])
+    {
+        $return = parent::execute($params);
+        return $return;
+    }
+}

+ 22 - 0
app/Configuration/Addon/Update/Before.php

@@ -0,0 +1,22 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\Configuration\Addon\Update;
+
+/**
+ * runs before module update actions
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Before extends \ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Addon\Update\Before
+{
+
+    /**
+     * @return array
+     */
+    public function execute($version)
+    {
+        $return = parent::execute($version);
+
+        return $return;
+    }
+}

+ 29 - 0
app/Configuration/Addon/Update/Patch/M2M7P0.php

@@ -0,0 +1,29 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\Configuration\Addon\Update\Patch;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Addon\Update\Patch\AbstractPatch;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+
+/**
+ * Description of M2M6P0
+ *
+ * @author <slawomir@modulesgarden.com>
+ */
+class M2M7P0 extends AbstractPatch
+{
+    public function execute()
+    {
+        if ($this->runSchema())
+        {
+            sl('logger')
+                ->addDebug("Correctly installed update {$this->getVersion()} .", []);
+        }
+        else
+        {
+            sl('errorManager')
+                ->addError(self::class, "Incorrectly installed update {$this->getVersion()} .", []);
+        }
+
+    }
+}

+ 31 - 0
app/Cron/MainCron.php

@@ -0,0 +1,31 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\Cron;
+
+use ModulesGarden\Servers\ProxmoxVps\App\Helpers\ProxmoxAddonValidator;
+use ModulesGarden\Servers\ProxmoxVps\Core\ModuleConstants;
+use Symfony\Component\Console\Input\ArgvInput;
+use Symfony\Component\Console\Output\ConsoleOutput;
+use Symfony\Component\Console\Style\SymfonyStyle;
+
+class MainCron extends \ModulesGarden\ProxmoxAddon\Core\CommandLine\CronManager
+{
+
+    public function  run(){
+
+        ProxmoxAddonValidator::isInstalledOrFail();
+        $this->loadCommandsControllers($this->getCommands());
+        $input = new ArgvInput();
+        $output = new ConsoleOutput();
+        $this->configureIO($input, $output);
+        $io = new SymfonyStyle($input, $output);
+        $io->error(sprintf("This cron is depracted since version 2.7.0, please run: %s",
+            ModuleConstants::getFullPathWhmcs() . DS .'modules'. DS .'addons'. DS .'proxmoxAddon'.DS.'cron'.DS.'cron.php'));
+        //queue
+        $command = $this ->find('queue');
+        $command->run(  $input, $output , $io );
+        //update-server-usage
+        $command = $this ->find('update-server-usage');
+        $command->run(  $input, $output, $io  );
+    }
+}

+ 0 - 0
app/Database/data.sql


+ 0 - 0
app/Database/schema.sql


+ 31 - 0
app/Enum/ConfigurableOption.php

@@ -0,0 +1,31 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\Enum;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\Enum\Enum;
+
+final  class ConfigurableOption extends Enum
+{
+    const SOCKETS              = "The number of CPU sockets";
+    const CORES_PER_SOCKET     = "The number of cores per socket";
+    const CORES                = "cores";
+    const CPU_LIMIT            = "cpulimit";
+    const CPU_UNITS            = "CPU weight for a VM";
+    const MEMORY               = "Amount of RAM";
+    const DISK_SIZE            = "Disk Space";
+    const ADDITIONAL_DISKS_SIZE = "additionalDisksSpace";
+    const IPV4                 = "IP Addresses";
+    const IPV6                 = "IPv6 Addresses";
+    const SWAP                 = "Amount of SWAP";
+    const BACKUPS_SIZE         = "Backups Limit";
+    const BACKUPS_FILES        = "Backups Files Limit";
+    const SNAPSHOTS            = "snapshots";
+    const OS_TEMPLATE          = "VM Template";
+    const NETWORK_RATE         = "Network Rate";
+    const VCPUS                = "vcpus";
+    const ISO_IMAGE            = "ISO Image";
+    const OS_TYPE              = "osType";
+    const BANDWIDTH = 'Bandwidth';
+    const SNAPSHOT_JOBS = 'snapshotJobs';
+    const CICUSTOM = 'cicustom';
+}

+ 19 - 0
app/Enum/CustomField.php

@@ -0,0 +1,19 @@
+<?php
+
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\Enum;
+
+
+use ModulesGarden\Servers\ProxmoxVps\Core\Enum\Enum;
+
+class CustomField extends  Enum
+{
+    const VMID = 'vmid';
+    const NODE =  'node';
+    const TAG = 'VLAN Tag';
+    const USERNAME ='userName';
+    const SSH_PUBLIC_KEY = 'sshkeys';
+    const HOSTNAME = 'proxmoxHostname';
+    const CI_USER = 'ciuser';
+
+}

+ 15 - 0
app/Enum/JobPeriod.php

@@ -0,0 +1,15 @@
+<?php
+
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\Enum;
+
+
+use ModulesGarden\Servers\ProxmoxVps\Core\Enum\Enum;
+
+final class JobPeriod extends  Enum
+{
+    const DAILY = 'daily';
+    const HOURLY =  'hourly';
+    const DAYS_OF_WEEK = ['Monday', 'Tuesday',  'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday' ];
+
+}

+ 20 - 0
app/Helpers/AppParams.php

@@ -0,0 +1,20 @@
+<?php
+
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\Helpers;
+
+
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+
+class AppParams
+{
+
+    public function initFromWhmcsParams(){
+        \ModulesGarden\ProxmoxAddon\Core\Helper\sl('whmcsParams')->setParams(sl('whmcsParams')->getWhmcsParams());
+    }
+
+    public function initFromParams($params){
+        \ModulesGarden\ProxmoxAddon\Core\Helper\sl('whmcsParams')->setParams($params);
+    }
+
+}

+ 37 - 0
app/Helpers/BuildUrl.php

@@ -0,0 +1,37 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\Helpers;
+
+/*
+File:   BuildUrl.php
+Date:   28.05.2020
+Author: Tomasz Bielecki (tomasz.bi@modulesgarden.com)
+Class BuildUrl
+*/
+
+class BuildUrl extends \ModulesGarden\Servers\ProxmoxVps\Core\Helper\BuildUrl
+{
+
+    public static function getSelfUrl()
+    {
+        $host   = $GLOBALS['CONFIG']['SystemURL'] ? $GLOBALS['CONFIG']['SystemURL'] : $_SERVER['HTTP_HOST'];
+        $url = \parse_url( $host );
+        $surfix = $_SERVER['PHP_SELF'];
+
+        $parms = $_GET;
+        $url = "{$url['scheme']}://{$url['host']}{$surfix}";
+        if($parms)
+        {
+            $url = $url.'?'.http_build_query($parms);
+        }
+
+        return $url;
+    }
+
+
+    public static function isClientArea()
+    {
+        return defined('CLIENTAREA');
+    }
+
+}

+ 15 - 0
app/Helpers/ErrorCodesLib.php

@@ -0,0 +1,15 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\Helpers;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\ErrorCodes\ErrorCodes;
+
+class ErrorCodesLib extends ErrorCodes
+{
+    const YOUR_APP_000001 = [
+        self::MESSAGE     => 'Your error message',
+        self::CODE        => 'YOUR_APP_000001',
+        self::DEV_MESSAGE => "Your error message left for other developers, the error genesis explanation...",
+        self::LOG         => true //optional, determines if the error should be logged despite of inactive debug mode 
+    ];
+}

+ 11 - 0
app/Helpers/ProxmoxAddonNotInstalledException.php

@@ -0,0 +1,11 @@
+<?php
+
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\Helpers;
+
+
+class  ProxmoxAddonNotInstalledException extends \Exception
+{
+
+
+}

+ 30 - 0
app/Helpers/ProxmoxAddonValidator.php

@@ -0,0 +1,30 @@
+<?php
+
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\Helpers;
+
+
+class ProxmoxAddonValidator
+{
+    const ERROR_MESSAGE = 'ProxmoxAddon is not installed or activated';
+
+    public static function isInstalled(){
+
+        if(!class_exists('\ModulesGarden\ProxmoxAddon\Core\ModuleConstants') ){
+            return false;
+        }
+        return !is_null(\ModulesGarden\ProxmoxAddon\Core\ModuleConstants::getModuleRootDir());
+    }
+
+    public static function isInstalledOrFail(){
+        if(!self::isInstalled()){
+            throw new ProxmoxAddonNotInstalledException(self::ERROR_MESSAGE);
+        }
+    }
+
+    public static function failAsString(){
+        return self::ERROR_MESSAGE;
+    }
+
+
+}

+ 65 - 0
app/Helpers/UrlServiceHelper.php

@@ -0,0 +1,65 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\Helpers;
+
+/*
+File:   UrlServiceHelper.php
+Date:   15.06.2020
+Author: Tomasz Bielecki (tomasz.bi@modulesgarden.com)
+Class UrlServiceHelper
+*/
+
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\UrlService;
+use ModulesGarden\Servers\ProxmoxVps\App\Helpers\BuildUrl;
+
+/**
+ * Class UrlServiceHelper
+ * @package ModulesGarden\Servers\ProxmoxVps\App\Helpers
+ */
+class UrlServiceHelper
+{
+
+    /**
+     * @var \ModulesGarden\ProxmoxAddon\App\Services\Vps\UrlService
+     */
+    protected $urlService;
+
+    /**
+     * UrlServiceHelper constructor.
+     */
+    public function __construct()
+    {
+        $this->urlService = new UrlService();
+    }
+
+    /**
+     * @return string
+     */
+    public function getXTermConsoleUrl()
+    {
+        return BuildUrl::isClientArea() ? $this->urlService->getUrl('console', 'xtermjs') : BuildUrl::getSelfUrl().'&mg-action=xtermjs';
+    }
+
+    /**
+     * @return string
+     */
+    public function getNoVncConsoleUrl()
+    {
+        return BuildUrl::isClientArea() ? $this->urlService->getUrl('console', 'novnc') : BuildUrl::getSelfUrl().'&mg-action=novnc';
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getSpiceConsoleUrl()
+    {
+        return $this->urlService->getUrl('console', 'spice');
+    }
+
+    public function home()
+    {
+        return $this->urlService->getUrl();
+    }
+
+
+}

+ 40 - 0
app/Hooks/AdminAreaFooterOutput.php

@@ -0,0 +1,40 @@
+<?php
+/* * ********************************************************************
+*  ProxmoxVPS Product developed. (26.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.
+*
+*
+* ******************************************************************** */
+
+use ModulesGarden\Servers\ProxmoxVps\Core\Hook\HookIntegrator;
+
+$hookManager->register(
+    function ($args)
+    {
+        $hookIntegrator = new HookIntegrator($args);
+
+        /**
+         * @var $toReturn is a HTML integration code (or null if no integration was made)
+         * you can add your code to this var before returning its content,
+         * do not overwrite this var!
+         */
+        $toReturn = $hookIntegrator->getHtmlCode();
+
+        if ($toReturn)
+        {
+            return $toReturn;
+        }
+    },
+    100
+);

+ 31 - 0
app/Hooks/AdminProductConfigFieldsSave.php

@@ -0,0 +1,31 @@
+<?php
+/* * ********************************************************************
+*  ProxmoxVPS Product developed. (26.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.
+*
+*
+* ******************************************************************** */
+
+use ModulesGarden\Servers\ProxmoxVps as main;
+
+$hookManager->register(
+    function ($args)
+    {
+        $provider = new main\App\UI\Admin\Product\Providers\ProductProvider($args['pid']);
+        if (!$provider->isSupportedModule())
+        {
+            return;
+        }
+        $provider->update();
+    }, 1001);

+ 364 - 0
app/Hooks/ClientAreaHeadOutput.php

@@ -0,0 +1,364 @@
+<?php
+/* * ********************************************************************
+*  ProxmoxVPS Product developed. (26.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.
+*
+*
+* ******************************************************************** */
+
+use Illuminate\Database\Capsule\Manager as DB;
+use ModulesGarden\ProxmoxAddon\App\Repositories\Vps\ProductConfigurationRepository;
+use ModulesGarden\Servers\ProxmoxVps\App\Enum\ConfigurableOption;
+
+$hookManager->register(
+    function ($vars)
+    {
+        if ($vars['filename'] != 'upgrade' || $_REQUEST['step'] != 2)
+        {
+            return;
+        }
+        try
+        {
+            if (!function_exists('ModuleBuildParams'))
+            {
+                require_once ROOTDIR . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . "modulefunctions.php";
+            }
+            global $smartyvalues;
+            $displayUpgradePage = true;
+            /* @var $request \ModulesGarden\Servers\ProxmoxVps\Core\Http\Request */
+            $request = \ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl("request");
+            /**
+             * @var \ModulesGarden\Servers\ProxmoxVps\Core\Lang\Lang $lang
+             */
+            $lang      = \ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl("lang");
+            $serviceId = $request->get('id');
+            $h         = 'tblhosting';
+            $p         = 'tblproducts';
+            $hosting   = \WHMCS\Service\Service::select("{$h}.*")
+                ->leftJoin($p, "{$p}.id", '=', "{$h}.packageid")
+                ->where("{$h}.id", $serviceId)
+                ->where("{$h}.userid", $request->getSession('uid'))
+                ->where("{$p}.servertype", 'proxmoxVPS')
+                ->first();
+            if (!$hosting)
+            {
+                return;
+            }
+            // Disk Downsize Protection chosen product as smaller disk size than the current server disk size
+            if ($request->get('type') && $request->get('pid') && $request->get('type') == "package")
+            {
+                $newProductId = $request->get('pid');
+                $newProduct   = new ProductConfigurationRepository($newProductId);
+                $newDisk      = $newProduct->getDiskSize();
+                \ModulesGarden\ProxmoxAddon\App\Services\Utility::unitFormat($newDisk, "gb", 'bytes');
+                //Current
+                $product = new ProductConfigurationRepository($hosting->productId);
+                $disk    = $product->getDiskSize();
+                \ModulesGarden\ProxmoxAddon\App\Services\Utility::unitFormat($disk, "gb", 'bytes');
+                if ($newDisk < $disk)
+                {
+                    $newSize                    = \ModulesGarden\ProxmoxAddon\App\Libs\Format::convertBytes($newDisk);
+                    $size                       = \ModulesGarden\ProxmoxAddon\App\Libs\Format::convertBytes($disk);
+                    $smartyvalues['promoerror'] = $lang->abtr("You cannot select a product which disk size is lower than the one you currently have.");
+                    $displayUpgradePage         = false;
+                }
+            }
+            else
+            {
+                if ($request->get('configoption'))
+                { //chosen configurable option value for disk size is smaller than the current server disksize
+                    $configoptions = getCartConfigOptions($hosting->productId, $request->get('configoption'), $hosting->billingcycle);
+                    $params        = \ModuleBuildParams($hosting->id);
+                    $product       = new ProductConfigurationRepository($hosting->productId);
+                    if ($params['configoptions'][ConfigurableOption::DISK_SIZE])
+                    {
+                        $disk = $params['configoptions'][ConfigurableOption::DISK_SIZE];
+                        \ModulesGarden\ProxmoxAddon\App\Services\Utility::unitFormat($disk, $product->getDiskUnit(), 'bytes');
+                    }
+                    else
+                    {
+                        $disk = $product->getDiskSize();
+                        \ModulesGarden\ProxmoxAddon\App\Services\Utility::unitFormat($disk, "gb", 'bytes');
+                    }
+                    //additional disks size
+                    if (isset($params['configoptions'][ConfigurableOption::ADDITIONAL_DISKS_SIZE]))
+                    {
+                        $additionalDisksSpace = $params['configoptions'][ConfigurableOption::ADDITIONAL_DISKS_SIZE];
+                        \ModulesGarden\ProxmoxAddon\App\Services\Utility::unitFormat($additionalDisksSpace, $product->getAdditionalDiskUnit(), 'bytes');
+                    }
+                    else
+                    {
+                        $additionalDisksSpace =  $product->getAdditionalDiskSize();
+                        \ModulesGarden\ProxmoxAddon\App\Services\Utility::unitFormat($additionalDisksSpace, "gb", 'bytes');
+                    }
+                    foreach ($configoptions as $configoption)
+                    {
+                        if (isset($params['configoptions']['']) || $configoption['hidden'])
+                        {
+                            continue;
+                        }
+                        $moduleName = DB::table('tblproductconfigoptions')->where('id', $configoption['id'])->value('optionname');
+                        if (preg_match('/\|/', $moduleName))
+                        {
+                            $ex         = explode("|", $moduleName);
+                            $moduleName = $ex[0];
+                        }
+                        if (!$moduleName || !isset($params['configoptions'][$moduleName]))
+                        {
+                            continue;
+                        }
+                        if ($configoption['selectedqty'] != 0)
+                        {
+                            $params['configoptions'][$moduleName] = $configoption['selectedqty'];
+                            continue;
+                        }
+                        foreach ($configoption['options'] as $option)
+                        {
+                            if ($configoption['selectedvalue'] == $option['id'])
+                            {
+                                if (preg_match('/\|/', $option['rawName']))
+                                {
+                                    $ex                = explode("|", $option['rawName']);
+                                    $option['rawName'] = $ex[0];
+                                }
+                                $params['configoptions'][$moduleName] = $option['rawName'];
+                                break;
+                            }
+                        }
+                    }
+                    if ($params['configoptions'][ConfigurableOption::DISK_SIZE])
+                    {
+                        $newDisk = $params['configoptions'][ConfigurableOption::DISK_SIZE];
+                        \ModulesGarden\ProxmoxAddon\App\Services\Utility::unitFormat($newDisk, $product->getDiskUnit(), 'bytes');
+                    }
+                    else
+                    {
+                        $newDisk = $product->getDiskSize();
+                        \ModulesGarden\ProxmoxAddon\App\Services\Utility::unitFormat($newDisk, "gb", 'bytes');
+                    }
+                    if ($newDisk < $disk)
+                    {
+                        $newSize                    = \ModulesGarden\ProxmoxAddon\App\Libs\Format::convertBytes($newDisk);
+                        $size                       = \ModulesGarden\ProxmoxAddon\App\Libs\Format::convertBytes($disk);
+                        $smartyvalues['promoerror'] = sprintf($lang->abtr("You are not able to set %s of Disk Size. Current Disk Size: %s. Disk downgrading is not supported."), $newSize, $size);
+                        $displayUpgradePage         = false;
+                    }
+                    //Additonal Disk Downsize Protection
+                    if (isset($params['configoptions'][ConfigurableOption::ADDITIONAL_DISKS_SIZE]))
+                    {
+                        $newAdditionalDisksSpace = $params['configoptions'][ConfigurableOption::ADDITIONAL_DISKS_SIZE];
+                        \ModulesGarden\ProxmoxAddon\App\Services\Utility::unitFormat($newAdditionalDisksSpace, $product->getAdditionalDiskUnit(), 'bytes');
+                    }
+                    else
+                    {
+                        $newAdditionalDisksSpace =  $product->getAdditionalDiskSize();
+                        \ModulesGarden\ProxmoxAddon\App\Services\Utility::unitFormat($newAdditionalDisksSpace, "gb", 'bytes');
+                    }
+                    if($newAdditionalDisksSpace < $additionalDisksSpace && $params['customfields']['node'] && $params['customfields']['vmid']){
+                        $api = \MGProvision\Proxmox\v2\Factory::api($params);
+                        $vm = \MGProvision\Proxmox\v2\Factory::vmVps($product, $params);
+                        $vm->setApi($api);
+                        $used = 0;
+                        if($vm instanceof  \MGProvision\Proxmox\v2\models\Lxc){
+                            $used = $vm->getMounPoints()->additionalSizeToBytes();
+                        }elseif ($vm instanceof  \MGProvision\Proxmox\v2\models\Kvm){
+                            foreach ($vm->getHardDisks() as $hd){
+                                if($hd->isMaster()){
+                                    continue;
+                                }
+                                $used += $hd->getBytes();
+                            }
+                        }
+                        if($used > $newAdditionalDisksSpace){
+                            $smartyvalues['promoerror'] = $lang->abtr("Disk downgrading is not possible until you remove additional disks.");
+                            $displayUpgradePage = false;
+                        }
+                    }
+                }
+            }
+            $isLoadBalancer = \ModulesGarden\ProxmoxAddon\App\Models\ProductConfiguration::ofProductId($hosting->productId)->ofSetting("loadBalancer")->ofValue('"on"')->count();
+            //LoadBalancer is enabled?
+            if ($isLoadBalancer && $displayUpgradePage)
+            {
+                $product = new ProductConfigurationRepository($hosting->productId);
+                //LoadBalancer on upgrade
+                $onUpgrade = $product->getLoadBalancerOnUpgrade();
+                if ($onUpgrade == "none" || !$onUpgrade)
+                {
+                    return;
+                }
+
+                $configoptions = getCartConfigOptions($hosting->productId, $request->get('configoption'), $hosting->billingcycle);
+                $params        = \ModuleBuildParams($hosting->id);
+                foreach ($configoptions as $configoption)
+                {
+                    if (isset($params['configoptions']['']) || $configoption['hidden'])
+                    {
+                        continue;
+                    }
+                    $moduleName = DB::table('tblproductconfigoptions')->where('id', $configoption['id'])->value('optionname');
+                    if (preg_match('/\|/', $moduleName))
+                    {
+                        $ex         = explode("|", $moduleName);
+                        $moduleName = $ex[0];
+                    }
+                    if (!$moduleName || !isset($params['configoptions'][$moduleName]))
+                    {
+                        continue;
+                    }
+                    if ($configoption['selectedqty'] != 0)
+                    {
+                        $params['configoptions'][$moduleName] = $configoption['selectedqty'];
+                        continue;
+                    }
+                    foreach ($configoption['options'] as $option)
+                    {
+                        if ($configoption['selectedvalue'] == $option['id'])
+                        {
+                            if (preg_match('/\|/', $option['rawName']))
+                            {
+                                $ex                = explode("|", $option['rawName']);
+                                $option['rawName'] = $ex[0];
+                            }
+                            $params['configoptions'][$moduleName] = $option['rawName'];
+                            break;
+                        }
+                    }
+                }
+                $loadBalancer = new \ModulesGarden\ProxmoxAddon\App\Services\LoadBalancerService($params['serverid']);
+                $api          = \MGProvision\Proxmox\v2\Api::whmcsFactory($params);
+                $api->debug(\ModulesGarden\ProxmoxAddon\App\Models\ModuleSettings::isDebug());
+                $loadBalancer->setApi($api);
+                if ($product->isQemu())
+                {
+                    $socket = $params['configoptions'][ConfigurableOption::SOCKETS] ? $params['configoptions'][ConfigurableOption::SOCKETS] : $product->getSockets();
+                    $cores  = $params['configoptions'][ConfigurableOption::CORES_PER_SOCKET] ? $params['configoptions'][ConfigurableOption::CORES_PER_SOCKET] : $product->getCores();
+                    $cpu    = $socket * $cores;
+                }
+                else
+                {
+                    if ($product->isLxc())
+                    {
+                        $cpu = $params['configoptions'][ConfigurableOption::CORES] ? $params['configoptions'][ConfigurableOption::CORES] : $product->getCores();
+                    }
+                }
+                //disk
+                if ($params['configoptions'][ConfigurableOption::DISK_SIZE])
+                {
+                    $newDisk = $params['configoptions'][ConfigurableOption::DISK_SIZE];
+                    \ModulesGarden\ProxmoxAddon\App\Services\Utility::unitFormat($newDisk, $product->getDiskUnit(), 'bytes');
+                }
+                else
+                {
+                    $newDisk = $product->getDiskSize();
+                    \ModulesGarden\ProxmoxAddon\App\Services\Utility::unitFormat($newDisk, "gb", 'bytes');
+                }
+                //ram
+                if ($params['configoptions'][ConfigurableOption::MEMORY])
+                {
+                    $ram = $params['configoptions'][ConfigurableOption::MEMORY];
+                    \ModulesGarden\ProxmoxAddon\App\Services\Utility::unitFormat($ram, $product->getMemoryUnit(), 'bytes');
+                }
+                else
+                {
+                    $ram = $product->getMemory();
+                    \ModulesGarden\ProxmoxAddon\App\Services\Utility::unitFormat($ram, "mb", 'bytes');
+                }
+                $loadBalancer->setExcludeVmid($params['customfields']['vmid']);
+                //Upgrade on current node
+                if ($onUpgrade == "block")
+                {
+                    $loadBalancerNodes = $loadBalancer->findByNode($params['customfields']['node']);
+                    $loadBalancerNodes = $loadBalancerNodes->findByRam($ram)
+                        ->findByCpu($cpu)
+                        ->findByDisk($disk);
+                    if (!$loadBalancerNodes->isEmpty())
+                    {
+                        return;
+                    }
+                    $smartyvalues['promoerror'] = $lang->abtr("You cannot upgrade there no free resurces on our server");
+                    $displayUpgradePage         = false;
+                }
+                else
+                {
+                    if ($onUpgrade == "migrate")
+                    {
+                        try
+                        {
+                            $loadBalancerNodes = $loadBalancer->findByNode($params['customfields']['node']);
+                            $loadBalancerNodes = $loadBalancerNodes->findByRam($ram)
+                                ->findByCpu($cpu)
+                                ->findByDisk($disk);
+                            if (!$loadBalancerNodes->isEmpty())
+                            {
+                                return;
+                            }
+                            $loadBalancerNodes = $loadBalancer->findByVmCreate();
+                            $nodesForUser      = $loadBalancer->findNotUser($params['userid']);
+                            if (!$nodesForUser->isEmpty())
+                            {
+                                $loadBalancerNodes = $nodesForUser;
+                            }
+                            $targetNode = $loadBalancerNodes->findByRam($ram)
+                                ->findByCpu($cpu)
+                                ->findByDisk($disk)
+                                ->findByVms(1)
+                                ->nodeLowLoad();
+
+                            $smartyvalues['promoerror'] = $lang->abtr("Your machine will be migrated to another server");
+                        }
+                        catch (\Exception $ex)
+                        {
+                            $smartyvalues['promoerror'] = $lang->abtr("You cannot migrate there no free resurces on our server");
+                            $displayUpgradePage         = false;
+                        }
+                    }
+                }
+            }
+            if (!$displayUpgradePage)
+            {
+                return '<script type="text/javascript">
+                        $(document).ready(function(){
+                            //six
+                            if($(".main-content .table").size()){
+                                     $(".main-content .table").hide();
+                                     $(".main-content .alert-info").hide();
+                                     $(".main-content .row").hide();
+                                     $(".main-content .form-group .btn").hide();
+                                     var form  = $(".container .row .panel .panel-footer form").clone();
+                                     $(".main-content .form-group.text-center").append(form );
+                                     $(".main-content .form-group.text-center .btn-block ").removeClass("btn-block");
+                            }
+                            //Control
+                             if($("#main-content .col-md-12").size()){
+                                  $("#main-content .col-md-12").hide();
+                             }
+                           
+                        });
+                    </script>';
+            }
+        }
+        catch (\Exception $ex)
+        {
+            logModuleCall(
+                'ProxmoxVPS',
+                __FUNCTION__,
+                $vars,
+                $ex->getMessage(),
+                $ex->getTraceAsString()
+            );
+        }
+
+    }
+);

+ 63 - 0
app/Hooks/ClientAreaPrimarySidebar.php

@@ -0,0 +1,63 @@
+<?php
+/* * ********************************************************************
+*  ProxmoxVPS Product developed. (26.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.
+*
+*
+* ******************************************************************** */
+
+
+$hookManager->register(
+    function (\WHMCS\View\Menu\Item $primarySidebar)
+    {
+        if(!\ModulesGarden\Servers\ProxmoxVps\App\Helpers\ProxmoxAddonValidator::isInstalled()){
+            return;
+        }
+        /**
+         * @var  main\Core\Http\Request $request
+         */
+        $request = \ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl('request');
+        if (!$request->get('id'))
+        {
+            return;
+        }
+        $clientAreaSideBar = new \ModulesGarden\ProxmoxAddon\App\Services\Vps\ClientAreaSidebarService($request->get("id"), $primarySidebar);
+        if (!$clientAreaSideBar->isActive() || !$clientAreaSideBar->isSupportedModule())
+        {
+            return;
+        }
+        if (!function_exists('ModuleBuildParams'))
+        {
+            require_once \ModulesGarden\Servers\ProxmoxVps\Core\ModuleConstants::getFullPathWhmcs('includes') . DIRECTORY_SEPARATOR . "modulefunctions.php";
+        }
+        $params = \ModuleBuildParams($request->get("id"));
+        \ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl("whmcsParams")->setParams($params);
+        if(!$clientAreaSideBar->isVpsCreated()){
+            return;
+        }
+        //Page Cancel
+        if ($request->get('action') == "cancel")
+        {
+            $clientAreaSideBar->informationReplaceUri();
+        } //Page Productdetails
+        else
+        {
+            if ($request->get('action') == "productdetails")
+            {
+                $clientAreaSideBar->informationReplaceUri();
+                $clientAreaSideBar->build();
+            }
+        }
+    }, 943
+);

+ 31 - 0
app/Hooks/ProductDelete.php

@@ -0,0 +1,31 @@
+<?php
+/* * ********************************************************************
+*  ProxmoxVPS Product developed. (26.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.
+*
+*
+* ******************************************************************** */
+
+
+$hookManager->register(
+    function ($args)
+    {
+        $provider = new \ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Providers\ProductProvider($args['pid']);
+        if (!$provider->isSupportedModule())
+        {
+            return;
+        }
+        $provider->delete();
+    }
+);

+ 44 - 0
app/Hooks/ServiceDelete.php

@@ -0,0 +1,44 @@
+<?php
+/* * ********************************************************************
+*  ProxmoxVPS Product developed. (26.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.
+*
+*
+* ******************************************************************** */
+
+use ModulesGarden\ProxmoxAddon\App\Models\SnapshotJob;
+
+$hookManager->register(
+    function ($vars)
+    {
+
+        if (!$vars['serviceid'])
+        {
+            return;
+        }
+        $serviceid = $vars['serviceid'];
+        try
+        {
+            \ModulesGarden\ProxmoxAddon\App\Models\Job::ofHostingId($serviceid)->delete();
+            \ModulesGarden\ProxmoxAddon\App\Models\VmIpAddress::ofHostingId($serviceid)->delete();
+            \ModulesGarden\ProxmoxAddon\App\Models\User::ofHostingId($serviceid)->delete();
+            \ModulesGarden\ProxmoxAddon\App\Models\IpAddress::ofHostingId($serviceid)->update(["hosting_id" => "0"]);
+            //snapshot jobs
+            SnapshotJob::ofHostingId($serviceid)->delete();
+        }
+        catch (\Exception $ex)
+        {
+        }
+    }
+);

+ 64 - 0
app/Http/Actions/AdminServicesTabFields.php

@@ -0,0 +1,64 @@
+<?php
+/**********************************************************************
+ * ProxmoxVPS developed. (26.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\ProxmoxVps\App\Http\Actions;
+
+use ModulesGarden\ProxmoxAddon\App\Configuration\Addon\Update\AddonUpgradeService;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\Helpers\AppParams;
+use ModulesGarden\Servers\ProxmoxVps\App\Helpers\ProxmoxAddonValidator;
+use ModulesGarden\Servers\ProxmoxVps\App\Http\Admin\Home;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Validators\Validator;
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\AddonController;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Traits\WhmcsParams;
+
+class AdminServicesTabFields extends AddonController
+{
+    use WhmcsParams;
+    use ProductService;
+    use ApiService;
+
+    /**
+     * @var AddonUpgradeService
+     */
+    private $addonUpgradeService;
+
+    public function execute($params = null)
+    {
+        $action = $this->getRequestValue('mg-action') ? $this->request->get('mg-action') : 'index';
+
+        if ($params['status'] != "Active" || !$params["customfields"]["vmid"])
+        {
+            return [];
+        }
+        try {
+            ProxmoxAddonValidator::isInstalledOrFail();
+            (new AppParams())->initFromWhmcsParams();
+            $this->addonUpgradeService = new AddonUpgradeService();
+            $this->addonUpgradeService->run();
+            $this->vm()->status();
+            return [Home::class, $action];
+        } catch (\Exception $ex) {
+
+            return ["Error" => "<span style='color: red'>" . $ex->getMessage() . "</span>"];
+        }
+
+    }
+}

+ 331 - 0
app/Http/Actions/ChangePackage.php

@@ -0,0 +1,331 @@
+<?php
+/**********************************************************************
+ * ProxmoxVPS developed. (26.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\ProxmoxVps\App\Http\Actions;
+
+use Illuminate\Database\Capsule\Manager as DB;
+use ModulesGarden\ProxmoxAddon\App\Events\Vps\LxcUpdateEvent;
+use ModulesGarden\ProxmoxAddon\App\Events\Vps\QemuUpdateEvent;
+use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\Agent\ConfigureNetworkJob;
+use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\LoadBalancer as LoadBalancer;
+use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\RebootVmJob;
+use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\Reinstall\BackupVmJob;
+use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\Reinstall\CreateVmJob;
+use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\Reinstall\DeleteVmJob;
+use ModulesGarden\ProxmoxAddon\App\Libs\Format;
+use ModulesGarden\ProxmoxAddon\App\Models\Job;
+use ModulesGarden\ProxmoxAddon\App\Models\Whmcs\ToDoList;
+use ModulesGarden\ProxmoxAddon\App\Models\Whmcs\Upgrade;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\EmailService;
+use ModulesGarden\ProxmoxAddon\App\Services\LoadBalancerService;
+use ModulesGarden\ProxmoxAddon\App\Services\Utility;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\HostingService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\IpSetIpFilterService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\NetworkService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\UserService;
+use ModulesGarden\Servers\ProxmoxVps\App\Helpers\AppParams;
+use ModulesGarden\Servers\ProxmoxVps\App\Helpers\ProxmoxAddonValidator;
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\AddonController;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Traits\WhmcsParams;
+use function ModulesGarden\ProxmoxAddon\Core\Helper\fire;
+use function ModulesGarden\ProxmoxAddon\Core\Helper\queue;
+use function ModulesGarden\ProxmoxAddon\Core\Helper\sl;
+use ModulesGarden\Servers\ProxmoxVps\App\Enum\ConfigurableOption;
+
+
+class ChangePackage extends AddonController
+{
+    use WhmcsParams;
+    use ApiService;
+    use ProductService;
+    use UserService;
+    use HostingService;
+    /**
+     * @var NetworkService
+     */
+    private $networkService;
+    /**
+     * @var IpSetIpFilterService
+     */
+    private $ipSetIpFilterService;
+    /**
+     * @var EmailService
+     */
+    private $emailService;
+
+    /**
+     * ChangePackage constructor.
+     * @param $networkService
+     */
+    public function __construct()
+    {
+        $this->networkService       = new NetworkService();
+        $this->ipSetIpFilterService = new IpSetIpFilterService();
+        $this->emailService         = new EmailService();
+    }
+
+    public function execute($params = null)
+    {
+        if(!ProxmoxAddonValidator::isInstalled()){
+            return ProxmoxAddonValidator::failAsString();
+        }
+        (new AppParams())->initFromWhmcsParams();
+        try
+        {
+            $this->manuallyUpgrade();
+            //Disk
+            $this->diskSizeValidation();
+            $this->createReinstallJob();
+            //Add IP Addresses
+            if (!Utility::isIpManagerProxmoxVPSIntegration())
+            {
+                list($requestIPv4, $requestIPv6) = $this->networkService->getIpAddressesRequest();
+
+                $this->networkService->hasIp($requestIPv4, $requestIPv6, $this->vm()->getNode())
+                    ->addIp($requestIPv4, $requestIPv6, $this->vm()->getNode());
+            }
+            //Unassing ip addresses and  delete network
+            if(!Utility::isIpManagerProxmoxVPSIntegration())
+            {
+                $this->networkService->unassignIpAddressesAndDeleteNetwork();
+            }
+
+            //Load Balancer
+            if (!Job::waiting()->ofHostingId($this->getWhmcsParamByKey("serviceid"))->ofJob(LoadBalancer\UpgradeVmJob::class)->count() && $this->configuration()->isLoadBalancer() && in_array($this->configuration()->getLoadBalancerOnUpgrade(), ["block", "migrate"]))
+            {
+                $loadBalancer = new LoadBalancerService($this->getWhmcsParamByKey('serverid'));
+                $loadBalancer->setApi($this->api());
+                //Disk
+                $disk = $this->configuration()->getDiskSize();
+                Utility::unitFormat($disk, "gb", 'bytes');
+                if ($this->getWhmcsConfigOption(ConfigurableOption::DISK_SIZE))
+                {
+                    $disk = $this->getWhmcsConfigOption(ConfigurableOption::DISK_SIZE);
+                    Utility::unitFormat($disk, $this->configuration()->getDiskUnit(), 'bytes');
+                }
+                //RAM
+                $ram = $this->configuration()->getMemory();
+                Utility::unitFormat($ram, "mb", 'bytes');
+                if ($this->getWhmcsConfigOption(ConfigurableOption::MEMORY))
+                {
+                    $ram = $this->getWhmcsConfigOption(ConfigurableOption::MEMORY);
+                    Utility::unitFormat($ram, $this->configuration()->getMemoryUnit(), 'bytes');
+                }
+                if ($this->configuration()->isQemu())
+                {
+                    $socket = $this->getWhmcsConfigOption(ConfigurableOption::SOCKETS,$this->configuration()->getSockets() );
+                    $cores  = $this->getWhmcsConfigOption(ConfigurableOption::CORES_PER_SOCKET, $this->configuration()->getCores()) ;
+                    $cpu    = $socket * $cores;
+                }
+                else if ($this->configuration()->isLxc())
+                {
+                    $cpu = $this->getWhmcsConfigOption(ConfigurableOption::CORES, $this->configuration()->getCores()) ;
+                }
+                $loadBalancer->setExcludeVmid($this->vm()->getVmid());
+                //Upgrade on current node
+                if ($this->configuration()->getLoadBalancerOnUpgrade() == "block")
+                {
+                    $loadBalancerNodes = $loadBalancer->findByNode($this->vm()->getNode());
+                    $loadBalancerNodes = $loadBalancerNodes->findByRam($ram)
+                        ->findByCpu($cpu)
+                        ->findByDisk($disk);
+                    if ($loadBalancerNodes->isEmpty())
+                    {
+                        throw new \Exception("Load Balancer: Cannot find free resources on node: " . $this->vm()->getNode());
+                    }
+                }
+                else
+                {
+                    if ($this->configuration()->getLoadBalancerOnUpgrade() == "migrate")
+                    { //Allow to upgrade process, after previous migration vm to the server with free space.
+                        $loadBalancerNodes = $loadBalancer->findByNode($this->vm()->getNode());
+                        $loadBalancerNodes = $loadBalancerNodes->findByRam($ram)
+                            ->findByCpu($cpu)
+                            ->findByDisk($disk);
+                        if ($loadBalancerNodes->isEmpty())
+                        {
+                            $loadBalancerNodes = $loadBalancer->findByVmCreate();
+                            $nodesForUser      = $loadBalancer->findNotUser($this->getWhmcsParamByKey('userid'));
+                            if (!$nodesForUser->isEmpty())
+                            {
+                                $loadBalancerNodes = $nodesForUser;
+                            }
+                            $targetNode = $loadBalancerNodes->findByRam($ram)
+                                ->findByCpu($cpu)
+                                ->findByDisk($disk)
+                                ->findByVms(1)
+                                ->nodeLowLoad();
+                            if ($this->configuration()->isLoadBalancerShutdownOnUpgrade())
+                            {
+                                $job = queue(LoadBalancer\ShutdownVmJob::class, ['hostingId' => $this->getWhmcsParamByKey('serviceid'), "targetNode" => $targetNode], null, "hosting", $this->getWhmcsParamByKey("serviceid"));
+                            }
+                            $job = queue(LoadBalancer\MigrateVmJob::class, ['hostingId' => $this->getWhmcsParamByKey('serviceid'), "targetNode" => $targetNode], $job->id, "hosting", $this->getWhmcsParamByKey("serviceid"));
+                            queue(LoadBalancer\UpgradeVmJob::class, ['hostingId' => $this->getWhmcsParamByKey('serviceid'), "targetNode" => $targetNode], $job->id, "hosting", $this->getWhmcsParamByKey("serviceid"));
+                            return true;
+                        }
+                    }
+                }
+            }
+            if ($this->configuration()->isQemu())
+            {
+                $evnet = new QemuUpdateEvent($this->vm());
+                $evnet->setChangeVmPassword(false);
+                fire($evnet);
+            }
+            elseif ($this->configuration()->isLxc())
+            {
+                fire(new LxcUpdateEvent($this->vm()));
+            }
+            //hosting limit
+            $this->saveUsageLimit();
+            //reboot
+            if ($this->configuration()->isRebootVmAfterChangePackage() &&
+                $this->vm()->isRunning() &&
+                !Job::waiting()->ofJob(RebootVmJob::class)->ofHostingId($this->getWhmcsParamByKey("serviceid"))->count())
+            {
+                $parentId = queue(RebootVmJob::class, ['hostingId' => $this->getWhmcsParamByKey('serviceid')], null, "hosting", $this->getWhmcsParamByKey("serviceid"));
+            }
+            if($this->configuration()->isAgentConfigureNetwork()){
+                $parentId = queue(ConfigureNetworkJob::class, ['hostingId' => $this->getWhmcsParamByKey('serviceid')], $parentId, "hosting", $this->getWhmcsParamByKey("serviceid"));
+            }
+            //IP Filter
+            if ($this->configuration()->isIpsetIpFilter())
+            {
+                $this->ipSetIpFilterService->create();
+            }
+            return "success";
+        }
+        catch (\Exception $ex)
+        {
+            return $ex->getMessage();
+        }
+    }
+
+    private function manuallyUpgrade()
+    {
+        $scriptFile = substr($_SERVER['SCRIPT_NAME'], strrpos($_SERVER['SCRIPT_NAME'], DIRECTORY_SEPARATOR) + 1);
+        if (!$this->configuration()->getUpgradeNotificationTemplateId() || $scriptFile == "clientsservices.php")
+        {
+            return;
+        }
+        if ($this->configuration()->isToDoList())
+        {
+            $title = sprintf('Manually Upgrade - Service ID: %s', $this->getWhmcsParamByKey('serviceid'));
+            if (!ToDoList::ofTitle($title)->pending()->count())
+            {
+                $entity = new ToDoList();
+                $entity->fill(
+                    [
+                        'date'        => date("Y-m-d H:i:s"),
+                        "duedate"     => date("Y-m-d H:i:s"),
+                        'title'       => $title,
+                        "status"      => "Pending",
+                        "description" => "An upgrade order has received its payment, automatic upgrades  has been disabled and requires manually processing.",
+                        "admin"       => 0,
+                    ]
+                );
+                $entity->save();
+            }
+        }
+        //Send Admin notification
+        $this->emailService->template($this->configuration()->getUpgradeNotificationTemplateId());
+        global $customadminpath;
+        $adminDir      = $customadminpath ? $customadminpath : "admin";
+        $adminAreaLink = $GLOBALS['CONFIG']['SystemURL'] . "/{$adminDir}";
+        $hosting       = $GLOBALS['CONFIG']['SystemURL'] . "/{$adminDir}/clientsservices.php?id=" . $this->getWhmcsParamByKey('serviceid');
+        $emailVars     = [
+            "client_id"        => $this->getWhmcsParamByKey('clientsdetails')['id'],
+            "service_id"       => $this->getWhmcsParamByKey('serviceid'),
+            "service_product"  => "<a href='{$hosting}/'>{$hosting}</a>",
+            "service_domain"   => $this->getWhmcsParamByKey('domain'),
+            "whmcs_admin_link" => "<a href='{$adminAreaLink}/'>{$adminAreaLink}</a>",
+        ];
+        $this->emailService->vars($emailVars)->sendToAdmin();
+        throw new \Exception("Automaticall upgrade  has been disabled by admin");
+    }
+
+    private function createReinstallJob()
+    {
+        if (!$this->getWhmcsConfigOption(ConfigurableOption::OS_TEMPLATE))
+        {
+            return;
+        }
+        if (!Upgrade::ofHostingId($this->getWhmcsParamByKey('serviceid'))->pending()->today()->count())
+        {
+            return;
+        }
+
+        $pg       = "tblproductconfiggroups";
+        $pl       = "tblproductconfiglinks";
+        $po       = "tblproductconfigoptions";
+        $optionId = DB::table($po)
+            ->select("{$po}.id")
+            ->leftJoin($pg, "{$pg}.id", "=", "{$po}.gid")
+            ->leftJoin($pl, "{$pl}.gid", "=", "{$pg}.id")
+            ->where("{$pl}.pid", $this->getWhmcsParamByKey("pid"))
+            ->where("{$po}.optionname", "like", "VM Template|%")
+            ->value("id");
+        if (!$optionId)
+        {
+            return;
+        }
+        if (!Upgrade::ofHostingId($this->getWhmcsParamByKey('serviceid'))->pending()->today()->ofOptionId($optionId)->count())
+        {
+            return;
+        }
+        if ($this->configuration()->isQemu())
+        {
+            if ($this->getWhmcsConfigOption(ConfigurableOption::OS_TEMPLATE)=== "0")
+            {
+                return;
+            }
+        }
+        $arguments = [
+            'hostingId'  => $this->getWhmcsParamByKey('serviceid'),
+            "osTemplate" => $this->getWhmcsConfigOption(ConfigurableOption::OS_TEMPLATE),
+            "password"   => encrypt($this->getWhmcsParamByKey("password"))
+        ];
+        if ($this->configuration()->isBackupVmBeforeReinstall())
+        {
+            $job = queue(BackupVmJob::class, $arguments, null, "hosting", $this->getWhmcsParamByKey("serviceid"));
+        }
+        $job = queue(DeleteVmJob::class, $arguments, $job->id, "hosting", $this->getWhmcsParamByKey("serviceid"));
+        $job = queue(CreateVmJob::class, $arguments, $job->id, "hosting", $this->getWhmcsParamByKey("serviceid"));
+    }
+
+    protected function diskSizeValidation(){
+        $diskSize = $this->configuration()->getDiskSize();
+        if ($this->getWhmcsConfigOption(ConfigurableOption::DISK_SIZE))
+        {
+            $diskSize = $this->getWhmcsConfigOption(ConfigurableOption::DISK_SIZE);
+            Utility::unitFormat($diskSize, $this->configuration()->getDiskUnit(), 'bytes');
+        }else{
+            Utility::unitFormat($diskSize, "gb", 'bytes');
+        }
+        $masterHddSize = $this->vm()->getMasterHddSize();
+        Utility::unitFormat($masterHddSize, "gb", 'bytes');
+        if ($diskSize < $masterHddSize)
+        {
+            throw new \Exception(sprintf('Downgrading disk size  is restricted. Request Disk size: %s, VM disk size: %s',
+                Format::convertBytes($diskSize), Format::convertBytes($masterHddSize)));
+        }
+    }
+}

+ 86 - 0
app/Http/Actions/ChangePassword.php

@@ -0,0 +1,86 @@
+<?php
+/**********************************************************************
+ * ProxmoxVPS developed. (26.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\ProxmoxVps\App\Http\Actions;
+
+use MGProvision\Proxmox\v2\ProxmoxApiException;
+use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\Agent\ChangePasswordJob;
+use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\RebootVmJob;
+use ModulesGarden\ProxmoxAddon\App\Models\Job;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\AgentService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\Enum\CustomField;
+use ModulesGarden\Servers\ProxmoxVps\App\Helpers\AppParams;
+use ModulesGarden\Servers\ProxmoxVps\App\Helpers\ProxmoxAddonValidator;
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\AddonController;
+use function ModulesGarden\ProxmoxAddon\Core\Helper\queue;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Traits\WhmcsParams;
+
+class ChangePassword extends AddonController
+{
+    use WhmcsParams;
+    use ProductService;
+    use ApiService;
+
+    public function execute($params = null)
+    {
+        if(!ProxmoxAddonValidator::isInstalled()){
+            return ProxmoxAddonValidator::failAsString();
+        }
+        (new AppParams())->initFromWhmcsParams();
+        try
+        {
+            //cloud init
+            if($this->configuration()->isCloudInit()){
+                //KVM only
+                $container               = [];
+                if($this->getWhmcsCustomField(CustomField::CI_USER)){
+                    $container['ciuser']     = $this->getWhmcsCustomField(CustomField::CI_USER);
+                }else{
+                    $container['ciuser']     = $this->configuration()->getCiuser() ? $this->configuration()->getCiuser() : $params['username'];
+                }
+                $container['cipassword'] = $params['password'];
+                $this->vm()->updateConfig($container);
+                //restart
+                if (!Job::waiting()->ofJob(RebootVmJob::class)->ofHostingId($this->getWhmcsParamByKey("serviceid"))->count())
+                {
+                    queue(RebootVmJob::class, [], null, "hosting", $this->getWhmcsParamByKey("serviceid"));
+                }
+            }
+            if ($this->configuration()->isAgent() && $this->configuration()->isAgentServicePassword()){
+                try{
+                    if(!$this->vm()->isRunning()) {
+                        throw new ProxmoxApiException("VM not running");
+                    }
+                    $agent = new AgentService();
+                    $this->vm()->agent()->ping();
+                    $agent->passwordUpdate();
+                }catch (ProxmoxApiException $ex){
+                    queue(ChangePasswordJob::class, [], null, "hosting", $this->getWhmcsParamByKey("serviceid"));
+                }
+            }
+            return "success";
+        }
+        catch (\Exception $ex)
+        {
+            return $ex->getMessage();
+        }
+    }
+}

+ 71 - 0
app/Http/Actions/ChangeUserRole.php

@@ -0,0 +1,71 @@
+<?php
+/**********************************************************************
+ * ProxmoxVPS developed. (26.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\ProxmoxVps\App\Http\Actions;
+
+use ModulesGarden\ProxmoxAddon\App\Models\ModuleSettings;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\UserService;
+use ModulesGarden\Servers\ProxmoxVps\App\Helpers\AppParams;
+use ModulesGarden\Servers\ProxmoxVps\App\Helpers\ProxmoxAddonValidator;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Validators\Validator;
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\AddonController;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Traits\WhmcsParams;
+
+class ChangeUserRole extends AddonController
+{
+
+    use WhmcsParams;
+    use ProductService;
+    use UserService;
+    use ApiService;
+
+    public function execute($params = null)
+    {
+        if(!ProxmoxAddonValidator::isInstalled()){
+            return ProxmoxAddonValidator::failAsString();
+        }
+        (new AppParams())->initFromWhmcsParams();
+        try
+        {
+            //Create User
+            if (!$this->isUser())
+            {
+                $this->userCreate();
+            }
+            $this->userUpdate();
+            return "success";
+        }
+        catch (\Exception $ex)
+        {
+            if (ModuleSettings::isDebug())
+            {
+                logModuleCall(
+                    'ProxmoxVps',
+                    __CLASS__,
+                    [],
+                    null,
+                    $ex->getMessage() . " " . $ex->getTraceAsString()
+                );
+            }
+            return $ex->getMessage();
+        }
+    }
+}

+ 53 - 0
app/Http/Actions/ConfigOptions.php

@@ -0,0 +1,53 @@
+<?php
+/**********************************************************************
+ * ProxmoxVPS developed. (26.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\ProxmoxVps\App\Http\Actions;
+
+use ModulesGarden\ProxmoxAddon\App\Configuration\Addon\Update\AddonUpgradeService;
+use ModulesGarden\Servers\ProxmoxVps\App\Helpers\ProxmoxAddonValidator;
+use ModulesGarden\Servers\ProxmoxVps\App\Http\Admin\Product;
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\AddonController;
+
+class ConfigOptions extends AddonController
+{
+
+    /**
+     * @var AddonUpgradeService
+     */
+    private $addonUpgradeService;
+
+    public function execute($params = null)
+    {
+
+        if (($this->getRequestValue('action') === 'module-settings' || ($this->getRequestValue('loadData') && $this->getRequestValue('ajax') == '1')))
+        {
+            ProxmoxAddonValidator::isInstalledOrFail();
+            $this->addonUpgradeService = new AddonUpgradeService();
+            $this->addonUpgradeService->run();
+            return [Product::class, 'index'];
+        }
+        else
+        {
+            if ($this->getRequestValue('action') !== 'save')
+            {
+                return [];
+            }
+        }
+    }
+}

+ 555 - 0
app/Http/Actions/CreateAccount.php

@@ -0,0 +1,555 @@
+<?php
+/**********************************************************************
+ * ProxmoxVPS developed. (26.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\ProxmoxVps\App\Http\Actions;
+
+use MGProvision\Proxmox\v2\models\Kvm;
+use MGProvision\Proxmox\v2\models\Node;
+use MGProvision\Proxmox\v2\repository\ClusterResourcesRepository;
+use ModulesGarden\ProxmoxAddon as addon;
+use ModulesGarden\ProxmoxAddon\App\Configuration\Addon\Update\AddonUpgradeService;
+use ModulesGarden\ProxmoxAddon\App\Models\VmIpAddress;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Utility;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\HostingService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\NetworkService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\UserService;
+use ModulesGarden\ProxmoxAddon\Core\Queue\Models\Job;
+use ModulesGarden\Servers\ProxmoxVps\App\Enum\CustomField;
+use ModulesGarden\Servers\ProxmoxVps\App\Helpers\AppParams;
+use ModulesGarden\Servers\ProxmoxVps\App\Helpers\ProxmoxAddonValidator;
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\AddonController;
+use ModulesGarden\Servers\ProxmoxVps\Core\Models\Whmcs\Server;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Traits\WhmcsParams;
+use ModulesGarden\Servers\ProxmoxVps\App\Enum\ConfigurableOption;
+
+class CreateAccount extends AddonController
+{
+    use WhmcsParams;
+    use ProductService;
+    use ApiService;
+    use UserService;
+    use HostingService;
+    use addon\App\Traits\Vps\SnippetTrait;
+
+    private $errors = [];
+
+    /**
+     * @var AddonUpgradeService
+     */
+    private $addonUpgradeService;
+
+    /**
+     * @var Kvm|null
+     */
+    private $templateVm;
+
+    public function execute($params = null)
+    {
+        if(!ProxmoxAddonValidator::isInstalled()){
+            return ProxmoxAddonValidator::failAsString();
+        }
+        (new AppParams())->initFromWhmcsParams();
+        $this->addonUpgradeService = new AddonUpgradeService();
+        $this->addonUpgradeService->run();
+        try
+        {
+            //init nameservers
+            $this->initNameServers();
+            //Validate
+            $this->validate();
+            //Clone validate
+            if ($this->configuration()->isQemu())
+            {
+                $this->cloneValidate();
+            }
+            //Check free resources
+            $this->checkResources();
+            //update hostname
+            if($params['customfields']['proxmoxHostname']){
+                $this->hosting()->domain = $params['customfields']['proxmoxHostname'];
+                $this->hosting()->save();
+            }
+            //throw errors
+            if ($this->errors)
+            {
+                throw new \Exception(implode(", ", $this->errors));
+            }
+            //Create User
+            if (!$this->isUser())
+            {
+                $this->userCreate();
+            }elseif($this->isUser() ){
+                $this->createUserIfNotExist($this->getUser());
+            }
+            //Assing ip
+            if (!Utility::isIpManagerProxmoxVPSIntegration())
+            {
+                if ($this->isCustomIpRequest() && $this->hasCustomIp())
+                {
+                    $this->addCustomIp();
+                }
+                else
+                {
+                    $networkService = new NetworkService();
+                    list($requestIPv4, $requestIPv6) = $networkService->getIpAddressesRequest();
+                    $node = $this->getNode()->getNode();
+                    $networkService->hasIp($requestIPv4, $requestIPv6, $node)
+                        ->addIp($requestIPv4, $requestIPv6, $node);
+                    $this->customFieldUpdate(CustomField::NODE, $node);
+
+                }
+            }
+            //automaticaly configure administartor username for window
+            if($this->templateVm instanceof Kvm &&
+                $this->configuration()->isAgent() &&
+                $this->configuration()->isAgentServicePassword() &&
+                !$this->configuration()->isAgentTemplateUser() &&
+                preg_match('/w/', $this->templateVm->config()['ostype'])){
+                $ciuser =  $this->templateVm->config()['ciuser'];
+                $this->hosting()->update(['username' => $ciuser ?: 'Administrator' ]);
+            }
+            elseif($this->configuration()->isQemu() && $this->configuration()->getCiuser()){
+                $this->hosting()->update(['username' =>$this->configuration()->getCiuser() ]);
+            }
+                        //hosting limit
+            $this->saveUsageLimit();
+            //Create task
+            if ($this->configuration()->isLxc())
+            {
+                $taskName = addon\App\Jobs\Vps\CreateLxcJob::class;
+            }
+            else
+            {
+                if ($this->configuration()->isQemu())
+                {
+                    $taskName   = addon\App\Jobs\Vps\CreateQemuJob::class;
+                    $osTemplate = $this->getWhmcsConfigOption(ConfigurableOption::OS_TEMPLATE, $this->configuration()->getOsTemplate());
+                    if (!empty($osTemplate) && $osTemplate != "0")
+                    {
+                        $taskName = addon\App\Jobs\Vps\CloneQemuJob::class;
+                    }
+                }
+            }
+            $arguments = [
+                'hostingId' => $this->getWhmcsParamByKey('serviceid')
+            ];
+            if($this->configuration()->isQemu() && $this->hasSnippet()){
+                $parent = addon\Core\Helper\queue(addon\App\Jobs\Vps\CreateSnippet::class, $arguments, null, "hosting", $this->getWhmcsParamByKey("serviceid"));
+            }
+            addon\Core\Helper\queue($taskName, $arguments, $parent->id, "hosting", $this->getWhmcsParamByKey("serviceid"));
+            return "success";
+        }
+        catch (\Exception $ex)
+        {
+            if (addon\App\Models\ModuleSettings::isDebug())
+            {
+                logModuleCall(
+                    'ProxmoxVps',
+                    __CLASS__,
+                    [],
+                    null,
+                    $ex->getMessage() . " " . $ex->getTraceAsString()
+                );
+            }
+            return $ex->getMessage();
+        }
+    }
+
+    private function validate()
+    {
+        //vmid
+        if ($this->getWhmcsCustomField(CustomField::VMID))
+        {
+            $this->errors[] = "Custom Field \"VMID\" is not empty";
+        }
+        //node
+        if ($this->getWhmcsCustomField(CustomField::NODE))
+        {
+            $this->errors[] = "Custom Field \"Node\" is not empty";
+        }
+        if (!in_array($this->configuration()->getVirtualization(), ["qemu", "lxc"]))
+        {
+            $this->errors[] = 'Unknown virtualization type: ' . $this->configuration()->getVirtualization();
+        }
+        //Network bridge
+        if (!$this->configuration()->getBridge())
+        {
+            $this->errors[] = "''Bridge' - is empty";
+        }
+        //lxc
+        if ($this->configuration()->isLxc())
+        {
+            //OS Template
+            if (!$this->getWhmcsConfigOption(ConfigurableOption::OS_TEMPLATE, $this->configuration()->getOsTemplate()) )
+            {
+                $this->errors[] = "'OS Template' - is empty";
+            }
+            //Storage
+            if (!$this->configuration()->getStorage())
+            {
+                $this->errors[] = "'Default Storage' - is empty";
+            }
+            $taskName = addon\App\Jobs\Vps\CreateLxcJob::class . '@handle';
+        }
+        else
+        {
+            if ($this->configuration()->isQemu())
+            {
+                //searchdomain
+                if ($this->configuration()->getSearchdomain() && !preg_match('/^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$/', $this->configuration()->getSearchdomain()))
+                {
+                    $this->errors[] = sprintf('DNS Domain \'%s\' is invalid', $this->configuration()->getSearchdomain());
+                }
+                //SSH Key
+                if ($this->getWhmcsParamByKey('customfields')['sshkeys'] && !preg_match('/ssh\-/', $this->getWhmcsParamByKey('customfields')['sshkeys']))
+                {
+                    $this->errors[] = ' SSH Public Key is invalid';
+                }
+                $taskName   = addon\App\Jobs\Vps\CreateQemuJob::class . '@handle';
+                $osTemplate = $this->getWhmcsConfigOption(ConfigurableOption::OS_TEMPLATE, $this->configuration()->getOsTemplate() );
+                //clone
+                if (!empty($osTemplate) && $osTemplate != "0")
+                {
+                    $taskName = addon\App\Jobs\Vps\CloneQemuJob::class . '@handle';
+                }
+            }
+        }
+        $query = Job::where("job", $taskName)->whereIn("status", ['waiting', "running", ""])->where("rel_id", $this->getWhmcsParamByKey("serviceid"))->where("rel_type", "hosting")
+                    ->orWhere("job", $taskName)->where("status", 'error')->where("rel_id", $this->getWhmcsParamByKey("serviceid"))->where("rel_type", "hosting")->where("retry_count","<",100);
+        if ( $query->count() )
+        {
+            $this->errors[] = "Job 'create' already exist";
+        }
+        //Name servers
+        if ($this->configuration()->isLxc() || $this->configuration()->isCloudInitServiceNameservers())
+        {
+            $ns = [];
+            for ($i = 1; $i <= 2; $i++)
+            {
+                $n = trim($this->hosting()->{"ns{$i}"});
+                if (!empty($n) && !filter_var($n, FILTER_VALIDATE_IP))
+                {
+                    $n = gethostbyname($n);
+                }
+                if (!empty($n) && !filter_var($n, FILTER_VALIDATE_IP))
+                {
+                    $ns[] = "'{$n}'";
+                }
+            }
+            if (!empty($ns))
+            {
+                $this->errors[] = sprintf(" Name Server value: %s does not look like a valid IP Address", implode(", ", $ns));
+            }
+        }
+        //Disk size
+        $diskSize = $this->getWhmcsConfigOption(ConfigurableOption::DISK_SIZE);
+        if ($diskSize && $this->configuration()->getDiskUnit() == "mb" && $diskSize < 1024)
+        {
+            $this->errors[] = sprintf("Disk size of %sMB cannot be  created", $diskSize);
+        }
+
+        $rate = $this->getWhmcsConfigOption(addon\App\Enum\Vps\ConfigurableOption::NETWORK_RATE) ? $this->getWhmcsConfigOption(addon\App\Enum\Vps\ConfigurableOption::NETWORK_RATE) :$this->configuration()->getRate();
+        if ($rate && !is_numeric($rate))
+        {
+            $this->errors[] = sprintf("Network Rate - invalid format: %s ", $rate) ;
+        }
+
+    }
+
+    private function initNameServers()
+    {
+        $this->setHostingId($this->getWhmcsParamByKey("serviceid"));
+        if ($this->configuration()->isServerNameservers())
+        {
+            $server               = Server::select('id', 'nameserver1ip', 'nameserver2ip')->findOrFail($this->getWhmcsParamByKey('serverid'));
+            $this->hosting()->ns1 = trim($server->nameserver1ip);
+            $this->hosting()->ns2 = trim($server->nameserver2ip);
+            $this->hosting()->save();
+        }
+        else
+        {
+            if ($this->configuration()->isLxc() || $this->configuration()->isCloudInitServiceNameservers())
+            {
+                $domain =  $this->getWhmcsCustomField(CustomField::HOSTNAME, $this->getWhmcsParamByKey('domain'));
+                $update = [];
+                for ($i = 1; $i <= 2; $i++)
+                {
+                    $n = trim($this->hosting()->{"ns{$i}"});
+                    if (!empty($n) && !filter_var($n, FILTER_VALIDATE_IP))
+                    {
+                        $host = preg_match('/\./', $n) ? $n : "{$n}.{$domain}";
+                        $n    = gethostbyname($host);
+                        if (!$n || !filter_var($n, FILTER_VALIDATE_IP))
+                        {
+                            throw new \Exception(sprintf("Nameserver '%s' cannot be resolved", $host));
+                        }
+                    }
+                    if (!empty($n) && filter_var($n, FILTER_VALIDATE_IP))
+                    {
+                        $update['ns' . $i]           = $n;
+                        $this->hosting()->{"ns{$i}"} = $n;
+                    }
+                }
+                if ($update)
+                {
+                    $this->hosting()->update($update);
+                }
+            }
+        }
+    }
+
+    private function isCustomIpRequest()
+    {
+        //if there is custom ip on dedicated ip or assinged ips
+        $model = $this->getWhmcsParamByKey('model');
+        if (!$model)
+        {
+            $model = \WHMCS\Service\Service::where("id", $this->getWhmcsParamByKey('serviceid'))->first();
+        }
+        if (!$model->dedicatedip && !$model->assignedips)
+        {
+            return false;
+        }
+        $ips = $this->getCustomIp();
+        if (!$ips)
+        {
+            return false;
+        }
+        foreach ($ips as $k => $ip)
+        {
+            if (!filter_var((string)$ip, FILTER_VALIDATE_IP))
+            {
+                throw new \Exception(sprintf("IP Address '%s' is not valid", $ip));
+            }
+        }
+        return true;
+    }
+
+    private function getCustomIp()
+    {
+        $ips   = [];
+        $model = $this->getWhmcsParamByKey('model');
+        if (!$model)
+        {
+            $model = \WHMCS\Service\Service::where("id", $this->getWhmcsParamByKey('serviceid'))->first();
+        }
+        if ($model->dedicatedip)
+        {
+            $ips[] = $model->dedicatedip;
+        }
+        if ($model->assignedips)
+        {
+            $ex = explode(PHP_EOL, $model->assignedips);
+            foreach ($ex as $ip)
+            {
+                if (!$ip)
+                {
+                    continue;
+                }
+                $ips[] = str_replace(["\r", "\n"], ["", ""], $ip);
+            }
+        }
+        return array_diff($ips, [""]);
+    }
+
+    private function hasCustomIp()
+    {
+        $nodeName       = $this->getNode()->getNode();
+        $ipAddresses    = $this->getCustomIp();
+        $virtualization = $this->configuration()->isQemu() ? "KVM" : "LXC";
+        $ipCollections  = addon\App\Models\IpAddress::where('hosting_id', '0')
+            ->where('private', '0')
+            ->whereIn('ip', $ipAddresses)
+            ->whereIn('sid', [$this->getWhmcsParamByKey('serverid'), '0'])
+            ->whereIn('visualization', [$virtualization, 'Auto'])
+            ->whereIn('node', [$nodeName, '0', ""]);
+        $count          = $ipCollections->count();
+        return $count == count($ipAddresses);
+    }
+
+    private function addCustomIp()
+    {
+        $nodeName       = $this->getNode()->getNode();
+        $ipAddresses    = $this->getCustomIp();
+        $virtualization = $this->configuration()->isQemu() ? "KVM" : "LXC";
+        addon\App\Models\IpAddress::where('hosting_id', '0')
+            ->where('private', '0')
+            ->whereIn('ip', $ipAddresses)
+            ->whereIn('sid', [$this->getWhmcsParamByKey('serverid'), '0'])
+            ->whereIn('visualization', [$virtualization, 'Auto'])
+            ->whereIn('node', [$nodeName, '0', ""])
+            ->update(["hosting_id" => $this->getWhmcsParamByKey('serviceid'), 'last_check' => Utility::timeStamp()]);
+        //get ips
+        $collection = addon\App\Models\IpAddress::where('hosting_id', $this->getWhmcsParamByKey('serviceid'))
+            ->whereNotIn('ip', function ($query)
+            {
+                $query->select('ip')->from((new VmIpAddress)->getTable());
+            });
+        foreach ($collection->get() as $ip)
+        {
+            /*@var $ip VmIpAddress */
+            $newIp                = new VmIpAddress();
+            $ipData               = $ip->toArray();
+            $ipData['hosting_id'] = $this->getWhmcsParamByKey('serviceid');
+            $ipData['server_id']  = $this->getWhmcsParamByKey('serverid');
+            $newIp->fill($ipData)->save();
+        }
+        return $this;
+    }
+
+    private function checkResources()
+    {
+        if (!$this->configuration()->isCheckResources())
+        {
+            return;
+        }
+        //get free space
+        $storage = $this->configuration()->isQemu() ? $this->configuration()->getDiskStorage() : $this->configuration()->getStorage();
+        $resurces      = $this->getNode()->getFreeSpace($storage);
+        //Memory
+        if ($this->getWhmcsConfigOption(ConfigurableOption::MEMORY))
+        {
+            $memoryBytes = $this->getWhmcsConfigOption(ConfigurableOption::MEMORY);
+            Utility::unitFormat($memoryBytes, $this->configuration()->getMemoryUnit(), 'bytes');
+        }
+        else
+        {
+            $memoryBytes = $this->configuration()->getMemory();
+            Utility::unitFormat($memoryBytes, "mb", 'bytes');
+        }
+        //Validation
+        if ($memoryBytes && $resurces['memory'] && $memoryBytes > $resurces['memory'])
+        {
+            $this->errors[] = sprintf("Unable to allocate %s of Memory. Memory available: %s",
+                addon\App\Libs\Format::convertBytes($memoryBytes), addon\App\Libs\Format::convertBytes($resurces['memory']));
+        }
+        //SWAP
+        if ($this->configuration()->isLxc())
+        {
+            if ($this->getWhmcsConfigOption(ConfigurableOption::SWAP))
+            {
+                $swapBytes = $this->getWhmcsConfigOption(ConfigurableOption::SWAP);
+                Utility::unitFormat($swapBytes, strtolower($this->configuration()->getSwapUnit()), 'bytes');
+            }
+            else
+            {
+                $swapBytes = $this->configuration()->getSwap();
+                Utility::unitFormat($swapBytes, "mb", 'bytes');
+            }
+            //Validation
+            if ($swapBytes && $resurces['swap'] && $swapBytes > $resurces['swap'])
+            {
+                $this->errors[] = sprintf("Unable to allocate %s of SWAP. SWAP available: %s",
+                    addon\App\Libs\Format::convertBytes($swapBytes), addon\App\Libs\Format::convertBytes($resurces['swap']));
+            }
+        }
+        //Disk
+        if ($this->getWhmcsConfigOption(ConfigurableOption::DISK_SIZE))
+        {
+            $diskBytes = $this->getWhmcsConfigOption(ConfigurableOption::DISK_SIZE);
+            Utility::unitFormat($diskBytes, $this->configuration()->getDiskUnit(), 'bytes');
+        }
+        else
+        {
+            $diskBytes = $this->configuration()->getDiskSize();
+            Utility::unitFormat($diskBytes, "gb", 'bytes');
+        }
+        //Validation
+        if ($diskBytes && $resurces['storage'] && $diskBytes > $resurces['storage'])
+        {
+            $this->errors[] = sprintf("Unable to allocate %s of Disk Space. Disk Space available: %s",
+                addon\App\Libs\Format::convertBytes($diskBytes), addon\App\Libs\Format::convertBytes($resurces['storage']));
+        }
+    }
+
+    private function cloneValidate()
+    {
+
+        $osTemplate    = $this->getWhmcsConfigOption(ConfigurableOption::OS_TEMPLATE, $this->configuration()->getOsTemplate() );
+        if (empty($osTemplate) && $osTemplate == "0")
+        {
+            return;
+        }
+        //Support for configurable options i.e vmname|OS Name
+        if (is_string($osTemplate) && !preg_match('/\//', $osTemplate))
+        {
+            $templateNode      = $this->getNode()->getNode();
+            $clusterRepository = new ClusterResourcesRepository();
+            $clusterRepository->setApi($this->api());
+            if(!$this->configuration()->isOsTemplatesInAllNodes()){
+                $clusterRepository->findByNodes([$templateNode]);
+            }
+            $clusterRepository->findKvmTemplate();
+            foreach ($clusterRepository->fetch() as $resurce)
+            {
+                if ($resurce->getName() == $osTemplate )
+                {
+                    $templateVmid = $resurce->getVmid();
+                    $templateNode = $resurce->getNode();
+                    break;
+                }
+            }
+            if (!$templateVmid)
+            {
+                $this->errors[] = sprintf("Unable to find KVM template: %s on node: %s", $osTemplate, $this->getNode()->getNode());
+                return;
+            }
+            //Support for configurable options like nodename/vmid|OS Name
+        }
+        else
+        {
+            if (preg_match('/\//', $osTemplate))
+            {
+                list($templateNode, $templateVmid) = explode("/", $osTemplate);
+            }
+        }
+        if (!in_array($templateNode, (array)$this->api()->get_node_list()))
+        {
+            $this->errors[] = sprintf("Unable to find node %s on cluster %s", $templateNode, $this->api()->getPveHostname());
+            return;
+        }
+        //template exist on node?
+        $node = new Node($templateNode);
+        $node->setApi($this->api());
+        if (!$node->hasKvm($templateVmid))
+        {
+            $this->errors[] = sprintf("KVM template VMID '%s' does not exist on  node '%s'", $templateVmid, $templateNode);
+            return;
+        }
+        //Disk size validation
+        $this->templateVm = new Kvm($templateNode, $templateVmid);
+        $this->templateVm->setApi($this->api());
+        //Disk
+        $diskSize = $this->configuration()->getDiskSize();
+        if ($this->getWhmcsConfigOption(ConfigurableOption::DISK_SIZE))
+        {
+            $diskSize = $this->getWhmcsConfigOption(ConfigurableOption::DISK_SIZE);
+            Utility::unitFormat($diskSize, $this->configuration()->getDiskUnit(), 'bytes');
+        }else{
+             Utility::unitFormat($diskSize, "gb", 'bytes');
+        }
+        if ($this->templateVm->getMasterHardDisk()->getBytes() > $diskSize)
+        {
+            $this->errors[] = sprintf('Downgrading disk size  is restricted. Request Disk size: %s, VM disk size: %s', addon\App\Libs\Format::convertBytes($diskSize), addon\App\Libs\Format::convertBytes($this->templateVm->getMasterHardDisk()->getBytes()));
+        }
+    }
+
+}

+ 37 - 0
app/Http/Actions/MetaData.php

@@ -0,0 +1,37 @@
+<?php
+/**********************************************************************
+ * ProxmoxVPS developed. (26.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\ProxmoxVps\App\Http\Actions;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\AddonController;
+
+class MetaData extends AddonController
+{
+    public function execute($params = null)
+    {
+        return [
+            'DisplayName'    => 'Proxmox VPS',
+            'RequiresServer' => true,
+            'DefaultNonSSLPort' => '8006', // Default Non-SSL Connection Port
+            'DefaultSSLPort' => '8006', // Default SSL Connection Port
+        ];
+
+    }
+
+}

+ 64 - 0
app/Http/Actions/ResetBandwidth.php

@@ -0,0 +1,64 @@
+<?php
+/**********************************************************************
+ * ProxmoxVPS developed. (26.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\ProxmoxVps\App\Http\Actions;
+
+use ModulesGarden\ProxmoxAddon\App\Models\ModuleSettings;
+use ModulesGarden\ProxmoxAddon\App\Models\Whmcs\Hosting;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\Helpers\AppParams;
+use ModulesGarden\Servers\ProxmoxVps\App\Helpers\ProxmoxAddonValidator;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Validators\Validator;
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\AddonController;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Traits\WhmcsParams;
+
+class ResetBandwidth extends AddonController
+{
+
+    use WhmcsParams;
+    use ProductService;
+
+    public function execute($params = null)
+    {
+        if(!ProxmoxAddonValidator::isInstalled()){
+            return ProxmoxAddonValidator::failAsString();
+        }
+        (new AppParams())->initFromWhmcsParams();
+        try
+        {
+            Hosting::where("id", $this->getWhmcsParamByKey('serviceid'))
+                   ->update(["bwusage" => 0]);
+            return "success";
+        }
+        catch (\Exception $ex)
+        {
+            if (ModuleSettings::isDebug())
+            {
+                logModuleCall(
+                    'ProxmoxVps',
+                    __CLASS__,
+                    [],
+                    null,
+                    $ex->getMessage() . " " . $ex->getTraceAsString()
+                );
+            }
+            return $ex->getMessage();
+        }
+    }
+}

+ 92 - 0
app/Http/Actions/SuspendAccount.php

@@ -0,0 +1,92 @@
+<?php
+/**********************************************************************
+ * ProxmoxVPS developed. (26.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\ProxmoxVps\App\Http\Actions;
+
+use MGProvision\Proxmox\v2\models\Kvm;
+use MGProvision\Proxmox\v2\models\User;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\UserService;
+use ModulesGarden\Servers\ProxmoxVps\App\Helpers\AppParams;
+use ModulesGarden\Servers\ProxmoxVps\App\Helpers\ProxmoxAddonValidator;
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\AddonController;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Traits\WhmcsParams;
+
+class SuspendAccount extends AddonController
+{
+    use ProductService;
+    use ApiService;
+    use UserService;
+    use WhmcsParams;
+
+    public function execute($params = null)
+    {
+        if(!ProxmoxAddonValidator::isInstalled()){
+            return ProxmoxAddonValidator::failAsString();
+        }
+        (new AppParams())->initFromWhmcsParams();
+        try
+        {
+            //User suspend
+            $user        = $this->getUser();
+            $userService = new User("{$user->username}@{$user->realm}");
+            $userService->setApi($this->api());
+            $permissions = $userService->permissions();
+            $vmid        = $params['customfields']['vmid'];
+            foreach ($permissions as $p)
+            {
+                if ($p['path'] == "/vms/" . $vmid && $p['ugid'] == $userService->getUserid())
+                {
+                    $userService->updatePermission($vmid, $p['roleid'], 1);
+                }
+            }
+            if ($user->hosting_id > 0)
+            {
+                $userService->disable();
+            }
+            //VM suspend
+            $this->vm()->updateConfig(["onboot" => 0]);
+            if (!$this->vm()->isRunning())
+            {
+                return "success";
+            }
+            $suspensionAction = $this->configuration()->getSuspensionAction();
+            if ($suspensionAction && method_exists($this->vm(), $suspensionAction))
+            {
+                $this->vm()->{$suspensionAction}();
+                return "success";
+            }
+            if ($this->vm() instanceof Kvm)
+            {
+                $this->vm()->suspend();
+                return "success";
+            }
+            if ($this->vm()->isRunning())
+            {
+                $this->vm()->stop();
+            }
+            return "success";
+        }
+        catch (\Exception $ex)
+        {
+            return $ex->getMessage();
+        }
+    }
+}

+ 182 - 0
app/Http/Actions/TerminateAccount.php

@@ -0,0 +1,182 @@
+<?php
+/**********************************************************************
+ * ProxmoxVPS developed. (26.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\ProxmoxVps\App\Http\Actions;
+
+
+use MGProvision\Proxmox\v2\models\Lxc;
+use MGProvision\Proxmox\v2\repository\BackupScheduleRepository;
+use MGProvision\Proxmox\v2\repository\FileRepository;
+use MGProvision\Proxmox\v2\repository\FirewallRulesRepository;
+use ModulesGarden\ProxmoxAddon\App\Models\KeyPair;
+use ModulesGarden\ProxmoxAddon\App\Models\SnapshotJob;
+use ModulesGarden\ProxmoxAddon\App\Models\TaskHistory;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\HighAvailabilityClusterService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\HostingService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\NetworkService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\UserService;
+use ModulesGarden\ProxmoxAddon\App\Traits\Vps\SnippetTrait;
+use ModulesGarden\ProxmoxAddon\Core\Models\ModuleSettings\Model as ModuleSettings;
+use ModulesGarden\ProxmoxAddon\Core\Queue\Models\Job;
+use ModulesGarden\Servers\ProxmoxVps\App\Helpers\AppParams;
+use ModulesGarden\Servers\ProxmoxVps\App\Helpers\ProxmoxAddonValidator;
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\AddonController;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Traits\WhmcsParams;
+
+class TerminateAccount extends AddonController
+{
+    use WhmcsParams;
+    use ProductService;
+    use ApiService;
+    use UserService;
+    use HostingService;
+    use SnippetTrait;
+    /**
+     * @var HighAvailabilityClusterService
+     */
+    private $highAvailabilityClusterService;
+
+    public function __construct()
+    {
+        $this->highAvailabilityClusterService = new HighAvailabilityClusterService();
+    }
+
+    public function execute($params = null)
+    {
+        if(!ProxmoxAddonValidator::isInstalled()){
+            return ProxmoxAddonValidator::failAsString();
+        }
+        (new AppParams())->initFromWhmcsParams();
+        try
+        {
+            if (!$this->getWhmcsParamByKey('serviceid'))
+            {
+                throw new \InvalidArgumentException("The Service Id cannot be empty");
+            }
+            //Cron delete active jobs
+            Job::whereIn("status", ['waiting', "running", "", "error"])
+                ->where("rel_id", $this->getWhmcsParamByKey("serviceid"))
+                ->where("rel_type", "hosting")
+                ->update(["status" => 'cancelled']);
+            //snapshot jobs
+            SnapshotJob::ofHostingId($this->getWhmcsParamByKey("serviceid"))->delete();
+            //User delete
+            if ($this->isUser())
+            {
+                $this->deleteUser();
+            }
+            //Unassing IP
+            $networkService = new NetworkService();
+            $networkService->deleteIpAddresses();
+            //vmid validation
+            if (!$this->getWhmcsParamByKey('customfields')['vmid'])
+            {
+                throw new \InvalidArgumentException("Custom Field \"VMID\" cannot be empty");
+            }
+            //node
+            if (!$this->getWhmcsParamByKey('customfields')['node'])
+            {
+                throw new \InvalidArgumentException("Custom Field \"VMID\" cannot be empty");
+            }
+            //Delete HA
+            if ($this->highAvailabilityClusterService->exist())
+            {
+                $this->highAvailabilityClusterService->delete();
+            }
+            //Stop VM
+            if ($this->vm()->isRunning())
+            {
+                $this->vm()->stop();
+                sleep(4);
+            }
+            //VM Protection LXC
+            if ($this->vm() instanceof Lxc && $this->vm()->config()['protection'] == "1")
+            {
+                $this->vm()->protectionOff();
+                KeyPair::ofHostingId($this->getWhmcsParamByKey("serviceid"))->delete();
+
+            }
+            //Destroy firewall rules
+            if (version_compare($this->api()->getVersion(), "3.2", '>'))
+            {
+                $rules = new FirewallRulesRepository();
+                $rules->findByVm($this->vm())
+                    ->delete();
+            }
+            //Destroy Backups
+            if ($this->configuration()->isDeleteBackups())
+            {
+                $storage        = $this->configuration()->getBackupStorage() ? $this->configuration()->getBackupStorage() : 'local';
+                $fileRepository = new FileRepository();
+                $fileRepository->findBackup($this->vm())
+                    ->findByStorages([$storage])
+                    ->delete();
+            }
+            //Destroy Backup Jobs
+            $schedule = new BackupScheduleRepository();
+            $schedule->findByVm($this->vm());
+            $schedule->delete();
+            //Destroy VM
+            $upid = $this->vm()->delete();
+            //Create Task History
+            $type = str_replace(["qemu", "lxc"], ["VM", "CT"], $this->vm()->getVirtualization());
+            $task = new TaskHistory();
+            $task->fill([
+                'hosting_id' => $this->getWhmcsParamByKey("serviceid"),
+                'upid'       => $upid,
+                'name'       => sprintf("%s %s - %s", $type, $this->vm()->getVmid(), "Delete"),
+                'vmid'       => $this->vm()->getVmid(),
+                'node'       => $this->vm()->getNode(),
+                'status'     => 0
+            ])->save();
+            //snippets
+            if($this->hasSnippet() && $snippet = $this->getSnippetFile()){
+                $snippet->delete();
+            }
+            //Reset Custom Fields
+            $this->customFieldUpdate("vmid", "");
+            $this->customFieldUpdate("node", "");
+            //Reset VLAN Tag
+            if ($this->getWhmcsParamByKey('customfields')['VLAN Tag'])
+            {
+                $this->customFieldUpdate("VLAN Tag", "");
+            }
+            //Cache
+            $serviceId = $this->getWhmcsParamByKey('serviceid');
+            ModuleSettings::where('setting', "LIKE", "%{$serviceId}_cacheData%")->delete();
+            return "success";
+        }
+        catch (\Exception $ex)
+        {
+            if (\ModulesGarden\ProxmoxAddon\App\Models\ModuleSettings::isDebug())
+            {
+                logModuleCall(
+                    'ProxmoxVps',
+                    __CLASS__,
+                    [],
+                    null,
+                    $ex->getMessage() . " " . $ex->getTraceAsString()
+                );
+            }
+            return $ex->getMessage();
+        }
+    }
+}

+ 69 - 0
app/Http/Actions/TestConnection.php

@@ -0,0 +1,69 @@
+<?php
+/**********************************************************************
+ * ProxmoxVPS developed. (26.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\ProxmoxVps\App\Http\Actions;
+
+use MGProvision\Proxmox\v2\Api;
+use ModulesGarden\Servers\ProxmoxVps\App\Helpers\ProxmoxAddonValidator;
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\AddonController;
+
+class TestConnection extends AddonController
+{
+    public function execute($params = null)
+    {
+        try
+        {
+            if(isset($GLOBALS['disable_hook_loading']) && $GLOBALS['disable_hook_loading']){
+                throw new \Exception("Enabled hooks are required by the module. Please disable \$disable_hook_loading in cofiguration.php ");
+            }
+            ProxmoxAddonValidator::isInstalledOrFail();
+            if (!$params['serverip'] && !$params['serverhostname'])
+            {
+                throw new \Exception("Server Hostname or  IP Address  is empty.");
+            }
+            if ($params['serverip'])
+            {
+                if(is_numeric($params['serverport'])){
+                    $params['serverip'] .=":".$params['serverport'];
+                }
+                $api = new Api($params['serverip'], $params['serverusername'], $params['serveraccesshash'], $params['serverpassword']);
+                $api->debug();
+                $api->get("/nodes");
+            }
+            if ($params['serverhostname'])
+            {
+                if (preg_match("/[\/]/", $params['serverhostname']))
+                {
+                    throw new \Exception(sprintf("Server Hostname '%s' is invalid", $params['serverhostname']));
+                }
+                if(is_numeric($params['serverport'])){
+                    $params['serverhostname'] .=":".$params['serverport'];
+                }
+                $api = new Api($params['serverhostname'], $params['serverusername'], $params['serveraccesshash'], $params['serverpassword']);
+                $api->debug();
+                $api->get("/nodes");
+            }
+            return ['success' => true];
+        }
+        catch (\Exception $e)
+        {
+            return ['error' => $e->getMessage()];
+        }
+    }
+}

+ 94 - 0
app/Http/Actions/UnsuspendAccount.php

@@ -0,0 +1,94 @@
+<?php
+/**********************************************************************
+ * ProxmoxVPS developed. (26.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\ProxmoxVps\App\Http\Actions;
+
+use MGProvision\Proxmox\v2\models\Kvm;
+use MGProvision\Proxmox\v2\models\User;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\UserService;
+use ModulesGarden\Servers\ProxmoxVps\App\Helpers\AppParams;
+use ModulesGarden\Servers\ProxmoxVps\App\Helpers\ProxmoxAddonValidator;
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\AddonController;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Traits\WhmcsParams;
+
+class UnsuspendAccount extends AddonController
+{
+    use ApiService;
+    use UserService;
+    use ProductService;
+    use WhmcsParams;
+
+    public function execute($params = null)
+    {
+        if(!ProxmoxAddonValidator::isInstalled()){
+            return ProxmoxAddonValidator::failAsString();
+        }
+        (new AppParams())->initFromWhmcsParams();
+        try
+        {
+            //User Unsuspend
+            $user        = $this->getUser();
+            $userService = new User("{$user->username}@{$user->realm}");
+            $userService->setApi($this->api());
+            if ($userService->configuration()['enable'] == "0")
+            {
+                $userService->enable();
+            }
+            //VM Permission
+            $permissions = $userService->permissions();
+            $vmid        = $params['customfields']['vmid'];
+            foreach ($permissions as $p)
+            {
+                if ($p['path'] == "/vms/" . $vmid && $p['ugid'] == $userService->getUserid())
+                {
+                    $userService->updatePermission($vmid, $p['roleid'], 1);
+                }
+            }
+            $role = $this->configuration()->getUserRole() ? $this->configuration()->getUserRole() : 'PVEVMUser';
+            $userService->updatePermission($vmid, $role);
+            if ($this->configuration()->isOnboot())
+            {
+                $this->vm()->updateConfig(["onboot" => 1]);
+            }
+            $status = $this->vm()->status();
+            if ($this->vm() instanceof Kvm && $status['qmpstatus'] == "paused")
+            {
+                $this->vm()->resume();
+            }
+            else
+            {
+                if ($status['status'] == "running")
+                {
+                    return "success";
+                }
+                else
+                {
+                    $this->vm()->start();
+                }
+            }
+            return "success";
+        }
+        catch (\Exception $ex)
+        {
+            return $ex->getMessage();
+        }
+    }
+}

+ 138 - 0
app/Http/Admin/Home.php

@@ -0,0 +1,138 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\Http\Admin;
+
+use MGProvision\Proxmox\v2\models\Kvm;
+use ModulesGarden\ProxmoxAddon\App\Models\ModuleSettings;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\IpSet\Pages\IpSetDataTable;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\QemuGuestAgent\Pages\NetworkInterfacesDataTable;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\User\Pages\UserDataTable;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Graph\Pages\CpuGraph;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Graph\Pages\DiskGraph;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Graph\Pages\MemoryGraph;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Graph\Pages\NetworkGraph;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Home\Pages\ServiceActions;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\IpAddress\Pages\IpAddressDataTable;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Reinstall\Pages\ReinstallTab;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Reinstall\Pages\TemplateDataTable;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\ServiceInformation\Pages\ServiceInformation;
+use ModulesGarden\Servers\ProxmoxVps\Core\Helper;
+use ModulesGarden\Servers\ProxmoxVps\Core\Http\AbstractController;
+use ModulesGarden\Servers\ProxmoxVps\Core\Traits\OutputBuffer;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Traits\WhmcsParams;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\UserService;
+use Symfony\Component\HttpFoundation\RedirectResponse;
+use MGProvision\Proxmox\v2\Api;
+/**
+ * Example admin home page controler
+ * @author Sławomir Miśkowicz <slawomir@modulesgarden.com>
+ */
+class Home extends AbstractController
+{
+    use WhmcsParams;
+    use ProductService;
+    use ApiService;
+    use OutputBuffer;
+    use UserService;
+    public function index()
+    {
+        $view = Helper\viewIntegrationAddon();
+        $view->initCustomAssetFiles();
+        //serviceActions
+        $view->addElement(ServiceActions::class);
+        // serviceInformationDataTable
+        $view->addElement(ServiceInformation::class);
+        $view->addElement(IpAddressDataTable::class);
+        $view->addElement(IpSetDataTable::class);
+        if ($this->vm() instanceof Kvm) {
+
+            if ($this->vm()->config()['agent'] == 1) {
+                try {
+                    $this->vm()->agent()->getHostname();
+                    $view->addElement(NetworkInterfacesDataTable::class);
+                } catch (\Exception $ex) {
+
+                }
+            }
+            $view->addElement(ReinstallTab::class);
+        } else {
+            $view->addElement(TemplateDataTable::class);
+        }
+        $view->addElement(CpuGraph::class)
+            ->addElement(MemoryGraph::class)
+            ->addElement(NetworkGraph::class)
+            ->addElement(DiskGraph::class)
+            ->addElement(UserDataTable::class);
+        return $view;
+
+    }
+
+    public function novnc()
+    {
+        $this->cleanOutputBuffer();
+        $this->acl()->novnc();
+        $this->console(['novnc' => 1]);
+    }
+
+    public function xtermjs()
+    {
+        $this->cleanOutputBuffer();
+        $this->acl()->novnc();
+        $this->console(['xtermjs' => 1]);
+    }
+
+    private function console($request = [])
+    {
+        $serverHost = $this->getWhmcsParamByKey('serverip') ? $this->getWhmcsParamByKey('serverip') : $this->getWhmcsParamByKey('serverhostname');
+        //Host
+        $consoleHost = $this->getWhmcsParamByKey('serverhostname') ? $this->getWhmcsParamByKey('serverhostname') : $this->getWhmcsParamByKey('serverip');
+        if ($this->configuration()->getConsoleHost())
+        {
+            $consoleHost = $this->configuration()->getConsoleHost();
+        }
+        //Port
+        $consolePort = 8006;
+        if(is_numeric($this->getWhmcsParamByKey('serverport'))){
+            $consolePort = $this->getWhmcsParamByKey('serverport');
+        }
+        if (preg_match('/\:/', $consoleHost))
+        {
+            $ex          = explode(":", $consoleHost);
+            $consoleHost = $ex['0'];
+            $consolePort = $ex['1'];
+        }
+        try
+        {
+            //User
+            $vpsUser = $this->getUser();
+            if (empty($vpsUser->username))
+            {
+                throw new \Exception('User does not have permissions to access noVNC console');
+            }
+            //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());
+            //User Authorization
+            $ticket                         = $api->getLoginTicket();
+            $request['token']               = $ticket['ticket'];
+            $request['CSRFPreventionToken'] = $ticket['CSRFPreventionToken'];
+            $request['console']             = $this->vm()->getVirtualization();
+            /* @deprecated $vars['virtualization'] since version 2.6.0 */
+            $request['virtualization'] = $this->vm()->getVirtualization();
+            $request['node']           = $this->vm()->getNode();
+            $request['vmid']           = $this->vm()->getVmid();
+        }
+        catch (\Exception $ex)
+        {
+
+            $request['error'] = $ex->getMessage();
+        }
+        $response = new RedirectResponse("https://{$consoleHost}:{$consolePort}/novnc/mgnovnc.html?" . http_build_query($request));
+        $response->send();
+    }
+}

+ 20 - 0
app/Http/Admin/LoggerManager.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\Http\Admin;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\LoggerManager\Pages\LoggerPage;
+use ModulesGarden\Servers\ProxmoxVps\Core\Helper;
+use ModulesGarden\Servers\ProxmoxVps\Core\Http\AbstractController;
+
+/**
+ * Description of LoggerManager
+ *
+ * @author inbs
+ */
+class LoggerManager extends AbstractController
+{
+    public function index()
+    {
+        return Helper\view()->addElement(LoggerPage::class);
+    }
+}

+ 53 - 0
app/Http/Admin/Product.php

@@ -0,0 +1,53 @@
+<?php
+/**********************************************************************
+ * ProxmoxVPS developed. (26.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\ProxmoxVps\App\Http\Admin;
+
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Forms\MainForm;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Pages\CustomOptionsWidget;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Pages\MainContainer;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Traits\RequestObjectHandler;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Traits\WhmcsParams;
+use ModulesGarden\Servers\ProxmoxVps\Packages\WhmcsService\UI\ConfigurableOption\OptionsWidget;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\viewIntegrationAddon;
+
+
+class Product
+{
+    use RequestObjectHandler;
+    use WhmcsParams;
+    use ProductService;
+
+    public function index()
+    {
+
+        $productId = $this->getRequestValue("id");
+        $product   = \ModulesGarden\ProxmoxAddon\App\Models\Whmcs\Product::where("id", $productId)->firstOrFail();
+        sl("whmcsParams")->setParams($product->getParams());
+
+        header("HTTP/1.1 200 OK");
+        return viewIntegrationAddon()
+            ->addElement(MainForm::class)
+            ->addElement(new  OptionsWidget());
+
+    }
+
+}

+ 23 - 0
app/Http/Client/Backup.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\Http\Client;
+
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\Helpers\AppParams;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Backup\Pages\BackupDataTable;
+use ModulesGarden\Servers\ProxmoxVps\Core\Helper;
+use ModulesGarden\Servers\ProxmoxVps\Core\Http\AbstractClientController;
+
+class Backup extends AbstractClientController
+{
+    use ProductService;
+
+    public function index()
+    {
+        (new AppParams())->initFromWhmcsParams();
+        $this->acl()->backup();
+        Helper\sl("sidebar")->getSidebar("managementProxmoxVps")->getChild("backup")->setActive(true);
+        return Helper\view()->addElement(BackupDataTable::class);
+    }
+
+}

+ 23 - 0
app/Http/Client/BackupJob.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\Http\Client;
+
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\Helpers\AppParams;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\BackupJob\Pages\BackupJobDataTable;
+use ModulesGarden\Servers\ProxmoxVps\Core\Helper;
+use ModulesGarden\Servers\ProxmoxVps\Core\Http\AbstractClientController;
+
+class BackupJob extends AbstractClientController
+{
+    use ProductService;
+
+    public function index()
+    {
+        (new AppParams())->initFromWhmcsParams();
+        $this->acl()->backupJob();
+        Helper\sl("sidebar")->getSidebar("managementProxmoxVps")->getChild("backupJob")->setActive(true);
+        return Helper\view()->addElement(BackupJobDataTable::class);
+    }
+
+}

+ 45 - 0
app/Http/Client/BaseClientController.php

@@ -0,0 +1,45 @@
+<?php
+
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\Http\Client;
+
+
+use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\CloneQemuJob;
+use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\CreateLxcJob;
+use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\CreateQemuJob;
+use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\LoadBalancer\UpgradeVmJob;
+use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\MigrateVmJob;
+use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\Reinstall\CreateVmJob;
+use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\RestoreVm;
+use ModulesGarden\ProxmoxAddon\App\Models\Job;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Home\Pages\VpsBuild;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\view;
+
+
+trait BaseClientController
+{
+    public function isVpsCreated()
+    {
+        $jobs = [
+            CloneQemuJob::class,
+            CreateQemuJob::class,
+            CreateLxcJob::class,
+            MigrateVmJob::class,
+            RestoreVm::class,
+            \ModulesGarden\ProxmoxAddon\App\Jobs\Vps\Reinstall\RestoreVm::class,
+            UpgradeVmJob::class,
+            CreateVmJob::class
+        ];
+        if(Job::waiting()->ofHostingId($this->getWhmcsParamByKey("serviceid"))->ofJobs($jobs)->count() > 0){
+            return false;
+        }else if (!$this->getWhmcsCustomField("vmid")){
+            return false;
+        }
+        return true;
+    }
+
+    public function onVpsBuild()
+    {
+        return view()->addElement(VpsBuild::class);
+    }
+}

+ 134 - 0
app/Http/Client/Console.php

@@ -0,0 +1,134 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\Http\Client;
+
+use MGProvision\Proxmox\v2\Api;
+use ModulesGarden\ProxmoxAddon\App\Models\ModuleSettings;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Utility;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\UserService;
+use ModulesGarden\Servers\ProxmoxVps\App\Helpers\AppParams;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Home\Pages\DetailsContainer;
+use ModulesGarden\Servers\ProxmoxVps\Core\Http\AbstractClientController;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Traits\WhmcsParams;
+use Symfony\Component\HttpFoundation\RedirectResponse;
+use Symfony\Component\HttpFoundation\StreamedResponse;
+
+class Console extends AbstractClientController
+{
+
+    use WhmcsParams;
+    use UserService;
+    use ApiService;
+    use ProductService;
+
+
+    public function novnc()
+    {
+        (new AppParams())->initFromWhmcsParams();
+        $this->acl()->novnc();
+        $this->console(['novnc' => 1]);
+    }
+
+    public function xtermjs()
+    {
+        (new AppParams())->initFromWhmcsParams();
+        $this->acl()->xtermjs();
+        $this->console(['xtermjs' => 1]);
+    }
+
+    private function console($request = [])
+    {
+        $serverHost = $this->getWhmcsParamByKey('serverip') ? $this->getWhmcsParamByKey('serverip') : $this->getWhmcsParamByKey('serverhostname');
+        //Host
+        $consoleHost = $this->getWhmcsParamByKey('serverhostname') ? $this->getWhmcsParamByKey('serverhostname') : $this->getWhmcsParamByKey('serverip');
+        if ($this->configuration()->getConsoleHost())
+        {
+            $consoleHost = $this->configuration()->getConsoleHost();
+        }
+        //Port
+        $consolePort = 8006;
+        if(is_numeric($this->getWhmcsParamByKey('serverport'))){
+            $consolePort = $this->getWhmcsParamByKey('serverport');
+        }
+        if (preg_match('/\:/', $consoleHost))
+        {
+            $ex          = explode(":", $consoleHost);
+            $consoleHost = $ex['0'];
+            $consolePort = $ex['1'];
+        }
+        try
+        {
+            //User
+            $vpsUser = $this->getUser();
+            if (empty($vpsUser->username))
+            {
+                throw new \Exception('User does not have permissions to access noVNC console');
+            }
+            //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());
+            //User Authorization
+            $ticket                         = $api->getLoginTicket();
+            $request['token']               = $ticket['ticket'];
+            $request['CSRFPreventionToken'] = $ticket['CSRFPreventionToken'];
+            $request['console']             = $this->vm()->getVirtualization();
+            /* @deprecated $vars['virtualization'] since version 2.6.0 */
+            $request['virtualization'] = $this->vm()->getVirtualization();
+            $request['node']           = $this->vm()->getNode();
+            $request['vmid']           = $this->vm()->getVmid();
+        }
+        catch (\Exception $ex)
+        {
+
+            $request['error'] = $ex->getMessage();
+        }
+        $response = new RedirectResponse("https://{$consoleHost}:{$consolePort}/novnc/mgnovnc.html?" . http_build_query($request));
+        $response->send();
+    }
+
+    public function spice()
+    {
+        (new AppParams())->initFromWhmcsParams();
+        $this->acl()->spice();
+        $proxy       = $this->vm()->spiceproxy();
+        $consoleHost = $this->getWhmcsParamByKey('serverhostname') ? $this->getWhmcsParamByKey('serverhostname') : $this->getWhmcsParamByKey('serverip');
+        if ($this->configuration()->getConsoleHost())
+        {
+            $consoleHost = $this->configuration()->getConsoleHost();
+        }
+        if ($consoleHost)
+        {
+            $ex             = explode(":", $proxy['proxy']);
+            $port           = end($ex);
+            $proxy['proxy'] = "http://{$consoleHost}:{$port}";
+        }
+        $content = "[virt-viewer]\r\n";
+        foreach ($proxy as $k => $v)
+        {
+            $content .= "{$k}={$v}\r\n";
+        }
+        //Response
+        $response = new StreamedResponse();
+        $response->setStatusCode(200);
+        $response->headers->set('Cache-Control', 'public');
+        $response->headers->set('Content-Type', 'application/x-virt-viewer');
+        $response->headers->set('Content-Transfer-Encoding', 'Binary');
+        $response->setCallback(function () use ($content)
+        {
+            echo $content;
+            die();
+        });
+        $fileName = Utility::generatePassword(8, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
+        $fileName .= ".vv";
+        $response->headers->set(
+            'Content-Disposition', "attachment; filename=\"{$fileName}\""
+        );
+        $response->send();
+        exit();
+    }
+}

+ 34 - 0
app/Http/Client/Disk.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\Http\Client;
+
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\Helpers\AppParams;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Disk\Pages\DiskDataTable;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\MountPoint\Pages\MountPointDataTable;
+use ModulesGarden\Servers\ProxmoxVps\Core\Helper;
+use ModulesGarden\Servers\ProxmoxVps\Core\Http\AbstractClientController;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Traits\WhmcsParams;
+
+class Disk extends AbstractClientController
+{
+    use WhmcsParams;
+    use ProductService;
+
+    public function index()
+    {
+        (new AppParams())->initFromWhmcsParams();
+        $this->acl()->disk();
+        Helper\sl("sidebar")->getSidebar("managementProxmoxVps")->getChild("disk")->setActive(true);
+
+        if ($this->configuration()->isQemu())
+        {
+            return Helper\view()->addElement(DiskDataTable::class);
+        }
+        elseif ($this->configuration()->isLxc())
+        {
+            return Helper\view()->addElement(MountPointDataTable::class);
+        }
+    }
+
+}

+ 23 - 0
app/Http/Client/Firewall.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\Http\Client;
+
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\Helpers\AppParams;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Firewall\Pages\FirewallDataTable;
+use ModulesGarden\Servers\ProxmoxVps\Core\Helper;
+use ModulesGarden\Servers\ProxmoxVps\Core\Http\AbstractClientController;
+
+class Firewall extends AbstractClientController
+{
+    use ProductService;
+
+    public function index()
+    {
+        (new AppParams())->initFromWhmcsParams();
+        $this->acl()->firewall();
+        Helper\sl("sidebar")->getSidebar("managementProxmoxVps")->getChild("firewall")->setActive(true);
+        return Helper\view()->addElement(FirewallDataTable::class);
+    }
+
+}

+ 22 - 0
app/Http/Client/FirewallOption.php

@@ -0,0 +1,22 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\Http\Client;
+
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\Helpers\AppParams;
+use ModulesGarden\Servers\ProxmoxVps\Core\Helper;
+use ModulesGarden\Servers\ProxmoxVps\Core\Http\AbstractClientController;
+
+class FirewallOption extends AbstractClientController
+{
+    use ProductService;
+
+    public function index()
+    {
+        (new AppParams())->initFromWhmcsParams();
+        $this->acl()->firewallOption();
+        Helper\sl("sidebar")->getSidebar("managementProxmoxVps")->getChild("firewallOption")->setActive(true);
+        return Helper\view()->addElement(\ModulesGarden\Servers\ProxmoxVps\App\UI\FirewallOption\Pages\FirewallOption::class);
+    }
+
+}

+ 32 - 0
app/Http/Client/Graph.php

@@ -0,0 +1,32 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\Http\Client;
+
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\Helpers\AppParams;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Graph\Pages\CpuGraph;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Graph\Pages\DiskGraph;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Graph\Pages\MemoryGraph;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Graph\Pages\NetworkGraph;
+use ModulesGarden\Servers\ProxmoxVps\Core\Helper;
+use ModulesGarden\Servers\ProxmoxVps\Core\Http\AbstractClientController;
+
+class Graph extends AbstractClientController
+{
+    use ProductService;
+
+    public function index()
+    {
+        (new AppParams())->initFromWhmcsParams();
+        $this->acl()->graph();
+        Helper\sl("sidebar")->getSidebar("managementProxmoxVps")->getChild("graph")->setActive(true);
+        $view = Helper\view();
+        $view->initCustomAssetFiles();
+        $view->addElement(CpuGraph::class)
+            ->addElement(MemoryGraph::class)
+            ->addElement(NetworkGraph::class)
+            ->addElement(DiskGraph::class);
+        return $view;
+    }
+
+}

+ 93 - 0
app/Http/Client/Home.php

@@ -0,0 +1,93 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\Http\Client;
+
+use ModulesGarden\ProxmoxAddon\App\Models\KeyPair;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\Helpers\AppParams;
+use ModulesGarden\Servers\ProxmoxVps\App\Helpers\ProxmoxAddonValidator;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Home\Pages\DetailsContainer;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Home\Pages\ServiceActions;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Home\Pages\ServiceManagement;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\IpAddress\Pages\IpAddressDataTable;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\ServiceInformation\Pages\ServiceInformation;
+use ModulesGarden\Servers\ProxmoxVps\Core\Helper;
+use ModulesGarden\Servers\ProxmoxVps\Core\Http\AbstractClientController;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Traits\WhmcsParams;
+use Symfony\Component\HttpFoundation\StreamedResponse;
+
+class Home extends AbstractClientController
+{
+
+    use WhmcsParams;
+    use ProductService;
+    use BaseClientController;
+
+    public function index()
+    {
+        if ($this->getWhmcsParamByKey('status') != 'Active')
+        {
+            return;
+        }
+        elseif(!ProxmoxAddonValidator::isInstalled()){
+            ProxmoxAddonValidator::isInstalledOrFail();
+        }
+        else if (!$this->isVpsCreated())
+        {
+            return $this->onVpsBuild();
+        }
+        (new AppParams())->initFromWhmcsParams();
+        return Helper\view()->addElement(ServiceActions::class)
+            ->addElement(ServiceManagement::class)
+            ->addElement(ServiceInformation::class)
+            ->addElement(IpAddressDataTable::class);
+    }
+
+    public function sshPublicKeyDownload()
+    {
+        $response = new StreamedResponse();
+        $response->setStatusCode(200);
+        $response->headers->set('Content-Type', 'application/x-pem-file; charset=utf-8');
+        $response->headers->set('Content-Transfer-Encoding', 'Binary');
+        $response->setCallback(function ()
+        {
+            /**
+             * @var $keyPair KeyPair
+             */
+            $keyPair = KeyPair::ofHostingId($this->getWhmcsParamByKey("serviceid"))->firstOrFail();
+            echo $keyPair->getPublic();
+            die();
+        });
+        $response->headers->set(
+            'Content-Disposition', 'attachment; filename="id_rsa.pub"'
+        );
+        $response->send();
+    }
+
+    public function sshPrivateKeyDownload()
+    {
+        $response = new StreamedResponse();
+        $response->setStatusCode(200);
+        $response->headers->set('Content-Type', 'application/x-pem-file; charset=utf-8');
+        $response->headers->set('Content-Transfer-Encoding', 'Binary');
+        $response->setCallback(function ()
+        {
+            /**
+             * @var $keyPair KeyPair
+             */
+            $keyPair = KeyPair::ofHostingId($this->getWhmcsParamByKey("serviceid"))->firstOrFail();
+            echo $keyPair->getPrivate();
+            //delete private key
+            if ($this->configuration()->isSshDeletePrivateKey())
+            {
+                $keyPair->setPrivate(null);
+                $keyPair->save();
+            }
+            die();
+        });
+        $response->headers->set(
+            'Content-Disposition', 'attachment; filename="id_rsa"'
+        );
+        $response->send();
+    }
+}

+ 37 - 0
app/Http/Client/Network.php

@@ -0,0 +1,37 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\Http\Client;
+
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\Helpers\AppParams;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Network\Pages\NetworkLxcDataTable;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Network\Pages\NetworkQemuDataTable;
+use ModulesGarden\Servers\ProxmoxVps\Core\Helper;
+use ModulesGarden\Servers\ProxmoxVps\Core\Http\AbstractClientController;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Traits\WhmcsParams;
+
+class Network extends AbstractClientController
+{
+    use WhmcsParams;
+    use ProductService;
+
+    public function index()
+    {
+        (new AppParams())->initFromWhmcsParams();
+        $this->acl()->network();
+        Helper\sl("sidebar")->getSidebar("managementProxmoxVps")->getChild("network")->setActive(true);
+        if ($this->configuration()->isQemu())
+        {
+            return Helper\view()->addElement(NetworkQemuDataTable::class);
+        }
+        else
+        {
+            if ($this->configuration()->isLxc())
+            {
+                return Helper\view()->addElement(NetworkLxcDataTable::class);
+            }
+        }
+
+    }
+
+}

+ 59 - 0
app/Http/Client/Reinstall.php

@@ -0,0 +1,59 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\Http\Client;
+
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\Helpers\AppParams;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Reinstall\Pages\IsoDataTable;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Reinstall\Pages\ReinstallTab;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Reinstall\Pages\TemplateDataTable;
+use ModulesGarden\Servers\ProxmoxVps\Core\Helper;
+use ModulesGarden\Servers\ProxmoxVps\Core\Http\AbstractClientController;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Traits\WhmcsParams;
+
+class Reinstall extends AbstractClientController
+{
+    use WhmcsParams;
+    use ProductService;
+    use BaseClientController;
+
+    public function index()
+    {
+        (new AppParams())->initFromWhmcsParams();
+        $this->acl()->reinstall();
+        Helper\sl("sidebar")->getSidebar("managementProxmoxVps")->getChild("reinstall")->setActive(true);
+        if (!$this->isVpsCreated())
+        {
+            return $this->onVpsBuild();
+        }
+        else if ($this->configuration()->isQemu() && $this->configuration()->isPermissionOsTemplate() && $this->configuration()->isPermissionIsoImage())
+        {
+            return Helper\view()->addElement(ReinstallTab::class);
+        }
+        else
+        {
+            if ($this->configuration()->isQemu() && $this->configuration()->isPermissionOsTemplate())
+            {
+                return Helper\view()->addElement(TemplateDataTable::class);
+            }
+            else
+            {
+                if ($this->configuration()->isQemu() && $this->configuration()->isPermissionIsoImage())
+                {
+                    return Helper\view()->addElement(IsoDataTable::class);
+                    //lxc
+                }
+                else
+                {
+                    if ($this->configuration()->isLxc())
+                    {
+                        return Helper\view()->addElement(TemplateDataTable::class);
+                    }
+                }
+            }
+        }
+
+
+    }
+
+}

+ 29 - 0
app/Http/Client/Snapshot.php

@@ -0,0 +1,29 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\Http\Client;
+
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\Helpers\AppParams;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Pages\SnapshotDataTable;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Pages\SnapshotTab;
+use ModulesGarden\Servers\ProxmoxVps\Core\Helper;
+use ModulesGarden\Servers\ProxmoxVps\Core\Http\AbstractClientController;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Traits\WhmcsParams;
+
+class Snapshot extends AbstractClientController
+{
+    use WhmcsParams;
+    use ProductService;
+
+    public function index()
+    {
+        (new AppParams())->initFromWhmcsParams();
+        $this->acl()->snapshot();
+        Helper\sl("sidebar")->getSidebar("managementProxmoxVps")->getChild("snapshot")->setActive(true);
+        if($this->configuration()->isPermissionSnapshotJob()){
+            return Helper\view()->addElement(SnapshotTab::class);
+        }
+        return Helper\view()->addElement(SnapshotDataTable::class);
+    }
+
+}

+ 41 - 0
app/Http/Client/TaskHistory.php

@@ -0,0 +1,41 @@
+<?php
+/* * ********************************************************************
+*  ProxmoxVPS Product developed. (26.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\ProxmoxVps\App\Http\Client;
+
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\Helpers\AppParams;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\TaskHistory\Pages\TaskHistoryDataTable;
+use ModulesGarden\Servers\ProxmoxVps\Core\Helper;
+use ModulesGarden\Servers\ProxmoxVps\Core\Http\AbstractClientController;
+
+class TaskHistory extends AbstractClientController
+{
+
+    use ProductService;
+
+    public function index()
+    {
+        (new AppParams())->initFromWhmcsParams();
+        $this->acl()->taskHistory();
+        Helper\sl("sidebar")->getSidebar("managementProxmoxVps")->getChild("taskHistory")->setActive(true);
+        return Helper\view()->addElement(TaskHistoryDataTable::class);
+    }
+
+}

+ 89 - 0
app/UI/Admin/IpSet/Pages/IpSetDataTable.php

@@ -0,0 +1,89 @@
+<?php
+/* * ********************************************************************
+*  ProxmoxVPS Product developed. (26.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\ProxmoxVps\App\UI\Admin\IpSet\Pages;
+
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\Column;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\DataProviders\Providers\ArrayDataProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\DataTable;
+
+class IpSetDataTable extends DataTable implements AdminArea
+{
+    use ProductService;
+    use ApiService;
+
+    protected $id = 'ipSetDataTable';
+    protected $name = 'ipSetDataTable';
+    protected $title = 'ipSetDataTable';
+    protected $searchable = false;
+    protected $tableLength = "100";
+
+    protected function loadHtml()
+    {
+        $this->addColumn((new Column('name')))
+            ->addColumn((new Column('comment')))
+            ->addColumn((new Column('ipCidr')));
+    }
+
+    public function replaceFieldIpCidr($key, $row)
+    {
+        return $row[$key] ? $row[$key] : '-';
+    }
+
+    protected function loadData()
+    {
+        $data = [];
+        foreach ($this->vm()->getIpSet() as $ipSet)
+        {
+            $cidr = [];
+            foreach ($ipSet->getIpCidr() as $ipCidr)
+            {
+                $cidr[] = $ipCidr->getCidr();
+            }
+            $data[] = [
+                "name"    => $ipSet->getName(),
+                "comment" => $ipSet->getComment(),
+                "ipCidr"  => implode(", ", $cidr)
+            ];
+        }
+        $dataProv = new ArrayDataProvider();
+        $dataProv->setData($data);
+        $this->setDataProvider($dataProv);
+    }
+
+
+    public function initContent()
+    {
+
+    }
+
+    public function isViewFooter()
+    {
+        return false;
+    }
+
+    public function isViewTopBody()
+    {
+        return false;
+    }
+
+}

+ 34 - 0
app/UI/Admin/Product/Buttons/VirtualizationChangButton.php

@@ -0,0 +1,34 @@
+<?php
+
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Buttons;
+
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Modals\VirtualizationChangeModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonCreate;
+
+class VirtualizationChangButton extends ButtonCreate implements AdminArea
+{
+    protected $title = null;
+    protected $name = 'virtualizationChangButton';
+
+    public function initContent()
+    {
+        $this->htmlAttributes['style'] = "display: none;";
+        $this->htmlAttributes['id']    = "virtualizationChangButton";
+        $this->initLoadModalAction(new VirtualizationChangeModal());
+    }
+
+    public function loadDataToForm()
+    {
+
+    }
+
+    public function getSections()
+    {
+
+    }
+
+
+}

+ 137 - 0
app/UI/Admin/Product/Forms/MainForm.php

@@ -0,0 +1,137 @@
+<?php
+/**********************************************************************
+ * ProxmoxVPS developed. (26.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\ProxmoxVps\App\UI\Admin\Product\Forms;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Buttons\VirtualizationChangButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Providers\ProductProvider;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections\AdminNotificationSection;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections\BackupSection;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections\ClientNotificationSection;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections\ConsoleSection;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections\FirewallOptionSection;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections\FirewallSection;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections\HighAvailabilityClusterSection;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections\LoadBalancerSection;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections\Lxc;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections\MainSection;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections\MiscellaneousSection;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections\Qemu;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections\UserSection;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\MainContainer;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\FormIntegration;
+
+class MainForm extends FormIntegration implements AdminArea
+{
+
+    public function initContent()
+    {
+       /**
+         *
+         */
+        $this->initIds('mainForm');
+        $this->setProvider(new ProductProvider($this->getRequestValue('id')));
+        $this->addSection(new VirtualizationChangButton());
+        $this->dataProvider->initData();
+        /**
+         *
+         */
+        $isQemu = !$this->dataProvider->getValueById('customconfigoption[virtualization]') || $this->dataProvider->getValueById('customconfigoption[virtualization]') == "qemu";
+        /**
+         * Main Section
+         */
+        $section = new MainSection();
+        $section->setMainContainer($this->mainContainer);
+        $this->addSection($section);
+
+        if ($isQemu)
+        {
+            // KVM
+            $this->addSection((new Qemu\ContainerSection())->enableToggler())
+                ->addSection((new Qemu\NetworkSection())->enableToggler())
+                ->addSection((new Qemu\DiskSection())->enableToggler())
+                ->addSection((new Qemu\DiskSpeedSection())->enableTogglerAndHide())
+                ->addSection((new Qemu\AdditonalDisk())->enableToggler())
+                ->addSection((new Qemu\AdditonalDiskSpeedSection())->enableToggler())
+                ->addSection((new BackupSection())->enableToggler())
+                ->addSection((new Qemu\BootSection())->enableTogglerAndHide())
+                ->addSection((new FirewallSection())->enableTogglerAndHide())
+                ->addSection((new FirewallOptionSection())->enableTogglerAndHide())
+                ->addSection((new Qemu\CloudInitSection())->enableTogglerAndHide())
+                ->addSection((new Qemu\GuestAgentSection())->enableTogglerAndHide())
+                ->addSection((new UserSection())->enableTogglerAndHide())
+                ->addSection((new MiscellaneousSection())->enableTogglerAndHide())
+                ->addSection((new LoadBalancerSection())->enableTogglerAndHide())
+                ->addSection((new Qemu\ConfigurationSection())->enableTogglerAndHide())
+                ->addSection((new Qemu\AdvancedSection())->enableTogglerAndHide())
+                ->addSection((new HighAvailabilityClusterSection())->enableTogglerAndHide())
+                ->addSection((new ConsoleSection())->enableTogglerAndHide())
+                ->addSection((new AdminNotificationSection())->enableTogglerAndHide())
+                ->addSection((new ClientNotificationSection())->enableTogglerAndHide())
+                ->addSection((new Qemu\ClientAreaSection())->enableToggler())
+                ->addSection((new Qemu\ConfigurableOptionUnitsSection())->enableToggler());
+        }
+        else
+        {
+            //LXC
+            $this->addSection((new Lxc\ContainerSection())->enableToggler())
+                ->addSection((new Lxc\MountPointSection())->enableToggler())
+                ->addSection((new BackupSection())->enableToggler())
+                ->addSection((new Lxc\NetworkSection())->enableToggler())
+                ->addSection((new FirewallSection())->enableTogglerAndHide())
+                ->addSection((new UserSection())->enableTogglerAndHide())
+                ->addSection((new MiscellaneousSection())->enableTogglerAndHide())
+                ->addSection((new LoadBalancerSection())->enableTogglerAndHide())
+                ->addSection((new Lxc\ConfigurationSection())->enableTogglerAndHide())
+                ->addSection((new HighAvailabilityClusterSection())->enableTogglerAndHide())
+                ->addSection((new ConsoleSection())->enableTogglerAndHide())
+                ->addSection((new AdminNotificationSection())->enableTogglerAndHide())
+                ->addSection((new ClientNotificationSection())->enableTogglerAndHide())
+                ->addSection((new Lxc\ClientAreaSection())->enableToggler())
+                ->addSection((new Lxc\ConfigurableOptionUnitsSection())->enableToggler());
+        }
+
+        $this->loadDataToForm();
+    }
+
+    public function getSwitcherFields()
+    {
+        $this->setMainContainer(new MainContainer());
+        $this->runInitContentProcess();
+        $fieldNames = [];
+        foreach ($this->getSections() as $section)
+        {
+            foreach ((array)$section->getSections() as $s)
+            {
+                foreach ($s->getFields() as $field)
+                {
+                    if (!$field instanceof Switcher)
+                    {
+                        continue;
+                    }
+                    $name         = str_replace(["customconfigoption[", "]"], ["", ""], $field->getName());
+                    $fieldNames[] = $name;
+                }
+            }
+        }
+        return array_unique($fieldNames);
+    }
+}

+ 35 - 0
app/UI/Admin/Product/Forms/VirtualizationChangeForm.php

@@ -0,0 +1,35 @@
+<?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\ProxmoxVps\App\UI\Admin\Product\Forms;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+
+
+class VirtualizationChangeForm extends BaseForm implements AdminArea
+{
+    public function initContent()
+    {
+        $this->initIds('virtualizationChangeForm');
+        $this->addClass(["dupa"]);
+        $this->setConfirmMessage('confirmVirtualizationChange');
+    }
+
+}

+ 53 - 0
app/UI/Admin/Product/Modals/VirtualizationChangeModal.php

@@ -0,0 +1,53 @@
+<?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\ProxmoxVps\App\UI\Admin\Product\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Forms\VirtualizationChangeForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ModalActionButtons\BaseAcceptButton;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ModalActionButtons\BaseCancelButton;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmSuccess;
+
+class VirtualizationChangeModal extends ModalConfirmSuccess implements AdminArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('virtualizationChangeModal');
+        $this->addForm(new VirtualizationChangeForm());
+    }
+
+
+    protected function initActionButtons()
+    {
+        if (!empty($this->actionButtons))
+        {
+            return $this;
+        }
+        $acceptButton = new BaseAcceptButton;
+        $acceptButton->deleteHtmlAttribute('@click');
+        $acceptButton->addClass('virtualizationChangeConfirmButton');
+        $this->addActionButton($acceptButton);
+        $this->addActionButton(new BaseCancelButton);
+
+        return $this;
+    }
+
+}

+ 524 - 0
app/UI/Admin/Product/Providers/ProductProvider.php

@@ -0,0 +1,524 @@
+<?php
+/**********************************************************************
+ * ProxmoxVPS developed. (26.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\ProxmoxVps\App\UI\Admin\Product\Providers;
+
+use MGProvision\Proxmox\v2\models\Node;
+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\Models\CloudInitScript;
+use ModulesGarden\ProxmoxAddon\App\Models\IpAddress;
+use ModulesGarden\ProxmoxAddon\App\Models\ProductConfiguration;
+use ModulesGarden\ProxmoxAddon\App\Models\Whmcs\Product;
+use ModulesGarden\ProxmoxAddon\App\Repositories\Vps\ProductConfigurationRepository;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\Enum\JobPeriod;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Forms\MainForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\FileReader\Reader\Json;
+use ModulesGarden\Servers\ProxmoxVps\Core\Models\Whmcs\EmailTemplate;
+use ModulesGarden\Servers\ProxmoxVps\Core\ModuleConstants;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\DataProviders\BaseDataProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+
+class ProductProvider extends BaseDataProvider implements AdminArea
+{
+    use ApiService;
+    use ProductService;
+
+    private $productId;
+
+    /**
+     * @var ProductConfigurationRepository
+     */
+    protected $configuration;
+    /**
+     * @var Node
+     */
+    private $node;
+
+    /**
+     * ProductConfigurationProvider constructor.
+     * @param $productId
+     */
+    public function __construct($productId)
+    {
+        if (!is_numeric($productId))
+        {
+            throw new \InvalidArgumentException("The product id must be definded.");
+        }
+        $this->configuration = new ProductConfigurationRepository($productId);
+        $this->productId     = $productId;
+    }
+
+    public function isSupportedModule()
+    {
+        return Product::where("id", $this->configuration->getProductId())
+                   ->where("servertype", "proxmoxVPS")->count() == 1;
+    }
+
+    public function read()
+    {
+        foreach ($this->configuration->all() as $key => $value)
+        {
+            //multiselect
+            if (is_array($value))
+            {
+                $this->data[sprintf("customconfigoption[%s][]", $key)] = $value;
+                continue;
+            }
+            $this->data[sprintf("customconfigoption[%s]", $key)] = $value;
+        }
+        $this->initApi();
+        $this->defaultRead();
+        if (!$this->configuration->getVirtualization() || $this->configuration->isQemu())
+        {
+            //kvm
+            $this->qemuRead();
+        }
+        else
+        {
+            //lxc
+            $this->lxcRead();
+        }
+    }
+
+    private function initApi()
+    {
+        $lang    = sl("lang");
+        $product = Product::where("id", $this->productId)->firstOrFail();
+        sl("whmcsParams")->setParams($product->getParams());
+    }
+
+    private function defaultRead()
+    {
+        $lang = sl("lang");
+        //Virtualization
+        $this->availableValues["customconfigoption[virtualization]"] = ["qemu" => $lang->tr("KVM"), "lxc" => $lang->tr("LXC")];
+        //Default Node
+        $this->availableValues["customconfigoption[defaultNode]"] = ["serverNode" => $lang->tr('Server-Node'), "autoNode" => $lang->tr('Auto-Node')];
+        $nodeRepository                                           = new NodeRepository();
+        $nodeRepository->setApi($this->api());
+        $nodeRepository->findOnline(true);
+        foreach ($nodeRepository->fetch() as $node)
+        {
+            $this->availableValues["customconfigoption[defaultNode]"][$node->getNode()] = $node->getNode();
+        }
+        //realm
+        foreach ($this->api()->get("/access/domains") as $d)
+        {
+            if (!$d['realm'])
+            {
+                continue;
+            }
+            $this->availableValues["customconfigoption[realm]"][$d['realm']] = $lang->tr($d['comment']);
+        }
+        //userRole
+        foreach ($this->api()->get("/access/roles") as $r)
+        {
+            if (!$r['roleid'])
+            {
+                continue;
+            }
+            $this->availableValues["customconfigoption[userRole]"][$r['roleid']] = $lang->tr($r['roleid']);
+        }
+        //welcomeEmailTemplateId
+        $this->availableValues["customconfigoption[welcomeEmailTemplateId]"][0] = "";
+        foreach (EmailTemplate::where('type', "product")->pluck("name", "id")->all() as $key => $value)
+        {
+            $this->availableValues["customconfigoption[welcomeEmailTemplateId]"][$key] = $value;
+        }
+        //reinstallEmailTemplateId
+        $this->availableValues["customconfigoption[reinstallEmailTemplateId]"][0] = "";
+        foreach (EmailTemplate::where('type', "product")->pluck("name", "id")->all() as $key => $value)
+        {
+            $this->availableValues["customconfigoption[reinstallEmailTemplateId]"][$key] = $value;
+        }
+        //upgradeNotificationTemplateId
+        $this->availableValues["customconfigoption[serviceCreationFailedTemplateId]"][0] = "";
+        foreach (EmailTemplate::where('type', "admin")->where("custom", 1)->pluck("name", "id")->all() as $key => $value)
+        {
+            $this->availableValues["customconfigoption[serviceCreationFailedTemplateId]"][$key] = $value;
+        }
+        //upgradeNotificationTemplateId
+        $this->availableValues["customconfigoption[upgradeNotificationTemplateId]"] = $this->availableValues["customconfigoption[serviceCreationFailedTemplateId]"];
+        //loadBalancerOnUpgrade
+        $this->availableValues["customconfigoption[loadBalancerOnUpgrade]"] = ['0' => $lang->tr('None'), "block" => $lang->tr("Block"), "migrate" => $lang->tr("Migrate")];
+        //backupStorage
+        if (in_array($this->configuration->getDefaultNode(), $this->availableValues["customconfigoption[defaultNode]"]))
+        {
+            $this->node = new Node($this->configuration->getDefaultNode());
+        }
+        else
+        {//"Auto-Node" or 'Server-Node' or empty
+
+            $servePrivateIP =  $this->getServerPrivateIpAddress();
+            $serverIp = $servePrivateIP ? $servePrivateIP : $this->getWhmcsParamByKey('serverip');
+            $this->node = $nodeRepository->findWithHostOrIp($this->getWhmcsParamByKey('serverhostname'), $serverIp );
+        }
+        $this->node->setApi($this->api());
+        $storageRepository = new StorageRepository();
+        $storageRepository->findByNodes([$this->node->getNode()])
+            ->findEnabed();
+        foreach ($storageRepository->fetch() as $entity)
+        {
+            if (!in_array("backup", $entity->getContentAsArray()))
+            {
+                continue;
+            }
+            $this->availableValues["customconfigoption[backupStorage]"] [$entity->getStorage()] = $lang->tr($entity->getStorage());
+        }
+        //clusterState
+        $this->availableValues["customconfigoption[clusterState]"] = ['' => "", 'started' => $lang->tr('Started'), 'stopped' => $lang->tr('Stopped'), 'enabled' => $lang->tr('Enabled'), 'disabled' => $lang->tr('Disabled'), 'ignored' => $lang->tr('Ignored')];
+        //firewallInterfaces
+        $this->availableValues["customconfigoption[firewallInterfaces][]"] = ["venet" => $lang->tr("venet"), "eth" => $lang->tr("eth\d+")];
+        //clusterGroup
+        $this->availableValues["customconfigoption[clusterGroup]"] = ['' => ""];
+        foreach ($this->api()->get('/cluster/ha/groups') as $g)
+        {
+            $this->availableValues["customconfigoption[clusterGroup]"][$g['group']] = ucfirst($g['group']);
+        }
+        //suspensionAction
+        $this->availableValues["customconfigoption[suspensionAction]"] = ['0' => $lang->tr('Default'), "stop" => $lang->tr('Stop VM'), 'shutdown' => $lang->tr('Shutdown VM')];
+        if ($this->configuration()->isQemu())
+        {
+            $this->availableValues["customconfigoption[suspensionAction]"]["suspend"] = $lang->tr("Pause VM");
+            $this->availableValues["customconfigoption[suspensionAction]"]["hibernate"] = $lang->tr("Hibernate VM");
+        }
+        //tag
+        $this->availableValues["customconfigoption[tags][]"];
+        foreach (IpAddress::select("tag")->whereNotNull("tag")->where("tag", ">", 0)->groupBy("tag")->pluck("tag")->all() as $tag)
+        {
+            $this->availableValues["customconfigoption[tags][]"][$tag] = $tag;
+        }
+        //pool
+        $this->availableValues["customconfigoption[pool]"]=[""];
+        foreach ($this->api()->get('/pools') as $pool)
+        {
+            $this->availableValues["customconfigoption[pool]"][$pool['poolid']] = $lang->tr($pool['poolid']);
+        }
+        //permissionSnapshotJobPeriod
+        $this->availableValues["customconfigoption[permissionSnapshotJobPeriod][]"] = [
+            JobPeriod::HOURLY => $lang->tr(JobPeriod::HOURLY),
+            JobPeriod::DAILY => $lang->tr(JobPeriod::DAILY )
+        ];
+        //permissionFirewalOptions
+        $this->availableValues["customconfigoption[permissionFirewalOptions][]"] = [
+            "enable" => $lang->abtr("Enable/Disable Firewall"),
+            "dhcp"  => $lang->abtr("DHCP"),
+            "radv"  => $lang->abtr("Allow Router Advertisement"),
+            "ndp"  => $lang->abtr("NDP"),
+            "macfilter"  => $lang->abtr("MAC Filter"),
+            "ipfilter"  => $lang->abtr("IP Filter"),
+        ];
+    }
+
+    /**
+     * KVM
+     */
+    private function qemuRead()
+    {
+            $lang = sl("lang");
+            //ostype
+            $ostype = new Json('ostype.json', ModuleConstants::getFullPathWhmcs('modules', 'addons', 'proxmoxAddon', 'storage', 'app'));
+            foreach ($ostype->get() as $k => $ostype)
+            {
+                $this->availableValues["customconfigoption[ostype]"][$k] = $lang->tr($ostype);
+            }
+            //hotplug
+            $this->availableValues["customconfigoption[hotplug][]"] = [ "disk" => $lang->tr('disk'), "network" => $lang->tr('network'),  "usb" => $lang->tr('usb'),  "cpu" => $lang->tr('cpu'),   "memory" => $lang->tr('memory')];
+            //keyboard
+            $this->availableValues["customconfigoption[keyboard]"] = ['', 'pt' => $lang->tr('pt'), "tr" => $lang->tr('tr'), 'ja' => $lang->tr('ja'), 'es'  => $lang->tr('es'), 'no' => $lang->tr('no'), 'is' => $lang->tr('is'), 'fr-ca' => $lang->tr('fr-ca'), 'fr' => $lang->tr('fr'), 'pt-br' => $lang->tr('pt-br'),  'da' => $lang->tr('da'), 'fr-ch' => $lang->tr('fr-ch'),  'sl' => $lang->tr('sl'),  'de-ch' => $lang->tr('de-ch'), 'en-gb' => $lang->tr('en-gb'), 'it' => $lang->tr('it'), 'en-us' => $lang->tr('en-us'), 'fr-be' => $lang->tr('fr-be'), 'hu' => $lang->tr('hu'),  'pl'=> $lang->tr('pl'), 'nl' => $lang->tr('nl'), 'mk' => $lang->tr('mk'), 'fi' => $lang->tr('fi'), 'lt' => $lang->tr('lt'), 'sv'=> $lang->tr('sv'), 'de' => $lang->tr('de')];
+            //vga
+            $this->availableValues["customconfigoption[vga]"] = [
+                "std"     => $lang->tr("Standard VGA"),
+                "cirrus"  => $lang->tr("Cirrus Logic"),
+                "vmware"  => $lang->tr("VMWare"),
+                "serial0" => $lang->tr("Serial terminal 0"),
+                "serial1" => $lang->tr("Serial terminal 1"),
+                "serial2" => $lang->tr("Serial terminal 2"),
+                "serial3" => $lang->tr("Serial terminal 3"),
+                "qxl"     => $lang->tr("SPICE"),
+                "qxl2"    => $lang->tr("SPICE dual monitor"),
+                "qxl3"    => $lang->tr("SPICE three monitor"),
+                "qxl4"    => $lang->tr("SPICE four monitor"),
+            ];
+            //clientNameForContainer
+            $this->availableValues["customconfigoption[clientNameForContainer]"] = [
+                0                             => 'No',
+                "emptyHostnameOnly"           => 'Yes  [only when hostname is empty]',
+                "overwriteHostname"           => 'Yes [overwrite hostname] ',
+                "overwriteHostnameWithPrefix" => 'Yes [overwrite hostname with container prefix and service id] ',
+            ];
+            //cloneMode
+            $this->availableValues["customconfigoption[cloneMode]"] = ['1' => $lang->tr('Full Clone'), "0" => $lang->tr("Linked Clone")];
+            //diskStorage images (Disk Images)
+            $storageRepository = new StorageRepository();
+            $storageRepository->findByNodes([$this->node->getNode()])
+                ->findEnabed();
+            foreach ($storageRepository->fetch() as $entity)
+            {
+                if (!in_array("images", $entity->getContentAsArray()))
+                {
+                    continue;
+                }
+                $this->availableValues["customconfigoption[diskStorage]"] [$entity->getStorage()]           = $lang->tr($entity->getStorage());
+                $this->availableValues["customconfigoption[additionalDiskStorage]"] [$entity->getStorage()] = $lang->tr($entity->getStorage());
+            }
+            //diskType
+            $this->availableValues["customconfigoption[diskType]"] = ["ide" => $lang->tr('IDE'), "sata" => $lang->tr('SATA'), "virtio" => $lang->tr('VIRTIO'), "scsi" => $lang->tr('SCSI')];
+            //diskFormat
+            $this->availableValues["customconfigoption[diskFormat]"] = ['raw' => $lang->tr('Raw disk image (raw)'), 'qcow2' => $lang->tr('QEMU image format (qcow2)'), 'vmdk' => $lang->tr('VM image format (vmdk)')];
+            //diskCache
+            $this->availableValues["customconfigoption[diskCache]"] = ['none' => $lang->tr('Default (No Cache)'), 'writethrough' => $lang->tr('Write Through'), 'writeback' => $lang->tr('Write Back'), 'unsafe' => $lang->tr('Write Back (Unsafe)'), 'directsync' => $lang->tr('Direct Sync')];
+            //scsihw
+            $this->availableValues["customconfigoption[scsihw]"] = [
+                '0' => $lang->abtr('Default (LSI 53C895A)'),
+                "lsi" => $lang->abtr('LSI 53C895A'),
+                "lsi53c810" => $lang->abtr('LSI 53C810'),
+                'virtio-scsi-pci' => $lang->abtr('VirtIO SCSI'),
+                "virtio-scsi-single" => $lang->abtr('VirtIO SCSI single'),
+                'megasas' => $lang->abtr('MegaRAID SAS 8708EM2'),
+                "pvscsi" => $lang->abtr('VMware PVSCSI'),
+           ];
+            //additionalDiskStorage
+            $this->availableValues["customconfigoption[additionalDiskStorage]"] = $this->availableValues["customconfigoption[diskStorage]"];
+            //additionalDiskType
+            $this->availableValues["customconfigoption[additionalDiskType][]"] = $this->availableValues["customconfigoption[diskType]"];
+            //additionalDiskFormat
+            $this->availableValues["customconfigoption[additionalDiskFormat][]"] = $this->availableValues["customconfigoption[diskFormat]"];
+            if($this->configuration->getAdditionalDiskStorage() && preg_match("/lvm/", $this->configuration->getAdditionalDiskStorage() )){
+                $this->disabledList["customconfigoption[additionalDiskFormat][]"] = ['qcow2', 'vmdk'];
+            }
+            //additionalDiskCache
+            $this->availableValues["customconfigoption[additionalDiskCache]"] =  $this->availableValues["customconfigoption[diskCache]"];
+            //networkModel
+            $this->availableValues["customconfigoption[networkModel]"] = ['e1000' => $lang->tr('e1000'), 'i82551' => $lang->tr('i82551'), 'i82557b' => $lang->tr('i82557b'), 'i82559er' => $lang->tr('i82559er'), 'ne2k_isa' => $lang->tr('ne2k_isa'), 'ne2k_pci' => $lang->tr('ne2k_pci'), 'pcnet' => $lang->tr('pcnet'), 'rtl8139' => $lang->tr('rtl8139'), 'virtio' => $lang->tr('virtio'), 'vmxnet3' => $lang->tr('vmxnet3')];
+            //bridge
+            foreach ($this->api()->get("/nodes/{$this->node->getNode()}/network") as $network)
+            {
+                if (!in_array($network['type'], ['bridge', 'OVSBridge']))
+                {
+                    continue;
+                }
+                $this->availableValues["customconfigoption[bridge]"] [$network['iface']] = $lang->tr($network['iface']);
+            }
+            ksort($this->availableValues["customconfigoption[bridge]"]);
+            //privateBridge
+            $this->availableValues["customconfigoption[privateBridge]"] = ['0' => ""] + (array)  $this->availableValues["customconfigoption[bridge]"];
+            //networkPrivateModel
+            $this->availableValues["customconfigoption[networkPrivateModel]"] = $this->availableValues["customconfigoption[networkModel]"];
+            //bootDevice1
+            $this->availableValues["customconfigoption[bootDevice1]"] = ['', 'c' => $lang->tr('Hard Disk'), 'd' => $lang->tr('CD-ROM'), 'n' => $lang->tr('Network')];
+            //bootDevice2
+            $this->availableValues["customconfigoption[bootDevice2]"] = $this->availableValues["customconfigoption[bootDevice1]"];
+            //bootDevice3
+            $this->availableValues["customconfigoption[bootDevice3]"] = $this->availableValues["customconfigoption[bootDevice1]"];
+            //permissionOsTemplates
+            $clusterResourcesRepository = new ClusterResourcesRepository();
+            $clusterResourcesRepository->setApi($this->api());
+            $clusterResourcesRepository->findKvmTemplate();
+            foreach ($clusterResourcesRepository->fetch() as $resurce)
+            {
+                if (preg_match('/^custom[0-9]*/', $resurce->getName()))
+                {
+                    continue;
+                }
+                $this->availableValues["customconfigoption[permissionOsTemplates][]"][$resurce->getName()] = $lang->tr($resurce->getName());
+            }
+            //osTemplate
+            $this->availableValues["customconfigoption[osTemplate]"] = ['0' => ""] + (array) $this->availableValues["customconfigoption[permissionOsTemplates][]"];
+            //permissionIsoImage
+            $fileRepository = new FileRepository();
+            $fileRepository->setApi($this->api());
+            $fileRepository->findIso();
+            $fileRepository->findByNode($this->node);
+            $fileRepository->findByStorages($storageRepository->fetchAsArray());
+            foreach ($fileRepository->fetch() as $file)
+            {
+                $this->availableValues["customconfigoption[permissionIsoImages][]"][$file->getVolid()] = $lang->tr($file->getFriendlyName());
+            }
+            //isoImage
+            $this->availableValues["customconfigoption[isoImage]"] = ["none" => $lang->tr("None")] + (array)$this->availableValues["customconfigoption[permissionIsoImages][]"];
+
+            //memoryUnit
+            $this->availableValues["customconfigoption[memoryUnit]"] = ['mb' => $lang->tr("MB"), "gb" => $lang->tr("GB")];
+            //diskUnit
+            $this->availableValues["customconfigoption[diskUnit]"] = ['mb' => $lang->tr("MB"), "gb" => $lang->tr("GB"), "tb" => $lang->tr("TB")];
+            //additionalDiskUnit
+            $this->availableValues["customconfigoption[additionalDiskUnit]"] = ['mb' => $lang->tr("MB"), "gb" => $lang->tr("GB"), "tb" => $lang->tr("TB")];
+            //cdromType
+            $this->availableValues["customconfigoption[cdromType]"] = $this->availableValues["customconfigoption[diskType]"];
+        //bios
+        $this->availableValues["customconfigoption[bios]"] = [
+            '0' => "",
+            'seabios' => $lang->tr('SeaBIOS'),
+            'ovmf' => $lang->tr('OVMF (UEFI)')
+        ];
+        //cloudInitScript
+        $this->availableValues["customconfigoption[cloudInitScript]"] =
+            CloudInitScript::pluck('name','id')->prepend("",0)->toArray();
+        //machine
+        $jsonData = new Json('machine.json', ModuleConstants::getFullPathWhmcs('modules', 'addons', 'proxmoxAddon', 'storage', 'app'));
+        foreach ($jsonData->get() as $k => $name)
+        {
+            $this->availableValues["customconfigoption[machine]"][$k] = $lang->tr($name);
+        }
+        //cpu
+        $jsonData = new Json('cpu.json', ModuleConstants::getFullPathWhmcs('modules', 'addons', 'proxmoxAddon', 'storage', 'app'));
+        foreach ($jsonData->get() as $k => $name)
+        {
+            $this->availableValues["customconfigoption[cpu]"][$k] = $lang->tr($name);
+        }
+    }
+
+    /**
+     * LXC
+     */
+    private function lxcRead()
+    {
+            $lang = sl("lang");
+            //storage
+            $storageRepository = new StorageRepository();
+            $storageRepository->findByNodes([$this->node->getNode()])
+                ->findEnabed();
+            foreach ($storageRepository->fetch() as $storage)
+            {
+                if (!in_array("rootdir", $storage->getContentAsArray()))
+                {
+                    continue;
+                }
+                $this->availableValues["customconfigoption[storage]"][$storage->getStorage()] = $lang->tr($storage->getStorage());
+            }
+            //arch
+            $this->availableValues["customconfigoption[arch]"] = ['0' => "", 'amd64' => $lang->tr("AMD64"), $lang->tr("i386") => $lang->tr("i386")];
+            //cmode
+            $this->availableValues["customconfigoption[cmode]"] = ['0' => "", 'shell' => $lang->tr("shell"), "console" => $lang->tr("console"), "tty" => $lang->tr("tty")];
+            //ostype
+            $this->availableValues["customconfigoption[ostype]"] = ['0' => "", 'debian' => $lang->tr("Debian"), "ubuntu" => $lang->tr("Ubuntu"), "centos" => $lang->tr("centos"), "archlinux" => $lang->tr("Archlinux")];
+            //osTemplate
+            $fileRepository = new FileRepository();
+            $fileRepository->setApi($this->api());
+            $fileRepository->findLxcTemplates();
+            $fileRepository->findByNode($this->node);
+            $fileRepository->findByStorages($storageRepository->fetchAsArray());
+            foreach ($fileRepository->fetch() as $file)
+            {
+                $this->availableValues["customconfigoption[osTemplate]"][$file->getVolid()] = $lang->tr($file->getFriendlyName());
+            }
+            //memoryUnit
+            $this->availableValues["customconfigoption[memoryUnit]"] = ['mb' => $lang->tr("MB"), "gb" => $lang->tr("GB")];
+            //diskUnit
+            $this->availableValues["customconfigoption[diskUnit]"] = ['mb' => $lang->tr("MB"), "gb" => $lang->tr("GB"), "tb" => $lang->tr("TB")];
+            //additionalDiskUnit
+            $this->availableValues["customconfigoption[additionalDiskUnit]"] = ['mb' => $lang->tr("MB"), "gb" => $lang->tr("GB"), "tb" => $lang->tr("TB")];
+            //persimonOsTemplates
+            $this->availableValues["customconfigoption[permissionOsTemplates][]"] = $this->availableValues["customconfigoption[osTemplate]"];
+            //mountPointStorage
+            foreach ($storageRepository->fetch() as $entity)
+            {
+                if (!in_array("rootdir", $entity->getContentAsArray()))
+                {
+                    continue;
+                }
+                $this->availableValues["customconfigoption[mountPointStorage]"][$entity->getStorage()] = $lang->tr($entity->getStorage());
+            }
+            //mountPointAcl
+            $this->availableValues["customconfigoption[mountPointAcl]"] = ["default" => $lang->tr('Default'), "1" => $lang->tr("On"), "0" => $lang->tr("Off")];
+            //ipv4NetworkMode
+            $this->availableValues["customconfigoption[ipv4NetworkMode]"] = ["static" => $lang->tr('Static'), "dhcp" => $lang->tr("DHCP")];
+            //ipv6NetworkMode
+            $this->availableValues["customconfigoption[ipv6NetworkMode]"] = ["static" => $lang->tr('Static'), "dhcp" => $lang->tr("DHCP"), "slaac" => $lang->tr("SLAAC")];
+            //swapUnit
+            $this->availableValues["customconfigoption[swapUnit]"] = ['mb' => $lang->tr("MB"), "gb" => $lang->tr("GB"), "tb" => $lang->tr("TB")];
+            //bridge
+            foreach ($this->api()->get("/nodes/{$this->node->getNode()}/network") as $network)
+            {
+                if (!in_array($network['type'], ['bridge', 'OVSBridge']))
+                {
+                    continue;
+                }
+                $this->availableValues["customconfigoption[bridge]"] [$network['iface']] = $lang->tr($network['iface']);
+            }
+            ksort($this->availableValues["customconfigoption[bridge]"]);
+            //privateBridge
+            $this->availableValues["customconfigoption[privateBridge]"] = ['0' => ""] + (array)  $this->availableValues["customconfigoption[bridge]"];
+    }
+
+    public function update()
+    {
+        $this->loadRequestObj();
+        if (empty($this->request->get('customconfigoption')))
+        {
+            return;
+        }
+
+        try{
+            $form           = new MainForm();
+            $switcherFields = $form->getSwitcherFields();
+            $values         = $this->request->get('customconfigoption');
+            foreach ($values as $k => $v)
+            {
+                if (in_array($k, $switcherFields))
+                {
+                    unset($switcherFields[array_search($k, $switcherFields)]);
+                }
+            }
+            foreach ($switcherFields as $switch)
+            {
+                $values[$switch] = "off";
+            }
+        }catch (\Exception $ex){
+            //login to proxmox host failed
+        }
+        //delete
+        $this->configuration->flush();
+        sleep(1);
+        //save
+        $this->configuration->fill((array)$values)
+            ->save();
+    }
+
+    public function delete()
+    {
+        $this->configuration->flush();
+    }
+
+    public function replicate($replicateProductId){
+        $_SESSION['proxmoxVPS']= null;
+        if(ProductConfiguration::ofProductId($this->productId)->count()){
+            return;
+        }
+        /**
+         * @var $entity ProductConfiguration
+         */
+        foreach (ProductConfiguration::ofProductId($replicateProductId)->get() as $entity)
+        {
+            $newEntity = new ProductConfiguration();
+            $newEntity->setting =  $entity->setting;
+            $newEntity->value = $entity->value;
+            $newEntity->product_id = $this->productId;
+            $newEntity->save();
+        }
+    }
+}

+ 50 - 0
app/UI/Admin/Product/Sections/AdminNotificationSection.php

@@ -0,0 +1,50 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+class AdminNotificationSection extends BoxSection implements AdminArea
+{
+    protected $id = 'adminNotificationSection';
+    protected $name = 'adminNotificationSection';
+    protected $title = 'adminNotificationSection';
+    /**
+     * @var HalfPageSection
+     */
+    private $leftSection;
+    /**
+     * @var HalfPageSection
+     */
+    private $rightSection;
+
+    public function initContent()
+    {
+        $this->leftSection  = new HalfPageSection('leftSection');
+        $this->rightSection = new HalfPageSection('rightSection');
+        $this->addSection($this->leftSection)
+            ->addSection($this->rightSection);
+        $this->initFields();
+    }
+
+    private function initFields()
+    {
+        //Service Creation Failed
+        $field = new Select('customconfigoption[serviceCreationFailedTemplateId]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //To-Do List
+        $field = new Switcher('customconfigoption[toDoList]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Upgrade
+        $field = new Select('customconfigoption[upgradeNotificationTemplateId]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+    }
+
+}

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

@@ -0,0 +1,52 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Text;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+class BackupSection extends BoxSection implements AdminArea
+{
+    protected $id = 'backupSection';
+    protected $name = 'backupSection';
+    protected $title = 'backupSection';
+    /**
+     * @var HalfPageSection
+     */
+    private $leftSection;
+    /**
+     * @var HalfPageSection
+     */
+    private $rightSection;
+
+    public function initContent()
+    {
+        $this->leftSection  = new HalfPageSection('leftSection');
+        $this->rightSection = new HalfPageSection('rightSection');
+        $this->addSection($this->leftSection)
+            ->addSection($this->rightSection);
+        $this->initFields();
+    }
+
+    private function initFields()
+    {
+        //Storage
+        $field = new Select('customconfigoption[backupStorage]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Backups Routing
+        $field = new Switcher('customconfigoption[backupRouting]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->rightSection->addField($field);
+        //Store The Backup For X Days
+        $field = new Text('customconfigoption[backupStoreDays]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+    }
+
+}

+ 46 - 0
app/UI/Admin/Product/Sections/ClientNotificationSection.php

@@ -0,0 +1,46 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+class ClientNotificationSection extends BoxSection implements AdminArea
+{
+    protected $id = 'clientNotificationSection';
+    protected $name = 'clientNotificationSection';
+    protected $title = 'clientNotificationSection';
+    /**
+     * @var HalfPageSection
+     */
+    private $leftSection;
+    /**
+     * @var HalfPageSection
+     */
+    private $rightSection;
+
+    public function initContent()
+    {
+        $this->leftSection  = new HalfPageSection('leftSection');
+        $this->rightSection = new HalfPageSection('rightSection');
+        $this->addSection($this->leftSection)
+            ->addSection($this->rightSection);
+        $this->initFields();
+    }
+
+    private function initFields()
+    {
+        //Welcome Email
+        $field = new Select('customconfigoption[welcomeEmailTemplateId]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Reinstall
+        $field = new Select('customconfigoption[reinstallEmailTemplateId]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+
+    }
+
+}

+ 43 - 0
app/UI/Admin/Product/Sections/ConfigurableOptionUnitSection.php

@@ -0,0 +1,43 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+class ConfigurableOptionUnitSection extends BoxSection implements AdminArea
+{
+    protected $id = 'configurableOptionUnitSection';
+    protected $name = 'configurableOptionUnitSection';
+    protected $title = 'configurableOptionUnitSection';
+    /**
+     * @var HalfPageSection
+     */
+    private $leftSection;
+    /**
+     * @var HalfPageSection
+     */
+    private $rightSection;
+
+    public function initContent()
+    {
+        $this->leftSection  = new HalfPageSection('leftSectionsdf');
+        $this->rightSection = new HalfPageSection('rightSectionsdf');
+
+        $this->addSection($this->leftSection)
+            ->addSection($this->rightSection);
+        $this->initFields();
+    }
+
+    private function initFields()
+    {
+        //One User Per VPS
+        $field = new Switcher('customconfigoption[oneUserPerVps]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->leftSection->addField($field);
+    }
+
+}

+ 42 - 0
app/UI/Admin/Product/Sections/ConsoleSection.php

@@ -0,0 +1,42 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Text;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+class ConsoleSection extends BoxSection implements AdminArea
+{
+    protected $id = 'consoleSection';
+    protected $name = 'consoleSection';
+    protected $title = 'consoleSection';
+    /**
+     * @var HalfPageSection
+     */
+    private $leftSection;
+    /**
+     * @var HalfPageSection
+     */
+    private $rightSection;
+
+    public function initContent()
+    {
+        $this->leftSection  = new HalfPageSection('leftSection');
+        $this->rightSection = new HalfPageSection('rightSection');
+        $this->addSection($this->leftSection)
+            ->addSection($this->rightSection);
+        $this->initFields();
+    }
+
+    private function initFields()
+    {
+        //Additional IP Address For VNC Console
+        $field = new Text('customconfigoption[consoleHost]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+
+    }
+
+}

+ 70 - 0
app/UI/Admin/Product/Sections/FirewallOptionSection.php

@@ -0,0 +1,70 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+class FirewallOptionSection extends BoxSection implements AdminArea
+{
+//    protected $id = 'clientNotificationSection';
+//    protected $name = 'clientNotificationSection';
+//    protected $title = 'clientNotificationSection';
+    /**
+     * @var HalfPageSection
+     */
+    private $leftSection;
+    /**
+     * @var HalfPageSection
+     */
+    private $rightSection;
+
+    public function initContent()
+    {
+        $this->initIds('firewallOptionSection');
+        $this->leftSection  = new HalfPageSection('leftSection');
+        $this->rightSection = new HalfPageSection('rightSection');
+        $this->addSection($this->leftSection)
+            ->addSection($this->rightSection);
+        $this->initFields();
+    }
+
+    private function initFields()
+    {
+        //enable
+        $field = new Switcher("customconfigoption[firewalOptionEnable]");
+        $this->addField($field);
+        //dhcp
+        $field = new Switcher("customconfigoption[firewalOptionDhcp]");
+        $field->setDefaultValue("on");
+        $this->addField($field);
+        //ndp
+        $field = new Switcher("customconfigoption[firewalOptionNdp]");
+        $field->setDefaultValue("on");
+        $this->addField($field);
+        //radv
+        $field = new Switcher("customconfigoption[firewalOptionRadv]");
+        $this->addField($field);
+        //macfilter
+        $field = new Switcher("customconfigoption[firewalOptionMacfilter]");
+        $field->setDefaultValue("on");
+        $this->addField($field);
+        //ipfilter
+        $field = new Switcher("customconfigoption[firewalOptionIpfilter]");
+        $this->addField($field);
+    }
+
+    public function addField($field){
+        $total = count($this->leftSection->getFields()) + count($this->rightSection->getFields());
+        if($total % 2 == 0){
+            $this->leftSection->addField($field);
+        }else{
+            $this->rightSection->addField($field);
+        }
+        return $this;
+    }
+
+}

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

@@ -0,0 +1,53 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Text;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+class FirewallSection extends BoxSection implements AdminArea
+{
+    protected $id = 'firewallSection';
+    protected $name = 'firewallSection';
+    protected $title = 'firewallSection';
+    /**
+     * @var HalfPageSection
+     */
+    private $leftSection;
+    /**
+     * @var HalfPageSection
+     */
+    private $rightSection;
+
+    public function initContent()
+    {
+        $this->leftSection  = new HalfPageSection('leftSection');
+        $this->rightSection = new HalfPageSection('rightSection');
+
+        $this->addSection($this->leftSection)
+            ->addSection($this->rightSection);
+        $this->initFields();
+    }
+
+    private function initFields()
+    {
+        //Interfaces
+        $field = new Select('customconfigoption[firewallInterfaces][]');
+        $field->setDescription('tip');
+        $field->enableMultiple();
+        $this->leftSection->addField($field);
+        //Firewall Rules Limit
+        $field = new Text('customconfigoption[firewallMaxRules]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //IPSet IP Filter
+        $field = new Switcher('customconfigoption[ipsetIpFilter]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+    }
+
+}

+ 54 - 0
app/UI/Admin/Product/Sections/HighAvailabilityClusterSection.php

@@ -0,0 +1,54 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Text;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+class HighAvailabilityClusterSection extends BoxSection implements AdminArea
+{
+    protected $id = 'highAvailabilityClusterSection';
+    protected $name = 'highAvailabilityClusterSection';
+    protected $title = 'highAvailabilityClusterSection';
+    /**
+     * @var HalfPageSection
+     */
+    private $leftSection;
+    /**
+     * @var HalfPageSection
+     */
+    private $rightSection;
+
+    public function initContent()
+    {
+        $this->leftSection  = new HalfPageSection('leftSection');
+        $this->rightSection = new HalfPageSection('rightSection');
+        $this->addSection($this->leftSection)
+            ->addSection($this->rightSection);
+        $this->initFields();
+    }
+
+    private function initFields()
+    {
+        //State
+        $field = new Select('customconfigoption[clusterState]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Group
+        $field = new Select('customconfigoption[clusterGroup]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Max. Restart
+        $field = new Text('customconfigoption[clusterMaxRestart]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Max. Relocate
+        $field = new Text('customconfigoption[clusterMaxRelocate]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+    }
+
+}

+ 55 - 0
app/UI/Admin/Product/Sections/LoadBalancerSection.php

@@ -0,0 +1,55 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+class LoadBalancerSection extends BoxSection implements AdminArea
+{
+    protected $id = 'loadBalancerSection';
+    protected $name = 'loadBalancerSection';
+    protected $title = 'loadBalancerSection';
+    /**
+     * @var HalfPageSection
+     */
+    private $leftSection;
+    /**
+     * @var HalfPageSection
+     */
+    private $rightSection;
+
+    public function initContent()
+    {
+        $this->leftSection  = new HalfPageSection('leftSection');
+        $this->rightSection = new HalfPageSection('rightSection');
+
+        $this->addSection($this->leftSection)
+            ->addSection($this->rightSection);
+        $this->initFields();
+    }
+
+    private function initFields()
+    {
+        //Enable
+        $field = new Switcher('customconfigoption[loadBalancer]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //On Upgrade
+        $field = new Select('customconfigoption[loadBalancerOnUpgrade]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Shutdown VM on Upgrade
+        $field = new Switcher('customconfigoption[loadBalancerShutdownOnUpgrade]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Stop VM If Shutdown Fails
+        $field = new Switcher('customconfigoption[loadBalancerStopOnUpgrade]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+    }
+
+}

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

@@ -0,0 +1,154 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections\Lxc;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+class ClientAreaSection extends BoxSection implements AdminArea
+{
+    protected $id = 'clientAreaSection';
+    protected $name = 'clientAreaSection';
+    protected $title = 'clientAreaSection';
+    /**
+     * @var HalfPageSection
+     */
+    private $leftSection;
+    /**
+     * @var HalfPageSection
+     */
+    private $rightSection;
+
+    public function initContent()
+    {
+        $this->leftSection  = new HalfPageSection('leftSection');
+        $this->rightSection = new HalfPageSection('rightSection');
+        $this->addSection($this->leftSection)
+            ->addSection($this->rightSection);
+        $this->initFields();
+    }
+
+    private function initFields()
+    {
+        //Start
+        $field = new Switcher('customconfigoption[permissionStart]');
+        $field->setDefaultValue("on");
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Reboot
+        $field = new Switcher('customconfigoption[permissionReboot]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->rightSection->addField($field);
+        //Stop
+        $field = new Switcher('customconfigoption[permissionStop]');
+        $field->setDefaultValue("on");
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Shutdown
+        $field = new Switcher('customconfigoption[permissionShutdown]');
+        $field->setDefaultValue("on");
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //noVNC Console
+        $field = new Switcher('customconfigoption[permissionNovnc]');
+        $field->setDefaultValue("on");
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //SPICE Console
+        $field = new Switcher('customconfigoption[permissionSpice]');
+        $field->setDefaultValue("on");
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //xterm.js Console
+        $field = new Switcher('customconfigoption[permissionXtermjs]');
+        $field->setDefaultValue("on");
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Reinstallation
+        $field = new Switcher('customconfigoption[permissionReinstall]');
+        $field->setDefaultValue("on");
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //OS Templates
+        $field = new Select('customconfigoption[permissionOsTemplates][]');
+        $field->setDescription('tip');
+        $field->enableMultiple();
+        $this->rightSection->addField($field);
+        //MRTG Graphics
+        $field = new Switcher('customconfigoption[permissionGraph]');
+        $field->setDefaultValue("on");
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Backup
+        $field = new Switcher('customconfigoption[permissionBackup]');
+        $field->setDefaultValue("on");
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Scheduled Backup Jobs
+        $field = new Switcher('customconfigoption[permissionBackupJob]');
+        $field->setDefaultValue("on");
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Task History
+        $field = new Switcher('customconfigoption[permissionTaskHistory]');
+        $field->setDefaultValue("on");
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Network
+        $field = new Switcher('customconfigoption[permissionNetwork]');
+        $field->setDefaultValue("on");
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Snapshots
+        $field = new Switcher('customconfigoption[permissionSnapshot]');
+        $field->setDefaultValue("on");
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Firewall
+        $field = new Switcher('customconfigoption[permissionFirewall]');
+        $field->setDefaultValue("on");
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Firewall Options
+        $field = new Switcher('customconfigoption[permissionFirewallOption]');
+        $field->setDefaultValue("on");
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Disks Management
+        $field = new Switcher('customconfigoption[permissionDisk]');
+        $field->setDefaultValue("on");
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Snapshot Jobs
+        $field = new Switcher('customconfigoption[permissionSnapshotJob]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->leftSection->addField($field);
+        //How Often
+        $field = new Select('customconfigoption[permissionSnapshotJobPeriod][]');
+        $field->setDescription('tip');
+        $field->enableMultiple();
+        $this->rightSection->addField($field);
+        //permissionfirewalOptions
+        $field = new Select("customconfigoption[permissionFirewalOptions][]");
+        $field->enableMultiple();
+        $field->setDescription('description');
+        $this->addField($field);
+
+    }
+
+    public function addField($field){
+        $total = count($this->leftSection->getFields()) + count($this->rightSection->getFields());
+        if($total % 2 == 0){
+            $this->leftSection->addField($field);
+        }else{
+            $this->rightSection->addField($field);
+        }
+        return $this;
+    }
+
+}

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

@@ -0,0 +1,57 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections\Lxc;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+class ConfigurableOptionUnitsSection extends BoxSection implements AdminArea
+{
+    protected $id = 'configurableOptionUnitsSection';
+    protected $name = 'configurableOptionUnitsSection';
+    protected $title = 'configurableOptionUnitsSection';
+    /**
+     * @var HalfPageSection
+     */
+    private $leftSection;
+    /**
+     * @var HalfPageSection
+     */
+    private $rightSection;
+
+    public function initContent()
+    {
+        $this->leftSection  = new HalfPageSection('leftSection');
+        $this->rightSection = new HalfPageSection('rightSection');
+        $this->addSection($this->leftSection)
+            ->addSection($this->rightSection);
+        $this->initFields();
+    }
+
+    private function initFields()
+    {
+        //SWAP For the VM - MB/GB
+        $field = new Select('customconfigoption[swapUnit]');
+        $field->setDefaultValue("mb");
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Memory- MB/GB
+        $field = new Select('customconfigoption[memoryUnit]');
+        $field->setDefaultValue("mb");
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Disk Size - MB/GB/TB
+        $field = new Select('customconfigoption[diskUnit]');
+        $field->setDefaultValue("gb");
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Additional Disks Size -  MB/GB/TB
+        $field = new Select('customconfigoption[additionalDiskUnit]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("gb");
+        $this->rightSection->addField($field);
+    }
+
+}

+ 122 - 0
app/UI/Admin/Product/Sections/Lxc/ConfigurationSection.php

@@ -0,0 +1,122 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections\Lxc;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Text;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Textarea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+class ConfigurationSection extends BoxSection implements AdminArea
+{
+    protected $id = 'lxcConfigurationSection';
+    protected $name = 'lxcConfigurationSection';
+    protected $title = 'lxcConfigurationSection';
+    /**
+     * @var HalfPageSection
+     */
+    private $leftSection;
+    /**
+     * @var HalfPageSection
+     */
+    private $rightSection;
+
+    public function initContent()
+    {
+        $this->leftSection  = new HalfPageSection('leftSection');
+        $this->rightSection = new HalfPageSection('rightSection');
+        $this->addSection($this->leftSection)
+            ->addSection($this->rightSection);
+        $this->initFields();
+    }
+
+    private function initFields()
+    {
+        //OS Architecture Type
+        $field = new Select('customconfigoption[arch]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Console Type
+        $field = new Select('customconfigoption[cmode]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Console
+        $field = new Switcher('customconfigoption[console]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->rightSection->addField($field);
+        //OS Type
+        $field = new Select('customconfigoption[ostype]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Start At Boot
+        $field = new Switcher('customconfigoption[onboot]');
+        $this->rightSection->addField($field);
+        //Add The VM To The Specific Pool
+        $field = new  Select('customconfigoption[pool]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Protection
+        $field = new Switcher('customconfigoption[protection]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Container Notes
+        $field = new Textarea('customconfigoption[description]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("Client: {\$client_name}  (ID: {\$client_id})\nEmail: {\$client_email}\nService ID: {\$service_id}\nHostname: {\$service_domain}\nMain IP: {\$service_dedicated_ip}\n{if \$service_assigned_ips}IP address allocation: {\$service_assigned_ips}\n{/if}\nProduct:  {\$product_name} (ID: {\$product_id})");
+        $this->leftSection->addField($field);
+        //Startup
+        $field = new Text('customconfigoption[startup]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Amount of tty For The VM
+        $field = new Text('customconfigoption[tty]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Unprivileged
+        $field = new Switcher('customconfigoption[unprivileged]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //SSH Key Pairs
+        $field = new Switcher('customconfigoption[sshKeyPairs]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Delete Private Key
+        $field = new Switcher('customconfigoption[sshDeletePrivateKey]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Start after created
+        $field = new Switcher('customconfigoption[start]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //featureKeyctl
+        $field = new Switcher('customconfigoption[featureKeyctl]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //featureNesting
+        $field = new Switcher('customconfigoption[featureNesting]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //featureNfs
+        $field = new Switcher('customconfigoption[featureNfs]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //featureCifs
+        $field = new Switcher('customconfigoption[featureCifs]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //featureFuse
+        $field = new Switcher('customconfigoption[featureFuse]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //featureMknod
+        $field = new Switcher('customconfigoption[featureMknod]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+
+    }
+
+}

+ 120 - 0
app/UI/Admin/Product/Sections/Lxc/ContainerSection.php

@@ -0,0 +1,120 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections\Lxc;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Text;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+class ContainerSection extends BoxSection implements AdminArea
+{
+    protected $id = 'containerSection';
+    protected $name = 'containerSection';
+    protected $title = 'containerSection';
+    /**
+     * @var HalfPageSection
+     */
+    private $leftSection;
+    /**
+     * @var HalfPageSection
+     */
+    private $rightSection;
+
+    public function initContent()
+    {
+        $this->leftSection  = new HalfPageSection('leftSection');
+        $this->rightSection = new HalfPageSection('rightSection');
+        $this->addSection($this->leftSection)
+            ->addSection($this->rightSection);
+        $this->initFields();
+    }
+
+    private function initFields()
+    {
+        //Storage
+        $field = new Select('customconfigoption[storage]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //OS Template
+        $field = new Select('customconfigoption[osTemplate]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //CPU Limit
+        $field = new Text('customconfigoption[cpulimit]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Cores
+        $field = new Text('customconfigoption[cores]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //SWAP For the VM in MB
+        $field = new Text('customconfigoption[swap]');
+        $field->setDescription('tip');
+        $field->setDefaultValue(512);
+        $this->rightSection->addField($field);
+        //CPU Weight For The VM
+        $field = new Text('customconfigoption[cpuunits]');
+        $field->setDescription('tip');
+        $field->setDefaultValue(1024);
+        $this->leftSection->addField($field);
+        //Memory
+        $field = new Text('customconfigoption[memory]');
+        $field->setDescription('tip');
+        $field->setDefaultValue(512);
+        $this->leftSection->addField($field);
+        //Disk Size
+        $field = new Text('customconfigoption[diskSize]');
+        $field->setDescription('tip');
+        $field->setDefaultValue(32);
+        $this->leftSection->addField($field);
+        //Additional Disks Size
+        $field = new Text('customconfigoption[additionalDiskSize]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Network Rate Limit
+        $field = new Text('customconfigoption[rate]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Minimum Network Rate Limit
+        $field = new Text('customconfigoption[minimumRate]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Amount of IPv4 Addresses
+        $field = new Text('customconfigoption[ipv4]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Amount of IPv6 Addresses
+        $field = new Text('customconfigoption[ipv6]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Backups Size Limit
+        $field = new Text('customconfigoption[backupMaxSize]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Backup Files Limit
+        $field = new Text('customconfigoption[backupMaxFiles]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Bandwidth Limit
+        $field = new Text('customconfigoption[bandwidth]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Snapshots Limit
+        $field = new Text('customconfigoption[snapshotMaxFiles]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //snapshotJobs
+        $field = new Text('customconfigoption[snapshotJobs]');
+        $field->setDescription('tip');
+        $field->setDefaultValue(1);
+        $this->rightSection->addField($field);
+        //randomHostname
+        $field = new Switcher('customconfigoption[randomHostname]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+    }
+
+}

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

@@ -0,0 +1,71 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections\Lxc;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+class MountPointSection extends BoxSection implements AdminArea
+{
+    protected $id = 'mountPointSection';
+    protected $name = 'mountPointSection';
+    protected $title = 'mountPointSection';
+    /**
+     * @var HalfPageSection
+     */
+    private $leftSection;
+    /**
+     * @var HalfPageSection
+     */
+    private $rightSection;
+
+    public function initContent()
+    {
+        $this->leftSection = new HalfPageSection('leftSection');
+
+        $this->rightSection = new HalfPageSection('rightSection');
+
+        $this->addSection($this->leftSection)
+            ->addSection($this->rightSection);
+        $this->initFields();
+    }
+
+    private function initFields()
+    {
+        //Storage
+        $field = new Select('customconfigoption[mountPointStorage]');
+        $field->setDefaultValue('local-lvm');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //ACLs
+        $field = new Select('customconfigoption[mountPointAcl]');
+        $field->setDefaultValue("default");
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Read-Only
+        $field = new Switcher('customconfigoption[mountPointRo]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Enable Quota
+        $field = new Switcher('customconfigoption[mountPointQuota]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Skip Replication
+        $field = new Switcher('customconfigoption[mountPointReplicate]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //permissionMountPointBackup
+        $field = new Switcher('customconfigoption[permissionMountPointBackup]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->rightSection->addField($field);
+        //mountPoint
+        $field = new Switcher('customconfigoption[mountPoint]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+    }
+
+}

+ 82 - 0
app/UI/Admin/Product/Sections/Lxc/NetworkSection.php

@@ -0,0 +1,82 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections\Lxc;
+
+use ModulesGarden\ProxmoxAddon\App\Services\Utility;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Text;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+class NetworkSection extends BoxSection implements AdminArea
+{
+    protected $id = 'networkSection';
+    protected $name = 'networkSection';
+    protected $title = 'networkSection';
+    /**
+     * @var HalfPageSection
+     */
+    private $leftSection;
+    /**
+     * @var HalfPageSection
+     */
+    private $rightSection;
+
+    public function initContent()
+    {
+        $this->leftSection  = new HalfPageSection('leftSection');
+        $this->rightSection = new HalfPageSection('rightSection');
+        $this->addSection($this->leftSection)
+            ->addSection($this->rightSection);
+        $this->initFields();
+    }
+
+    private function initFields()
+    {
+        //IPv4 Network Mode
+        $field = new Select('customconfigoption[ipv4NetworkMode]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //IPv6 Network Mode
+        $field = new Select('customconfigoption[ipv6NetworkMode]');
+        $field->setDescription('tip');
+        $field->setDefaultValue('static');
+        $this->rightSection->addField($field);
+        //Bridge
+        $field = new Select('customconfigoption[bridge]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Private Bridge
+        $field = new Select('customconfigoption[privateBridge]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Firewall
+        $field = new Switcher('customconfigoption[networkFirewall]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //VLAN TAG Range From
+        $field = new Text('customconfigoption[tagFrom]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //VLAN TAG Range To
+        $field = new Text('customconfigoption[tagTo]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Tag
+        $field = new Select('customconfigoption[tags][]');
+        $field->enableMultiple();
+        $field->setDescription('tip');
+        if(Utility::isIpManagerProxmoxVPSIntegration()){
+            $field->setDescription('ip_manager_integration_tag');
+        }
+        $this->rightSection->addField($field);
+        //privateNetwork
+        $field = new Switcher('customconfigoption[privateNetwork]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+
+    }
+
+}

+ 65 - 0
app/UI/Admin/Product/Sections/MainSection.php

@@ -0,0 +1,65 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections;
+
+
+use ModulesGarden\Servers\ProxmoxVps\Core\Lang\Lang;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\HalfPageSection;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+
+class MainSection extends BoxSection implements AdminArea
+{
+    protected $id = 'mainSection';
+    protected $name = 'mainSection';
+    protected $title = 'mainSection';
+
+    /**
+     * @var HalfPageSection
+     */
+    private $leftSection;
+    /**
+     * @var HalfPageSection
+     */
+    private $rightSection;
+
+    public function initContent()
+    {
+        $this->leftSection = new HalfPageSection('leftSection');
+
+        $this->rightSection = new HalfPageSection('rightSection');
+
+        $this->addSection($this->leftSection)
+            ->addSection($this->rightSection);
+        $this->initFields();
+    }
+
+    private function initFields()
+    {
+        /**
+         * @var Lang $lang
+         */
+        $lang = sl("lang");
+        //Virtualization
+        $field = new Select('customconfigoption[virtualization]');
+        $field->setDefaultValue('qemu');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Default Node
+        $field = new Select('customconfigoption[defaultNode]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Check Available Resources
+        $field = new Switcher('customconfigoption[checkResources]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //resetUsageFirstDayOfMonth
+        $field = new Switcher('customconfigoption[resetUsageFirstDayOfMonth]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+    }
+
+}

+ 65 - 0
app/UI/Admin/Product/Sections/MiscellaneousSection.php

@@ -0,0 +1,65 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+class MiscellaneousSection extends BoxSection implements AdminArea
+{
+    protected $id = 'miscellaneousSection';
+    protected $name = 'miscellaneousSection';
+    protected $title = 'miscellaneousSection';
+    /**
+     * @var HalfPageSection
+     */
+    private $leftSection;
+    /**
+     * @var HalfPageSection
+     */
+    private $rightSection;
+
+    public function initContent()
+    {
+
+        $this->leftSection  = new HalfPageSection('leftSection');
+        $this->rightSection = new HalfPageSection('rightSection');
+        $this->addSection($this->leftSection)
+            ->addSection($this->rightSection);
+        $this->initFields();
+
+    }
+
+    private function initFields()
+    {
+        //Backup VM Before Reinstallation
+        $field = new Switcher('customconfigoption[backupVmBeforeReinstall]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Reboot VM After Changing Package
+        $field = new Switcher('customconfigoption[rebootVmAfterChangePackage]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Delete Backups After Termination
+        $field = new Switcher('customconfigoption[deleteBackups]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->leftSection->addField($field);
+        //Use Server Nameservers
+        $field = new Switcher('customconfigoption[serverNameservers]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Suspension Action
+        $field = new Select('customconfigoption[suspensionAction]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Bandwidth Overage
+        $field = new Switcher('customconfigoption[suspendOnBandwidthOverage]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+    }
+
+}

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

@@ -0,0 +1,88 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections\Qemu;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+class AdditonalDisk extends BoxSection implements AdminArea
+{
+    protected $id = 'additonalDisk';
+    protected $name = 'additonalDisk';
+    protected $title = 'additonalDisk';
+    /**
+     * @var HalfPageSection
+     */
+    private $leftSection;
+    /**
+     * @var HalfPageSection
+     */
+    private $rightSection;
+
+    public function initContent()
+    {
+        $this->leftSection  = new HalfPageSection('leftSection');
+        $this->rightSection = new HalfPageSection('rightSection');
+        $this->addSection($this->leftSection)
+            ->addSection($this->rightSection);
+        $this->initFields();
+    }
+
+    private function initFields()
+    {
+        //Disks Storage
+        $field = new Select('customconfigoption[additionalDiskStorage]');
+        $field->setDefaultValue('local-lvm');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Disks Type
+        $field = new Select('customconfigoption[additionalDiskType][]');
+        $field->setDescription('tip');
+        $field->enableMultiple();
+        $field->setDefaultValue(["ide"]);
+        $this->rightSection->addField($field);
+        //Disk Format
+        $field = new Select('customconfigoption[additionalDiskFormat][]');
+        $field->enableMultiple();
+        $field->setDefaultValue(["raw"]);
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Disk Skip Replication
+        $field = new Switcher('customconfigoption[additionalDiskReplicate]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Disk Cache
+        $field = new Select('customconfigoption[additionalDiskCache]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Disk Discard
+        $field = new Switcher('customconfigoption[additionalDiskDiscard]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Disk IO Thread
+        $field = new Switcher('customconfigoption[additionalDiskIoThread]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Allow Backups On Additional Disks
+        $field = new Switcher('customconfigoption[permissionAdditionalDiskBackup]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Limits
+        $field = new Switcher('customconfigoption[additionalDiskSpeed]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //ssd
+        $field = new Switcher('customconfigoption[additionalDiskSsd]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //additionalDisk
+        $field = new Switcher('customconfigoption[additionalDisk]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+
+    }
+
+}

+ 63 - 0
app/UI/Admin/Product/Sections/Qemu/AdditonalDiskSpeedSection.php

@@ -0,0 +1,63 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections\Qemu;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Text;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+class AdditonalDiskSpeedSection extends BoxSection implements AdminArea
+{
+    protected $id = 'additonalDiskSpeedSection';
+    protected $name = 'additonalDiskSpeedSection';
+    protected $title = 'additonalDiskSpeedSection';
+    /**
+     * @var HalfPageSection
+     */
+    private $leftSection;
+    /**
+     * @var HalfPageSection
+     */
+    private $rightSection;
+
+    public function initContent()
+    {
+        $this->leftSection = new HalfPageSection('leftSection');
+
+        $this->rightSection = new HalfPageSection('rightSection');
+
+        $this->addSection($this->leftSection)
+            ->addSection($this->rightSection);
+        $this->initFields();
+    }
+
+    private function initFields()
+    {
+        //Read Limit (MB/s)
+        $field = new Text('customconfigoption[additionalDiskMbps_rd]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Write Limit (MB/s)
+        $field = new  Text('customconfigoption[additionalDiskMbps_wr]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Read Limit (ops/s)
+        $field = new  Text('customconfigoption[additionalDiskIops_rd]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Read Max Burst (ops)
+        $field = new  Text('customconfigoption[additionalDiskIops_rd_max]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Write Limit (ops/s)
+        $field = new  Text('customconfigoption[additionalDiskIops_wr]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Write Max Burst (ops)
+        $field = new  Text('customconfigoption[additionalDiskIops_wr_max]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+    }
+
+}

+ 92 - 0
app/UI/Admin/Product/Sections/Qemu/AdvancedSection.php

@@ -0,0 +1,92 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections\Qemu;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Text;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Textarea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+class AdvancedSection extends BoxSection implements AdminArea
+{
+    protected $id = 'advancedSection';
+    protected $name = 'advancedSection';
+    protected $title = 'advancedSection';
+    /**
+     * @var HalfPageSection
+     */
+    private $leftSection;
+    /**
+     * @var HalfPageSection
+     */
+    private $rightSection;
+
+    public function initContent()
+    {
+        $this->leftSection  = new HalfPageSection('leftSection');
+        $this->rightSection = new HalfPageSection('rightSection');
+        $this->addSection($this->leftSection)
+            ->addSection($this->rightSection);
+        $this->initFields();
+    }
+
+    private function initFields()
+    {
+        //Minimum RAM For The VM
+        $field = new Text('customconfigoption[balloon]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Memory Shares
+        $field = new Text('customconfigoption[shares]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Arguments-
+        $field = new Textarea('customconfigoption[args]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Local Time For Real Time Clock
+        $field = new Switcher('customconfigoption[localtime]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Maximum Tolerated Downtime
+        $field = new Text('customconfigoption[migrate_downtime]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Maximum Speed For Migrations [MB/s]
+        $field = new Text('customconfigoption[migrate_speed]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Hardware Watchdog Device
+        $field = new Text('customconfigoption[watchdog]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Initial Date Of The Real Time Clock
+        $field = new Text('customconfigoption[startdate]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Startup
+        $field = new Text('customconfigoption[startup]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Time Drift Fix
+        $field = new Switcher('customconfigoption[tdf]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //bwlimit
+        $field = new Text('customconfigoption[bwlimit]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //bios
+        $field = new Select('customconfigoption[bios]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //machine
+        $field = new Select('customconfigoption[machine]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+    }
+
+}

+ 54 - 0
app/UI/Admin/Product/Sections/Qemu/BootSection.php

@@ -0,0 +1,54 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections\Qemu;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Text;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+class BootSection extends BoxSection implements AdminArea
+{
+    protected $id = 'bootSection';
+    protected $name = 'bootSection';
+    protected $title = 'bootSection';
+    /**
+     * @var HalfPageSection
+     */
+    private $leftSection;
+    /**
+     * @var HalfPageSection
+     */
+    private $rightSection;
+
+    public function initContent()
+    {
+        $this->leftSection  = new HalfPageSection('leftSection');
+        $this->rightSection = new HalfPageSection('rightSection');
+        $this->addSection($this->leftSection)
+            ->addSection($this->rightSection);
+        $this->initFields();
+    }
+
+    private function initFields()
+    {
+        //Boot Device 1
+        $field = new Select('customconfigoption[bootDevice1]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Boot Device 2
+        $field = new Select('customconfigoption[bootDevice2]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Boot Device 3
+        $field = new Select('customconfigoption[bootDevice3]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Boot Disk
+        $field = new Text('customconfigoption[bootdisk]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+    }
+
+}

+ 171 - 0
app/UI/Admin/Product/Sections/Qemu/ClientAreaSection.php

@@ -0,0 +1,171 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections\Qemu;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+class ClientAreaSection extends BoxSection implements AdminArea
+{
+    protected $id = 'clientAreaSection';
+    protected $name = 'clientAreaSection';
+    protected $title = 'clientAreaSection';
+    /**
+     * @var HalfPageSection
+     */
+    private $leftSection;
+    /**
+     * @var HalfPageSection
+     */
+    private $rightSection;
+
+    public function initContent()
+    {
+        $this->leftSection  = new HalfPageSection('leftSection');
+        $this->rightSection = new HalfPageSection('rightSection');
+        $this->addSection($this->leftSection)
+            ->addSection($this->rightSection);
+        $this->initFields();
+    }
+
+    private function initFields()
+    {
+        //Start
+        $field = new Switcher('customconfigoption[permissionStart]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->leftSection->addField($field);
+        //Reboot
+        $field = new Switcher('customconfigoption[permissionReboot]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->rightSection->addField($field);
+        //Stop
+        $field = new Switcher('customconfigoption[permissionStop]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->leftSection->addField($field);
+        //Shutdown
+        $field = new Switcher('customconfigoption[permissionShutdown]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->rightSection->addField($field);
+        //noVNC Console
+        $field = new Switcher('customconfigoption[permissionNovnc]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->leftSection->addField($field);
+        //SPICE Console
+        $field = new Switcher('customconfigoption[permissionSpice]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->rightSection->addField($field);
+        //xterm.js Console
+        $field = new Switcher('customconfigoption[permissionXtermjs]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Reinstallation
+        $field = new Switcher('customconfigoption[permissionReinstall]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->rightSection->addField($field);
+        //KVM Templates
+        $field = new Switcher('customconfigoption[permissionOsTemplate]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->leftSection->addField($field);
+        //OS Templates
+        $field = new Select('customconfigoption[permissionOsTemplates][]');
+        $field->setDescription('tip');
+        $field->enableMultiple();
+        $this->rightSection->addField($field);
+        //ISO Images
+        $field = new Switcher('customconfigoption[permissionIsoImage]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->rightSection->addField($field);
+        //ISO Images
+        $field = new Select('customconfigoption[permissionIsoImages][]');
+        $field->setDescription('tip');
+        $field->enableMultiple();
+        $this->leftSection->addField($field);
+        //MRTG Graphics
+        $field = new Switcher('customconfigoption[permissionGraph]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->leftSection->addField($field);
+        //Backup
+        $field = new Switcher('customconfigoption[permissionBackup]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->rightSection->addField($field);
+        //Scheduled Backup Jobs
+        $field = new Switcher('customconfigoption[permissionBackupJob]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->leftSection->addField($field);
+        //Task History
+        $field = new Switcher('customconfigoption[permissionTaskHistory]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->rightSection->addField($field);
+        //Network
+        $field = new Switcher('customconfigoption[permissionNetwork]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->leftSection->addField($field);
+        //Snapshots
+        $field = new Switcher('customconfigoption[permissionSnapshot]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->rightSection->addField($field);
+        //Firewall
+        $field = new Switcher('customconfigoption[permissionFirewall]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->leftSection->addField($field);
+        //Firewall Options
+        $field = new Switcher('customconfigoption[permissionFirewallOption]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->rightSection->addField($field);
+        //Disks Management
+        $field = new Switcher('customconfigoption[permissionDisk]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->leftSection->addField($field);
+        //sshkeys
+        $field = new Switcher('customconfigoption[permissionSshkeys]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->rightSection->addField($field);
+        //Snapshot Jobs
+        $field = new Switcher('customconfigoption[permissionSnapshotJob]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->leftSection->addField($field);
+        //How Often
+        $field = new Select('customconfigoption[permissionSnapshotJobPeriod][]');
+        $field->setDescription('tip');
+        $field->enableMultiple();
+        $this->rightSection->addField($field);
+        //permissionfirewalOptions
+        $field = new Select("customconfigoption[permissionFirewalOptions][]");
+        $field->enableMultiple();
+        $field->setDescription('description');
+        $this->addField($field);
+    }
+
+    public function addField($field){
+        $total = count($this->leftSection->getFields()) + count($this->rightSection->getFields());
+        if($total % 2 == 0){
+            $this->leftSection->addField($field);
+        }else{
+            $this->rightSection->addField($field);
+        }
+        return $this;
+    }
+}

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

@@ -0,0 +1,98 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections\Qemu;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\BaseField;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Text;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Textarea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+class CloudInitSection extends BoxSection implements AdminArea
+{
+    protected $id = 'cloudInitSection';
+    protected $name = 'cloudInitSection';
+    protected $title = 'cloudInitSection';
+    private $sectionFields=[];
+    /**
+     * @var HalfPageSection
+     */
+    private $leftSection;
+    /**
+     * @var HalfPageSection
+     */
+    private $rightSection;
+
+    public function initContent()
+    {
+        $this->leftSection = new HalfPageSection('leftSection');
+
+        $this->rightSection = new HalfPageSection('rightSection');
+
+        $this->addSection($this->leftSection)
+            ->addSection($this->rightSection);
+        
+        $this->initFields();
+    }
+
+    private function initFields()
+    {
+        //Enable Cloud-Init
+        $field = new Switcher('customconfigoption[cloudInit]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->addSectionField($field);
+        //Service Username
+        $field = new Switcher('customconfigoption[cloudInitServiceUsername]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->addSectionField($field);
+        //Service Password
+        $field = new Switcher('customconfigoption[cloudInitServicePassword]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->addSectionField($field);
+        //Service Nameservers
+        $field = new Switcher('customconfigoption[cloudInitServiceNameservers]');
+        $field->setDescription('tip');
+        $this->addSectionField($field);
+        //DNS Domain
+        $field = new Text('customconfigoption[searchdomain]');
+        $field->setDescription('tip');
+        $this->addSectionField($field);
+        //Default User
+        $field = new Text('customconfigoption[ciuser]');
+        $field->setDescription('tip');
+        $this->addSectionField($field);
+        //cicustom
+        $field = new Textarea('customconfigoption[cicustom]');
+        $field->setDescription('tip');
+        $this->addSectionField($field);
+        //cloudInitScript
+        $field = new Select('customconfigoption[cloudInitScript]');
+        $field->setDescription('tip');
+        $this->addSectionField($field);
+        $this->addFieldsToSections();
+    }
+
+    public function addSectionField(BaseField $field)
+    {
+        $this->sectionFields[] = $field;
+        return $this;
+    }
+
+    private function addFieldsToSections(){
+        foreach($this->sectionFields as $k => $field){
+            if($k % 2 == 0 ){
+                $this->leftSection->addField($field);
+            }else{
+                $this->rightSection->addField($field);
+            }
+        }
+        unset($this->sectionFields);
+    }
+
+}

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

@@ -0,0 +1,52 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections\Qemu;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+class ConfigurableOptionUnitsSection extends BoxSection implements AdminArea
+{
+    protected $id = 'configurableOptionUnitsSection';
+    protected $name = 'configurableOptionUnitsSection';
+    protected $title = 'configurableOptionUnitsSection';
+    /**
+     * @var HalfPageSection
+     */
+    private $leftSection;
+    /**
+     * @var HalfPageSection
+     */
+    private $rightSection;
+
+    public function initContent()
+    {
+        $this->leftSection  = new HalfPageSection('leftSection');
+        $this->rightSection = new HalfPageSection('rightSection');
+        $this->addSection($this->leftSection)
+            ->addSection($this->rightSection);
+        $this->initFields();
+    }
+
+    private function initFields()
+    {
+        //Memory- MB/GB
+        $field = new Select('customconfigoption[memoryUnit]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("mb");
+        $this->leftSection->addField($field);
+        //Disk Size - MB/GB/TB
+        $field = new Select('customconfigoption[diskUnit]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("gb");
+        $this->rightSection->addField($field);
+        //Additional Disks Size -  MB/GB/TB
+        $field = new Select('customconfigoption[additionalDiskUnit]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("gb");
+        $this->leftSection->addField($field);
+    }
+
+}

+ 186 - 0
app/UI/Admin/Product/Sections/Qemu/ConfigurationSection.php

@@ -0,0 +1,186 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections\Qemu;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Text;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Textarea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+class ConfigurationSection extends BoxSection implements AdminArea
+{
+    protected $id = 'configurationSection';
+    protected $name = 'configurationSection';
+    protected $title = 'configurationSection';
+    /**
+     * @var HalfPageSection
+     */
+    private $leftSection;
+    /**
+     * @var HalfPageSection
+     */
+    private $rightSection;
+
+    public function initContent()
+    {
+        $this->leftSection = new HalfPageSection('leftSection');
+
+        $this->rightSection = new HalfPageSection('rightSection');
+
+        $this->addSection($this->leftSection)
+            ->addSection($this->rightSection);
+        $this->initFields();
+    }
+
+    private function initFields()
+    {
+        //OS Type	- default 2.6/3.x
+        $field = new Select('customconfigoption[ostype]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("l26");
+        $this->leftSection->addField($field);
+        //ACPI - switch, default off
+        $field = new Switcher('customconfigoption[acpi]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("off");
+        $this->rightSection->addField($field);
+        //Automatic Restart After Crash
+        $field = new Switcher('customconfigoption[autostart]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //cdrom
+        $field = new Text('customconfigoption[cdrom]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //CD/DVD-ROM Type
+        $field = new Select('customconfigoption[cdromType]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //PCID
+        $field = new Switcher('customconfigoption[pcid]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Numa
+        $field = new Switcher('customconfigoption[numa]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //SPEC-CTRL
+        $field = new Switcher('customconfigoption[spec-ctrl]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Container Notes
+        $field = new Textarea('customconfigoption[description]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("Client: {\$client_name}  (ID: {\$client_id})\nEmail: {\$client_email}\nService ID: {\$service_id}\nHostname: {\$service_domain}\nMain IP: {\$service_dedicated_ip}\n{if \$service_assigned_ips}IP address allocation: {\$service_assigned_ips}\n{/if}\nProduct:  {\$product_name} (ID: {\$product_id})");
+        $this->rightSection->addField($field);
+        //Startup Freeze CPU
+        $field = new Switcher('customconfigoption[freeze]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Hotplug
+        $field = new Select('customconfigoption[hotplug][]');
+        $field->setDescription('tip');
+        $field->enableMultiple();
+        $this->rightSection->addField($field);
+        //Keyboard
+        $field = new Select('customconfigoption[keyboard]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //KVM Hardware Virtualization
+        $field = new Switcher('customconfigoption[kvm]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->rightSection->addField($field);
+        //Start At Boot
+        $field = new Switcher('customconfigoption[onboot]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Add The VM To The Specific Pool
+        $field = new Select('customconfigoption[pool]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Allow Reboot
+        $field = new Switcher('customconfigoption[reboot]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //USB Tablet Device
+        $field = new Switcher('customconfigoption[tablet]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //VGA Type
+        $field = new Select('customconfigoption[vga]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Default KVM Container Prefix
+        $field = new Text('customconfigoption[containerPrefix]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Use Client Name For VPS
+        $field = new Select('customconfigoption[clientNameForContainer]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Search For Templates In All Nodes
+        $field = new Switcher('customconfigoption[osTemplatesInAllNodes]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->leftSection->addField($field);
+        //Clone Mode
+        $field = new Select('customconfigoption[cloneMode]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("full");
+        $this->rightSection->addField($field);
+        //Start after created
+        $field = new Switcher('customconfigoption[start]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->leftSection->addField($field);
+        //Clone On The Same Storage As Source
+        $field = new Switcher('customconfigoption[cloneOnTheSameStorage]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //md-clear
+        $field = new Switcher('customconfigoption[md-clear]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //ssbd
+        $field = new Switcher('customconfigoption[ssbd]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //ibpb
+        $field = new Switcher('customconfigoption[ibpb]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //virt-ssbd
+        $field = new Switcher('customconfigoption[virt-ssbd]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //amd-ssbd
+        $field = new Switcher('customconfigoption[amd-ssbd]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //amd-no-ssb
+        $field = new Switcher('customconfigoption[amd-no-ssb]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //pdpe1gb
+        $field = new Switcher('customconfigoption[pdpe1gb]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //hv-tlbflush
+        $field = new Switcher('customconfigoption[hv-tlbflush]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //hv-evmcs
+        $field = new Switcher('customconfigoption[hv-evmcs]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //aes
+        $field = new Switcher('customconfigoption[aes]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+    }
+
+}

+ 124 - 0
app/UI/Admin/Product/Sections/Qemu/ContainerSection.php

@@ -0,0 +1,124 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections\Qemu;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Text;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+class ContainerSection extends BoxSection implements AdminArea
+{
+    protected $id = 'containerSection';
+    protected $name = 'containerSection';
+    protected $title = 'containerSection';
+    /**
+     * @var HalfPageSection
+     */
+    private $leftSection;
+    /**
+     * @var HalfPageSection
+     */
+    private $rightSection;
+
+    public function initContent()
+    {
+        $this->leftSection  = new HalfPageSection('leftSection');
+        $this->rightSection = new HalfPageSection('rightSection');
+        $this->addSection($this->leftSection)
+            ->addSection($this->rightSection);
+        $this->initFields();
+    }
+
+    private function initFields()
+    {
+        //VM Template
+        $field = new Select('customconfigoption[osTemplate]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //ISO Image
+        $field = new Select('customconfigoption[isoImage]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //cpu
+        $field = new Select('customconfigoption[cpu]');
+        $field->setDescription('tip');
+        $field->setDefaultValue('kvm64');
+        $this->leftSection->addField($field);
+        //Number of CPU Sockets
+        $field = new Text('customconfigoption[sockets]');
+        $field->setDescription('tip');
+        $field->setDefaultValue(1);
+        $this->leftSection->addField($field);
+        //Number of Cores Per Socket
+        $field = new Text('customconfigoption[cores]');
+        $field->setDefaultValue(1);
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //VCPUs
+        $field = new Text('customconfigoption[vcpus]');
+        $field->setDefaultValue(1);
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Limit of CPU
+        $field = new Text('customconfigoption[cpulimit]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //CPU Weight For The VM
+        $field = new Text('customconfigoption[cpuunits]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //RAM For The VM
+        $field = new Text('customconfigoption[memory]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Disk Space
+        $field = new Text('customconfigoption[diskSize]');
+        $field->setDescription('tip');
+        $field->setDefaultValue(32);
+        $this->rightSection->addField($field);
+        //Additional Disks Space
+        $field = new Text('customconfigoption[additionalDiskSize]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Network Rate Limit
+        $field = new Text('customconfigoption[rate]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Minimum Network Rate Limit
+        $field = new Text('customconfigoption[minimumRate]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Amount of IPv4 Addresses
+        $field = new Text('customconfigoption[ipv4]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Amount of IPv6 Addresses
+        $field = new Text('customconfigoption[ipv6]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Backups Size Limit
+        $field = new Text('customconfigoption[backupMaxSize]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Backup Files Limit
+        $field = new Text('customconfigoption[backupMaxFiles]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Bandwidth Limit
+        $field = new Text('customconfigoption[bandwidth]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Snapshots Limit
+        $field = new Text('customconfigoption[snapshotMaxFiles]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Snapshot Jobs
+        $field = new Text('customconfigoption[snapshotJobs]');
+        $field->setDescription('tip');
+        $field->setDefaultValue(1);
+        $this->rightSection->addField($field);
+    }
+
+}

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

@@ -0,0 +1,79 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections\Qemu;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+class DiskSection extends BoxSection implements AdminArea
+{
+    protected $id = 'diskSection';
+    protected $name = 'diskSection';
+    protected $title = 'diskSection';
+    /**
+     * @var HalfPageSection
+     */
+    private $leftSection;
+    /**
+     * @var HalfPageSection
+     */
+    private $rightSection;
+
+    public function initContent()
+    {
+        $this->leftSection  = new HalfPageSection('leftSection');
+        $this->rightSection = new HalfPageSection('rightSection');
+        $this->addSection($this->leftSection)
+            ->addSection($this->rightSection);
+        $this->initFields();
+    }
+
+    private function initFields()
+    {
+        //Storage
+        $field = new Select('customconfigoption[diskStorage]');
+        $field->setDescription('tip');
+        $field->setDefaultValue('local-lvm');
+        $this->leftSection->addField($field);
+        //Disk Type
+        $field = new Select('customconfigoption[diskType]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Disk Format
+        $field = new Select('customconfigoption[diskFormat]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Cache
+        $field = new Select('customconfigoption[diskCache]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //SCSI Controller Model
+        $field = new Select('customconfigoption[scsihw]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Discard
+        $field = new Switcher('customconfigoption[discard]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Skip Replication
+        $field = new Switcher('customconfigoption[replicate]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //IO Thread
+        $field = new Switcher('customconfigoption[ioThread]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Limits
+        $field = new Switcher('customconfigoption[diskSpeed]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //ssd
+        $field = new Switcher('customconfigoption[ssd]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+    }
+
+}

+ 61 - 0
app/UI/Admin/Product/Sections/Qemu/DiskSpeedSection.php

@@ -0,0 +1,61 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections\Qemu;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Text;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+class DiskSpeedSection extends BoxSection implements AdminArea
+{
+    protected $id = 'diskSpeedSection';
+    protected $name = 'diskSpeedSection';
+    protected $title = 'diskSpeedSection';
+    /**
+     * @var HalfPageSection
+     */
+    private $leftSection;
+    /**
+     * @var HalfPageSection
+     */
+    private $rightSection;
+
+    public function initContent()
+    {
+        $this->leftSection  = new HalfPageSection('leftSection');
+        $this->rightSection = new HalfPageSection('rightSection');
+        $this->addSection($this->leftSection)
+            ->addSection($this->rightSection);
+        $this->initFields();
+    }
+
+    private function initFields()
+    {
+        //Read Limit (MB/s)
+        $field = new Text('customconfigoption[mbps_rd]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Write Limit (MB/s)
+        $field = new  Text('customconfigoption[mbps_wr]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Read Limit (ops/s)
+        $field = new  Text('customconfigoption[iops_rd]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Read Max Burst (ops)
+        $field = new  Text('customconfigoption[iops_rd_max]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Write Limit (ops/s)
+        $field = new  Text('customconfigoption[iops_wr]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Write Max Burst (ops)
+        $field = new  Text('customconfigoption[iops_wr_max]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+    }
+
+}

+ 75 - 0
app/UI/Admin/Product/Sections/Qemu/GuestAgentSection.php

@@ -0,0 +1,75 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections\Qemu;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\BaseField;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Text;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Textarea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+class GuestAgentSection extends BoxSection implements AdminArea
+{
+    protected $id = 'guestAgentSection';
+    protected $name = 'guestAgentSection';
+    protected $title = 'guestAgentSection';
+    private $sectionFields=[];
+    /**
+     * @var HalfPageSection
+     */
+    private $leftSection;
+    /**
+     * @var HalfPageSection
+     */
+    private $rightSection;
+
+    public function initContent()
+    {
+        $this->leftSection = new HalfPageSection('leftSection');
+        $this->rightSection = new HalfPageSection('rightSection');
+        $this->addSection($this->leftSection)
+            ->addSection($this->rightSection);
+        $this->initFields();
+        $this->addFieldsToSections();
+    }
+
+    private function initFields()
+    {
+        //Guest Agent [on/off]
+        $field = new Switcher('customconfigoption[agent]');
+        $field->setDescription('tip');
+        $this->addSectionField($field);
+        //Template User
+        $field = new Switcher('customconfigoption[agentTemplateUser]');
+        $field->setDescription('tip');
+        $this->addSectionField($field);
+        //Service Password
+        $field = new Switcher('customconfigoption[agentServicePassword]');
+        $field->setDescription('tip');
+        $this->addSectionField($field);
+        //Configure Network
+        $field = new Switcher('customconfigoption[agentConfigureNetwork]');
+        $field->setDescription('tip');
+        $this->addSectionField($field);
+    }
+
+    public function addSectionField(BaseField $field)
+    {
+        $this->sectionFields[] = $field;
+        return $this;
+    }
+
+    private function addFieldsToSections(){
+        foreach($this->sectionFields as $k => $field){
+            if($k % 2 == 0 ){
+                $this->leftSection->addField($field);
+            }else{
+                $this->rightSection->addField($field);
+            }
+        }
+        unset($this->sectionFields);
+    }
+
+}

+ 88 - 0
app/UI/Admin/Product/Sections/Qemu/NetworkSection.php

@@ -0,0 +1,88 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections\Qemu;
+
+use ModulesGarden\ProxmoxAddon\App\Services\Utility;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Text;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+class NetworkSection extends BoxSection implements AdminArea
+{
+    protected $id = 'networkSection';
+    protected $name = 'networkSection';
+    protected $title = 'networkSection';
+    /**
+     * @var HalfPageSection
+     */
+    private $leftSection;
+    /**
+     * @var HalfPageSection
+     */
+    private $rightSection;
+
+    public function initContent()
+    {
+        $this->leftSection  = new HalfPageSection('leftSection');
+        $this->rightSection = new HalfPageSection('rightSection');
+        $this->addSection($this->leftSection)
+            ->addSection($this->rightSection);
+        $this->initFields();
+    }
+
+    private function initFields()
+    {
+        //Network Model
+        $field = new Select('customconfigoption[networkModel]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Bridge
+        $field = new Select('customconfigoption[bridge]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Disable Additional NIC Creation
+        $field = new Switcher('customconfigoption[oneNetworkDevice]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Private Bridge
+        $field = new Select('customconfigoption[privateBridge]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Private Network Model
+        $field = new Select('customconfigoption[networkPrivateModel]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Firewall
+        $field = new Switcher('customconfigoption[networkFirewall]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //Multiqueue
+        $field = new Text('customconfigoption[queues]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //VLAN TAG Range From
+        $field = new Text('customconfigoption[tagFrom]');
+        $field->setDescription('tip');
+        $this->rightSection->addField($field);
+        //VLAN TAG Range To
+        $field = new Text('customconfigoption[tagTo]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+        //Tag
+        $field = new Select('customconfigoption[tags][]');
+        $field->enableMultiple();
+        $field->setDescription('tip');
+        if(Utility::isIpManagerProxmoxVPSIntegration()){
+            $field->setDescription('ip_manager_integration_tag');
+        }
+        $this->rightSection->addField($field);
+        //privateNetwork
+        $field = new Switcher('customconfigoption[privateNetwork]');
+        $field->setDescription('tip');
+        $this->leftSection->addField($field);
+    }
+
+}

+ 65 - 0
app/UI/Admin/Product/Sections/UserSection.php

@@ -0,0 +1,65 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Admin\Product\Sections;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Text;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Textarea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+class UserSection extends BoxSection implements AdminArea
+{
+    protected $id = 'userSection';
+    protected $name = 'userSection';
+    protected $title = 'userSection';
+    /**
+     * @var HalfPageSection
+     */
+    private $leftSection;
+    /**
+     * @var HalfPageSection
+     */
+    private $rightSection;
+
+    public function initContent()
+    {
+        $this->leftSection  = new HalfPageSection('leftSectionsdf');
+        $this->rightSection = new HalfPageSection('rightSectionsdf');
+        $this->addSection($this->leftSection)
+            ->addSection($this->rightSection);
+        $this->initFields();
+    }
+
+    private function initFields()
+    {
+        //One User Per VPS
+        $field = new Switcher('customconfigoption[oneUserPerVps]');
+        $field->setDescription('tip');
+        $field->setDefaultValue("on");
+        $this->leftSection->addField($field);
+        //Username Prefix
+        $field = new Text('customconfigoption[userPrefix]');
+        $field->setDescription('tip');
+        $field->setDefaultValue('proxmoxVPS_{$serviceid}');
+        $this->rightSection->addField($field);
+        //Realm
+        $field = new Select('customconfigoption[realm]');
+        $field->setDescription('tip');
+        $field->setDefaultValue('pve');
+        $this->leftSection->addField($field);
+        //Comment
+        $field = new Textarea('customconfigoption[userComment]');
+        $field->setDescription('tip');
+        $field->setDefaultValue('User from module ProxmoxVPS for WHMCS');
+        $this->rightSection->addField($field);
+        //Role
+        $field = new Select('customconfigoption[userRole]');
+        $field->setDescription('tip');
+        $field->setDefaultValue('PVEVMUser');
+        $this->leftSection->addField($field);
+    }
+
+}

+ 96 - 0
app/UI/Admin/QemuGuestAgent/Pages/NetworkInterfacesDataTable.php

@@ -0,0 +1,96 @@
+<?php
+/* * ********************************************************************
+*  ProxmoxVPS Product developed. (26.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\ProxmoxVps\App\UI\Admin\QemuGuestAgent\Pages;
+
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\Column;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\DataProviders\Providers\ArrayDataProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\DataTable;
+
+class NetworkInterfacesDataTable extends DataTable implements AdminArea
+{
+    use ProductService;
+    use ApiService;
+
+
+    protected $id = 'networkInterfacesDataTable';
+    protected $title = 'networkInterfacesDataTable';
+    protected $searchable = false;
+    protected $tableLength = "100";
+
+    protected function loadHtml()
+    {
+        $this->addColumn((new Column('name'))->setTitle("interfaceName"))
+            ->addColumn((new Column('hardwareAddress')))
+            ->addColumn((new Column('ipAddresses')));
+    }
+
+
+    public function replaceFieldHardwareAddress($key, $row)
+    {
+
+        if($row[$key]){
+            return $row[$key];
+        }
+        return '-';
+    }
+
+
+    protected function loadData()
+    {
+        $data  = [];
+        $agent = $this->vm()->agent();
+        foreach ($agent->networkGetInterfaces()['result'] as $net)
+        {
+            $ips = [];
+            foreach ($net['ip-addresses'] as $ipAddress)
+            {
+                $ips[] = "{$ipAddress['ip-address']} / {$ipAddress['prefix']}";
+            }
+            $data[] = [
+                "name"            => $net['name'],
+                "hardwareAddress" => $net['hardware-address'],
+                "ipAddresses"     => implode("<br/>", $ips)
+            ];
+        }
+        $dataProv = new ArrayDataProvider();
+        $dataProv->setData($data);
+        $this->setDataProvider($dataProv);
+    }
+
+
+    public function initContent()
+    {
+
+    }
+
+    public function isViewFooter()
+    {
+        return false;
+    }
+
+    public function isViewTopBody()
+    {
+        return false;
+    }
+
+}

+ 25 - 0
app/UI/Admin/Templates/assets/css/integration.css

@@ -0,0 +1,25 @@
+#contentarea > div > h1 {
+    display: block !important;
+}
+
+#contentarea {
+    margin: 10px;
+    padding: 15px;
+    min-height: 600px;
+    background-color: #fff;
+    border: 4px solid #e2e7e9;
+    -moz-border-radius: 10px;
+    -webkit-border-radius: 10px;
+    -o-border-radius: 10px;
+    border-radius: 10px;
+    overflow: auto;
+}
+
+.mg-integration-container .lu-app {
+    height: 0px;
+    visibility: hidden;
+}
+
+#layers .lu-app {
+    background-color: #efefef;
+}

+ 3 - 0
app/UI/Admin/Templates/assets/css/module_styles.css

@@ -0,0 +1,3 @@
+#layers  .lu-widget--toggle .lu-widget__header {
+    cursor: pointer !important;
+}

二進制
app/UI/Admin/Templates/assets/img/buttons/backup.png


二進制
app/UI/Admin/Templates/assets/img/buttons/backupJob.png


二進制
app/UI/Admin/Templates/assets/img/buttons/disk.png


二進制
app/UI/Admin/Templates/assets/img/buttons/firewall.png


二進制
app/UI/Admin/Templates/assets/img/buttons/firewallOption.png


二進制
app/UI/Admin/Templates/assets/img/buttons/graph.png


二進制
app/UI/Admin/Templates/assets/img/buttons/network.png


二進制
app/UI/Admin/Templates/assets/img/buttons/novnc.png


二進制
app/UI/Admin/Templates/assets/img/buttons/rebootButton.png


二進制
app/UI/Admin/Templates/assets/img/buttons/reinstall.png


二進制
app/UI/Admin/Templates/assets/img/buttons/shutdownButton.png


二進制
app/UI/Admin/Templates/assets/img/buttons/snapshot.png


二進制
app/UI/Admin/Templates/assets/img/buttons/spice.png


二進制
app/UI/Admin/Templates/assets/img/buttons/startButton.png


二進制
app/UI/Admin/Templates/assets/img/buttons/stopButton.png


二進制
app/UI/Admin/Templates/assets/img/buttons/taskHistory.png


二進制
app/UI/Admin/Templates/assets/img/buttons/vnc.png


二進制
app/UI/Admin/Templates/assets/img/buttons/xtermjs.png


+ 37 - 0
app/UI/Admin/Templates/assets/js/home/index.js

@@ -0,0 +1,37 @@
+function mgBytesToSize(bytes) {
+    var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
+    if (bytes <= 1) {
+        if (bytes !== 0) {
+            var bytes = Number(bytes).toFixed(1);
+        }
+        return bytes + ' Byte';
+    }
+    var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1000)));
+    return Math.round(bytes / Math.pow(1000, i), 2) + ' ' + sizes[i];
+}
+
+function mgTooltipCpu(tooltipItem, data) {
+    var used = Number(tooltipItem.yLabel).toFixed(2);
+    return used + "%";
+}
+
+function mgTooltipServerLoad(tooltipItem, data) {
+    var used = Number(tooltipItem.yLabel).toFixed(2);
+    return used;
+}
+
+function mgTooltipCallbackForMemory(tooltipItem, data) {
+    return mgBytesToSize(tooltipItem.yLabel) + "/s";
+}
+
+function mgTooltipCallbackForNet(tooltipItem, data) {
+    return mgBytesToSize(tooltipItem.yLabel) + "/s";
+}
+
+function mgTooltipCallbackForDisk(tooltipItem, data) {
+    return mgBytesToSize(tooltipItem.yLabel) + "/s";
+}
+
+function mgLocationReload(data) {
+    window.location.reload();
+}

+ 51 - 0
app/UI/Admin/Templates/assets/js/product/index.js

@@ -0,0 +1,51 @@
+//replace url wrapper
+var mgUrlParser = {
+    oldMgUrlParser: mgUrlParser,
+
+    getCurrentUrl: function () {
+        var url = this.oldMgUrlParser.getCurrentUrl();
+        return url.replace("action=edit", "action=module-settings").replace("&success=true", "");
+    }
+};
+//change virtualization
+$(document).on("click", ".virtualizationChangeConfirmButton", function (event) {
+    event.preventDefault();
+    $("form[name=packagefrm]").submit();
+});
+$(document).on("change", "select[name='customconfigoption[virtualization]']", function () {
+    document.getElementById("virtualizationChangButton").click();
+});
+//default node
+$(document).on("change", "select[name='customconfigoption[defaultNode]']", function () {
+    $("form[name=packagefrm]").submit();
+});
+// Disk Speed
+$(document).on("change", "input[name='customconfigoption[diskSpeed]']", function (e) {
+    var show = $(this).is(":checked");
+    $("input[name='customconfigoption[mbps_rd]']").closest(".lu-widget").toggle(show);
+});
+if ($("input[name='customconfigoption[diskSpeed]']").size()) {
+    $("input[name='customconfigoption[diskSpeed]']").trigger('change');
+}
+//Additional Disk Speed
+$(document).on("change", "input[name='customconfigoption[additionalDiskSpeed]']", function (e) {
+    var show = $(this).is(":checked");
+    $("input[name='customconfigoption[additionalDiskMbps_rd]']").closest(".lu-widget").toggle(show);
+});
+if ($("input[name='customconfigoption[additionalDiskSpeed]']").size()) {
+    $("input[name='customconfigoption[additionalDiskSpeed]']").trigger('change');
+}
+//Storage LVM
+$(document).on("change", "select[name='customconfigoption[diskStorage]']",function(e){
+    var storage = $(this).val();
+    if(storage.match(/lvm/)){
+        $("select[name='customconfigoption[diskFormat]']").val("raw");
+        $("select[name='customconfigoption[diskFormat]'] option").attr("disabled",true);
+        $("select[name='customconfigoption[diskFormat]'] option[value=raw]").attr("disabled",false);
+    }else{
+        $("select[name='customconfigoption[diskFormat]'] option").attr("disabled",false);
+    }
+});
+if ($("input[name='customconfigoption[diskStorage]']").size()) {
+    $("input[name='customconfigoption[diskStorage]']").trigger('change');
+}

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

@@ -0,0 +1,113 @@
+<?php
+/* * ********************************************************************
+*  ProxmoxVPS Product developed. (26.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\ProxmoxVps\App\UI\Admin\User\Pages;
+
+use MGProvision\Proxmox\v2\models\User;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\UserService;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\Column;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\DataProviders\Providers\ArrayDataProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\DataTable;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+
+class UserDataTable extends DataTable implements AdminArea
+{
+
+    use ProductService;
+    use UserService;
+    use ApiService;
+
+    protected $id = 'userDataTable';
+    protected $title = 'userDataTable';
+    protected $searchable = false;
+    protected $tableLength = "100";
+
+    protected function loadHtml()
+    {
+        $this->addColumn((new Column('username')))
+            ->addColumn((new Column('realm')))
+            ->addColumn((new Column('password')))
+            ->addColumn((new Column('enable')))
+            ->addColumn((new Column('expire')))
+            ->addColumn((new Column('name')))
+            ->addColumn((new Column('comment')));
+    }
+
+    public function replaceFieldExpire($key, $row)
+    {
+        if ($row[$key] == 0)
+        {
+            return sl("lang")->tr("Never");
+        }
+        return $row[$key];
+    }
+
+    public function replaceFieldEnable($key, $row)
+    {
+        if ($row[$key])
+        {
+            return '<span class="lu-label lu-label--success lu-label--status">' . sl('lang')->tr("Yes") . '</span>';
+        }
+        return '<span class="lu-label lu-label--danger lu-label--status">' . sl('lang')->tr("No") . '</span>';
+    }
+
+    protected function loadData()
+    {
+        $data = [];
+        if ($this->isUser())
+        {
+            $user        = $this->getUser();
+            $userService = new User("{$user->username}@{$user->realm}");
+            $userService->setApi($this->api());
+            $configuration = $userService->configuration();
+            $data[]        = [
+                'username' => $user->username,
+                'password' => $user->getPassword(),
+                'realm'    => $user->realm,
+                'enable'   => $configuration['enable'],
+                'expire'   => $configuration['expire'],
+                'name'     => $configuration['firstname'] . " " . $configuration['lastname'],
+                'comment'  => $configuration['comment'],
+            ];
+        }
+        $dataProv = new ArrayDataProvider();
+        $dataProv->setData($data);
+        $this->setDataProvider($dataProv);
+    }
+
+
+    public function initContent()
+    {
+
+    }
+
+    public function isViewFooter()
+    {
+        return false;
+    }
+
+    public function isViewTopBody()
+    {
+        return false;
+    }
+
+}

+ 35 - 0
app/UI/Backup/Buttons/CreateButton.php

@@ -0,0 +1,35 @@
+<?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\ProxmoxVps\App\UI\Backup\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Backup\Modals\CreateModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonCreate;
+
+class CreateButton extends ButtonCreate implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('createButton');
+        $this->initLoadModalAction(new CreateModal());
+    }
+
+}

+ 36 - 0
app/UI/Backup/Buttons/DeleteButton.php

@@ -0,0 +1,36 @@
+<?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\ProxmoxVps\App\UI\Backup\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Backup\Modals\DeleteModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+
+class DeleteButton extends ButtonDataTableModalAction implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('deleteButton');
+        $this->switchToRemoveBtn();
+        $this->initLoadModalAction(new DeleteModal());
+    }
+
+}

+ 36 - 0
app/UI/Backup/Buttons/DeleteMassButton.php

@@ -0,0 +1,36 @@
+<?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\ProxmoxVps\App\UI\Backup\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Backup\Modals\DeleteMassModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonMassAction;
+
+class DeleteMassButton extends ButtonMassAction implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('deleteMassButton');
+        $this->switchToRemoveBtn();
+        $this->initLoadModalAction(new DeleteMassModal());
+    }
+
+}

+ 36 - 0
app/UI/Backup/Buttons/RestoreButton.php

@@ -0,0 +1,36 @@
+<?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\ProxmoxVps\App\UI\Backup\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Backup\Modals\RestoreModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+
+class RestoreButton extends ButtonDataTableModalAction implements ClientArea
+{
+    protected $icon = 'lu-zmdi lu-zmdi-time-restore-setting';
+
+    public function initContent()
+    {
+        $this->initIds('restoreButton ');
+        $this->initLoadModalAction(new RestoreModal());
+    }
+
+}

+ 85 - 0
app/UI/Backup/Forms/CreateForm.php

@@ -0,0 +1,85 @@
+<?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\ProxmoxVps\App\UI\Backup\Forms;
+
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\Enum\ConfigurableOption;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Backup\Providers\BackupProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Helpers\AlertTypesConstants;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+
+
+class CreateForm extends BaseForm implements ClientArea
+{
+    use ProductService;
+
+    public function initContent()
+    {
+        $this->initIds('createForm');
+        $this->setFormType('create');
+        $this->setProvider(new BackupProvider());
+        $backupFilesLimit = $this->configuration()->getBackupMaxFiles();
+        if ($this->isWhmcsConfigOption(ConfigurableOption::BACKUPS_FILES) && $this->getWhmcsConfigOption(ConfigurableOption::BACKUPS_FILES) != "-1")
+        {
+            $backupFilesLimit = $this->getWhmcsConfigOption(ConfigurableOption::BACKUPS_FILES);
+        }
+        if($backupFilesLimit == "-1"){
+            $backupFilesLimit = null;
+        }
+        if ($this->configuration()->isBackupRouting() && $backupFilesLimit)
+        {
+            sl("lang")->addReplacementConstant("backupFilesLimit" , $backupFilesLimit);
+            $this->setInternalAlertMessage( sl("lang")->tr('Your routing backup limit is :backupFilesLimit:. When you exceed this limit, the last backup will be replaced with a new one.'));
+            $this->setInternalAlertMessageRaw(true);
+        }
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['create'];
+    }
+
+    private function initFields()
+    {
+        //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
+        $field = new Select('mode');
+        $field->setAvailableValues([
+            "snapshot" => sl("lang")->tr("Snapshot"),
+            "suspend"  => sl("lang")->tr("Suspend"),
+            "stop"     => sl("lang")->tr("Stop")
+        ]);
+        $this->addField($field);
+    }
+}

+ 52 - 0
app/UI/Backup/Forms/DeleteForm.php

@@ -0,0 +1,52 @@
+<?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\ProxmoxVps\App\UI\Backup\Forms;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Backup\Providers\BackupProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Hidden;
+
+
+class DeleteForm extends BaseForm implements ClientArea
+{
+    public function initContent()
+    {
+        $this->initIds('deleteForm');
+        $this->setFormType('delete');
+        $this->setProvider(new BackupProvider());
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['delete'];
+    }
+
+    private function initFields()
+    {
+        $this->setConfirmMessage('conforimDelete');
+        $this->addField(new Hidden("volid"));
+        $this->addField(new Hidden("date"));
+        $this->addField(new Hidden("hour"));
+    }
+
+}

+ 48 - 0
app/UI/Backup/Forms/DeleteMassForm.php

@@ -0,0 +1,48 @@
+<?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\ProxmoxVps\App\UI\Backup\Forms;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Backup\Providers\BackupProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+
+
+class DeleteMassForm extends BaseForm implements ClientArea
+{
+    public function initContent()
+    {
+        $this->initIds('deleteMassForm');
+        $this->setFormType('deleteMass');
+        $this->setProvider(new BackupProvider());
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['deleteMass'];
+    }
+
+    private function initFields()
+    {
+        $this->setConfirmMessage('conforimDeleteMass');
+    }
+
+}

+ 51 - 0
app/UI/Backup/Forms/RestoreForm.php

@@ -0,0 +1,51 @@
+<?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\ProxmoxVps\App\UI\Backup\Forms;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Backup\Providers\BackupProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Hidden;
+
+
+class RestoreForm extends BaseForm implements ClientArea
+{
+    public function initContent()
+    {
+        $this->initIds('restoreForm');
+        $this->setFormType('restore');
+        $this->setProvider(new BackupProvider());
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['restore'];
+    }
+
+    private function initFields()
+    {
+        $this->setConfirmMessage('confirmRestore');
+        $this->addField(new Hidden("volid"));
+        $this->addField(new Hidden("date"));
+        $this->addField(new Hidden("hour"));
+    }
+}

+ 36 - 0
app/UI/Backup/Modals/CreateModal.php

@@ -0,0 +1,36 @@
+<?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\ProxmoxVps\App\UI\Backup\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Backup\Forms\CreateForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\BaseEditModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmSuccess;
+
+class CreateModal extends BaseEditModal implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('createModal');
+        $this->addForm(new CreateForm());
+    }
+
+}

+ 35 - 0
app/UI/Backup/Modals/DeleteMassModal.php

@@ -0,0 +1,35 @@
+<?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\ProxmoxVps\App\UI\Backup\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Backup\Forms\DeleteMassForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmDanger;
+
+class DeleteMassModal extends ModalConfirmDanger implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('deleteMassModal');
+        $this->addForm(new DeleteMassForm());
+    }
+
+}

+ 35 - 0
app/UI/Backup/Modals/DeleteModal.php

@@ -0,0 +1,35 @@
+<?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\ProxmoxVps\App\UI\Backup\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Backup\Forms\DeleteForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmDanger;
+
+class DeleteModal extends ModalConfirmDanger implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('deleteModal');
+        $this->addForm(new DeleteForm());
+    }
+
+}

+ 35 - 0
app/UI/Backup/Modals/RestoreModal.php

@@ -0,0 +1,35 @@
+<?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\ProxmoxVps\App\UI\Backup\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Backup\Forms\RestoreForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmSuccess;
+
+class RestoreModal extends ModalConfirmSuccess implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('restoreModal');
+        $this->addForm(new RestoreForm());
+    }
+
+}

+ 87 - 0
app/UI/Backup/Pages/BackupDataTable.php

@@ -0,0 +1,87 @@
+<?php
+/* * ********************************************************************
+*  ProxmoxVPS Product developed. (26.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\ProxmoxVps\App\UI\Backup\Pages;
+
+use MGProvision\Proxmox\v2\repository\FileRepository;
+use ModulesGarden\ProxmoxAddon\App\Libs\Format;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Backup\Buttons\CreateButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Backup\Buttons\DeleteButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Backup\Buttons\DeleteMassButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Backup\Buttons\RestoreButton;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\Column;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\DataProviders\Providers\ArrayDataProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\DataTable;
+
+class BackupDataTable extends DataTable implements ClientArea
+{
+    use ProductService, ApiService;
+
+    protected $id = 'backupDataTable';
+    protected $title = 'backupDataTable';
+
+    public function initContent()
+    {
+        //Create
+        $createButton = new CreateButton();
+        if (!$this->configuration()->isPermissionBackup() || !$this->resourceGuard()->hasBackupLimit())
+        {
+            $createButton->addClass("hidden");
+        }
+        $this->addButton($createButton);
+        //Restore
+        $this->addActionButton(new RestoreButton());
+        //Delete
+        $this->addActionButton(new DeleteButton());
+        //Delete Mass
+        $this->addMassActionButton(new DeleteMassButton());
+    }
+
+    protected function loadHtml()
+    {
+        $this->addColumn((new Column('date'))->setSearchable(true, "date")->setOrderable('DESC'))
+            ->addColumn((new Column('format'))->setSearchable(true)->setOrderable())
+            ->addColumn((new Column('size'))->setSearchable(true)->setOrderable());
+    }
+
+    protected function loadData()
+    {
+        $backupRepository = new FileRepository();
+        $backupRepository->setApi($this->api());
+        $backupRepository->findBackup($this->vm())
+            ->findByStorages([$this->configuration()->getBackupStorage()]);
+        $data = [];
+        foreach ($backupRepository->fetch() as $file)
+        {
+            $row         = $file->getAttributes();
+            $row['size'] = Format::convertBytes($row['size']);
+            $row['date'] = $row['date'] . " " . $row['hour'];
+            $data[]      = array_merge(['id' => base64_encode(json_encode($row))], $row);
+        }
+        $dataProv = new ArrayDataProvider();
+        $dataProv->setDefaultSorting("date", 'DESC');
+        $dataProv->setData($data);
+        $this->setDataProvider($dataProv);
+    }
+
+
+}

+ 115 - 0
app/UI/Backup/Providers/BackupProvider.php

@@ -0,0 +1,115 @@
+<?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\ProxmoxVps\App\UI\Backup\Providers;
+
+use MGProvision\Proxmox\v2\models\File;
+use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\RestoreVm;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\ResponseTemplates\HtmlDataJsonResponse;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\DataProviders\BaseDataProvider;
+use function ModulesGarden\ProxmoxAddon\Core\Helper\queue;
+use ModulesGarden\Servers\ProxmoxVps\App\Enum\ConfigurableOption;
+
+class BackupProvider extends BaseDataProvider implements ClientArea
+{
+    use ProductService;
+    use ApiService;
+
+    public function read()
+    {
+        if ($this->actionElementId)
+        {
+            $this->data = json_decode(base64_decode($this->actionElementId), true);
+        }
+    }
+
+    public function create()
+    {
+        $this->acl()->backup();
+        $this->resourceGuard()->backupLimit();
+        $storage  = $this->configuration()->getBackupStorage();
+        $routing  = $this->configuration()->isBackupRouting() ? 1 : 0;
+        $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"){
+            $maxFiles       = null;
+        }
+        $this->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('pmToggleButton');
+    }
+
+    public function restore()
+    {
+        queue(RestoreVm::class, ['volid' => $this->formData['volid']], null, 'hosting', $this->getWhmcsParamByKey('serviceid'));
+        return (new HtmlDataJsonResponse())
+            ->setStatusSuccess()
+            ->setMessageAndTranslate('The virtual machine restore is in progress');
+    }
+
+    public function update()
+    {
+
+    }
+
+    public function delete()
+    {
+        $this->acl()->backup();
+        $storage    = $this->configuration()->getBackupStorage();
+        $volid      = $this->formData['volid'];
+        $backupFile = new File();
+        $backupFile->setApi($this->api());
+        $backupFile->setPath("/nodes/{$this->vm()->getNode()}/storage/{$storage}/content/{$volid}");
+        $backupFile->delete();
+
+        return (new HtmlDataJsonResponse())
+            ->setStatusSuccess()
+            ->setMessageAndTranslate('The backup has been deleted successfully')
+            ->addData('createButtonStatus', $this->configuration()->isPermissionBackup() && $this->resourceGuard()->hasBackupLimit())
+            ->setCallBackFunction('pmToggleButton');
+    }
+
+    public function deleteMass()
+    {
+        $this->acl()->backup();
+        $storage    = $this->configuration()->getBackupStorage();
+        $backupFile = new File();
+        $backupFile->setApi($this->api());
+        foreach ($this->request->get('massActions') as $id)
+        {
+            $data  = json_decode(base64_decode($id), true);
+            $volid = $data['volid'];
+            $backupFile->setPath("/nodes/{$this->vm()->getNode()}/storage/{$storage}/content/{$volid}");
+            $backupFile->delete();
+        }
+        return (new HtmlDataJsonResponse())
+            ->setStatusSuccess()
+            ->setMessageAndTranslate('The backups have been deleted successfully')
+            ->addData('createButtonStatus', $this->configuration()->isPermissionBackup() && $this->resourceGuard()->hasBackupLimit())
+            ->setCallBackFunction('pmToggleButton');
+    }
+
+}

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

@@ -0,0 +1,35 @@
+<?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\ProxmoxVps\App\UI\BackupJob\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\BackupJob\Modals\CreateModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonCreate;
+
+class CreateButton extends ButtonCreate implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('createButton');
+        $this->initLoadModalAction(new CreateModal());
+    }
+
+}

+ 36 - 0
app/UI/BackupJob/Buttons/DeleteButton.php

@@ -0,0 +1,36 @@
+<?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\ProxmoxVps\App\UI\BackupJob\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\BackupJob\Modals\DeleteModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+
+class DeleteButton extends ButtonDataTableModalAction implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('deleteButton');
+        $this->switchToRemoveBtn();
+        $this->initLoadModalAction(new DeleteModal());
+    }
+
+}

+ 81 - 0
app/UI/BackupJob/Buttons/MailtoSwitchButton.php

@@ -0,0 +1,81 @@
+<?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\ProxmoxVps\App\UI\BackupJob\Buttons;
+
+use MGProvision\Proxmox\v2\models\BackupSchedule;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\ResponseTemplates\DataJsonResponse;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonSwitchAjax;
+use ModulesGarden\Servers\ProxmoxVps\App\Enum\ConfigurableOption;
+
+class MailtoSwitchButton extends ButtonSwitchAjax implements ClientArea
+{
+    use ProductService;
+    use ApiService;
+    protected $switchColumn = 'mailto';
+    protected $refreshActionIds = 'dackupJobDataTable';
+
+    public function returnAjaxData()
+    {
+        try
+        {
+            $data           = json_decode(base64_decode($this->getRequestValue('actionElementId')), true);
+            $storage        = $this->configuration()->getBackupStorage() ? $this->configuration()->getBackupStorage() : "local";
+            $routing        = 1;
+            $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"){
+                $maxFiles       = null;
+            }
+            $backupSchedule = new BackupSchedule();
+            $backupSchedule->setApi($this->api());
+            $backupSchedule->setAttributes([
+                "id"        => $data['backupScheduleId'],
+                "vmid"      => $this->vm()->getVmid(),
+                "storage"   => $storage,
+                "remove"    => $routing,
+                "maxfiles"  => $maxFiles,
+                "starttime" => $data['starttime'],
+                "dow"       => $data['dow'],
+                "mode"      => $data['mode'],
+                "compress"  => $data['compress'],
+                "mailto"    => $this->getRequestValue("value") == "on" ? $this->getWhmcsParamByKey('clientsdetails')['email'] : null,
+            ]);
+            $backupSchedule->update();
+        }
+        catch (\Exception $exc)
+        {
+            return (new DataJsonResponse())->setStatusError()->setMessage($exc->getMessage())->setCallBackFunction($this->callBackFunction)->addRefreshTargetId($this->refreshActionIds);
+        }
+        return (new DataJsonResponse())->setMessageAndTranslate('changesSaved')
+                                       ->setCallBackFunction('pmOnBackupJobChanged');
+    }
+
+    /**
+     *
+     */
+    protected function afterInitContent()
+    {
+        //Why?
+    }
+}

+ 35 - 0
app/UI/BackupJob/Buttons/UpdateButton.php

@@ -0,0 +1,35 @@
+<?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\ProxmoxVps\App\UI\BackupJob\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\BackupJob\Modals\UpdateModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+
+class UpdateButton extends ButtonDataTableModalAction implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('updateButton');
+        $this->initLoadModalAction(new UpdateModal());
+    }
+
+}

+ 116 - 0
app/UI/BackupJob/Forms/CreateForm.php

@@ -0,0 +1,116 @@
+<?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\ProxmoxVps\App\UI\BackupJob\Forms;
+
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\Enum\ConfigurableOption;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\BackupJob\Providers\BackupJobProvider;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\BackupJob\Providers\FirewallOptionProvider;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Validators\StartTimeValidator;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Helpers\AlertTypesConstants;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Text;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+
+
+class CreateForm extends BaseForm implements ClientArea
+{
+    use ProductService;
+
+    public function initContent()
+    {
+        $this->initIds('createForm');
+        $this->setFormType('create');
+        $this->setProvider(new BackupJobProvider());
+        $backupFilesLimit = $this->configuration()->getBackupMaxFiles();
+        if ($this->isWhmcsConfigOption(ConfigurableOption::BACKUPS_FILES) &&
+            $this->getWhmcsConfigOption(ConfigurableOption::BACKUPS_FILES) != "-1")
+        {
+            $backupFilesLimit = $this->getWhmcsConfigOption(ConfigurableOption::BACKUPS_FILES);
+        }
+        if($backupFilesLimit == "-1"){
+            $backupFilesLimit = null;
+        }
+        if ($this->configuration()->isBackupRouting() && $backupFilesLimit)
+        {
+            sl("lang")->addReplacementConstant("backupFilesLimit" , $backupFilesLimit);
+            $this->setInternalAlertMessage( sl("lang")->tr('Your routing backup limit is :backupFilesLimit:. When you exceed this limit, the last backup will be replaced with a new one.'));
+            $this->setInternalAlertMessageRaw(true);
+            $this->setInternalAlertMessageType(AlertTypesConstants::INFO);
+        }
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['create'];
+    }
+
+    private function initFields()
+    {
+        //starttime
+        $field = new Text('starttime');
+        $field->setPlaceholder("00:00");
+        $field->addValidator(new StartTimeValidator());
+        $this->addField($field);
+        //dow
+        $field = new Select('dow');
+        $field->enableMultiple();
+        $field->setAvailableValues([
+            "mon" => sl("lang")->tr("mon"),
+            "tue" => sl("lang")->tr("tue"),
+            "wed" => sl("lang")->tr("wed"),
+            "thu" => sl("lang")->tr("thu"),
+            "fri" => sl("lang")->tr("fri"),
+            "sat" => sl("lang")->tr("sat"),
+            "sun" => sl("lang")->tr("sun")
+        ]);
+        $field->notEmpty();
+        $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")->abtr("ZSTD (fast and good)")
+        ]);
+        $field->setDefaultValue('zstd');
+        $field->notEmpty();
+        $this->addField($field);
+        //mode
+        $field = new Select('mode');
+        $field->setAvailableValues([
+            "snapshot" => sl("lang")->tr("snapshot"),
+            "suspend"  => sl("lang")->tr("suspend"),
+            "stop"     => sl("lang")->tr("stop")
+        ]);
+        $field->notEmpty();
+        $this->addField($field);
+        //mailto
+        $field = new Switcher("mailto");
+        $this->addField($field);
+
+    }
+}

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

@@ -0,0 +1,51 @@
+<?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\ProxmoxVps\App\UI\BackupJob\Forms;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\BackupJob\Providers\BackupJobProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Hidden;
+
+
+class DeleteForm extends BaseForm implements ClientArea
+{
+    public function initContent()
+    {
+        $this->initIds('deleteForm');
+        $this->setFormType('delete');
+        $this->setProvider(new BackupJobProvider());
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['delete'];
+    }
+
+    private function initFields()
+    {
+        $this->setConfirmMessage('conforimDelete');
+        $this->addField(new Hidden("backupScheduleId"));
+        $this->addField(new Hidden("displayId"));
+    }
+
+}

+ 124 - 0
app/UI/BackupJob/Forms/UpdateForm.php

@@ -0,0 +1,124 @@
+<?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\ProxmoxVps\App\UI\BackupJob\Forms;
+
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\Enum\ConfigurableOption;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\BackupJob\Providers\BackupJobProvider;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Validators\StartTimeValidator;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Helpers\AlertTypesConstants;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Hidden;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Text;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+
+
+class UpdateForm extends BaseForm implements ClientArea
+{
+    use ProductService;
+
+    public function initContent()
+    {
+        $this->initIds('updateForm');
+        $this->setFormType('update');
+        $this->setProvider(new BackupJobProvider());
+        $backupFilesLimit = $this->configuration()->getBackupMaxFiles();
+        if ($this->isWhmcsConfigOption(ConfigurableOption::BACKUPS_FILES) &&
+            $this->getWhmcsConfigOption(ConfigurableOption::BACKUPS_FILES) != "-1")
+        {
+            $backupFilesLimit = $this->getWhmcsConfigOption(ConfigurableOption::BACKUPS_FILES);
+        }else if($this->getWhmcsConfigOption(ConfigurableOption::BACKUPS_FILES) == "-1"){
+            $backupFilesLimit = null;
+        }
+        if ($this->configuration()->isBackupRouting() && $backupFilesLimit)
+        {
+            sl("lang")->addReplacementConstant("backupFilesLimit" , $backupFilesLimit);
+            $this->setInternalAlertMessage( sl("lang")->tr('Your routing backup limit is :backupFilesLimit:. When you exceed this limit, the last backup will be replaced with a new one.'));
+            $this->setInternalAlertMessageRaw(true);
+            $this->setInternalAlertMessageType(AlertTypesConstants::INFO);
+        }
+        else
+        {
+            $this->setInternalAlertMessage('confirmUpdate');
+            $this->setInternalAlertMessageType(AlertTypesConstants::INFO);
+        }
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['update'];
+    }
+
+    private function initFields()
+    {
+        //backupScheduleId
+        $this->addField(new Hidden("backupScheduleId"));
+        //displayId
+        $this->addField(new Hidden("displayId"));
+        //starttime
+        $field = new Text('starttime');
+        $field->setPlaceholder("00:00");
+        $field->addValidator(new StartTimeValidator());
+        $this->addField($field);
+        //dow
+        $field = new Select('dow');
+        $field->enableMultiple();
+        $field->setAvailableValues([
+            "mon" => sl("lang")->tr("mon"),
+            "tue" => sl("lang")->tr("tue"),
+            "wed" => sl("lang")->tr("wed"),
+            "thu" => sl("lang")->tr("thu"),
+            "fri" => sl("lang")->tr("fri"),
+            "sat" => sl("lang")->tr("sat"),
+            "sun" => sl("lang")->tr("sun")
+        ]);
+        $field->notEmpty();
+        $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")->abtr("ZSTD (fast and good)")
+        ]);
+        $field->setDefaultValue('zstd');
+        $field->notEmpty();
+        $this->addField($field);
+        //mode
+        $field = new Select('mode');
+        $field->setAvailableValues([
+            "snapshot" => sl("lang")->tr("snapshot"),
+            "suspend"  => sl("lang")->tr("suspend"),
+            "stop"     => sl("lang")->tr("stop")
+        ]);
+        $field->notEmpty();
+        $this->addField($field);
+        //mailto
+        $field = new Switcher("mailto");
+        $this->addField($field);
+
+    }
+}

+ 36 - 0
app/UI/BackupJob/Modals/CreateModal.php

@@ -0,0 +1,36 @@
+<?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\ProxmoxVps\App\UI\BackupJob\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\BackupJob\Forms\CreateForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\BaseEditModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmSuccess;
+
+class CreateModal extends BaseEditModal implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('createModal');
+        $this->addForm(new CreateForm());
+    }
+
+}

+ 35 - 0
app/UI/BackupJob/Modals/DeleteModal.php

@@ -0,0 +1,35 @@
+<?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\ProxmoxVps\App\UI\BackupJob\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\BackupJob\Forms\DeleteForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmDanger;
+
+class DeleteModal extends ModalConfirmDanger implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('deleteModal');
+        $this->addForm(new DeleteForm());
+    }
+
+}

+ 36 - 0
app/UI/BackupJob/Modals/UpdateModal.php

@@ -0,0 +1,36 @@
+<?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\ProxmoxVps\App\UI\BackupJob\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\BackupJob\Forms\UpdateForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\BaseEditModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmSuccess;
+
+class UpdateModal extends BaseEditModal implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('updateModal');
+        $this->addForm(new UpdateForm());
+    }
+
+}

+ 122 - 0
app/UI/BackupJob/Pages/BackupJobDataTable.php

@@ -0,0 +1,122 @@
+<?php
+/* * ********************************************************************
+*  ProxmoxVPS Product developed. (26.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\ProxmoxVps\App\UI\BackupJob\Pages;
+
+use MGProvision\Proxmox\v2\repository\BackupScheduleRepository;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\BackupJob\Buttons\CreateButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\BackupJob\Buttons\DeleteButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\BackupJob\Buttons\DeleteMassButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\BackupJob\Buttons\MailtoSwitchButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\BackupJob\Buttons\RestoreButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\BackupJob\Buttons\UpdateButton;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\Column;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\DataProviders\Providers\ArrayDataProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\DataTable;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+
+class BackupJobDataTable extends DataTable implements ClientArea
+{
+    use ProductService, ApiService;
+
+    protected $id = 'dackupJobDataTable';
+    protected $title = 'dackupJobDataTable';
+
+    public function initContent()
+    {
+        //Create
+        $createButton = new CreateButton();
+        if (!$this->resourceGuard()->hasBackupJobLimit())
+        {
+            $createButton->addClass("hidden");
+        }
+        $this->addButton($createButton );
+        //Update
+        $this->addActionButton(new UpdateButton());
+        //Delete
+        $this->addActionButton(new DeleteButton());
+    }
+
+    protected function loadHtml()
+    {
+        $this->addColumn((new Column('displayId'))->setSearchable(true, "int")->setOrderable('DESC'))
+            ->addColumn((new Column('starttime'))->setSearchable(true, "date")->setOrderable())
+            ->addColumn((new Column('dow'))->setSearchable(true)->setOrderable())
+            ->addColumn((new Column('compress'))->setSearchable(true)->setOrderable())
+            ->addColumn((new Column('mode'))->setSearchable(true)->setOrderable())
+            ->addColumn((new Column('mailto')));
+    }
+
+
+    public function replaceFieldDow($key, $row)
+    {
+        $down = explode(",", $row['dow']);
+        $days = [];
+        foreach ($down as $day)
+        {
+            $days[] = sl('lang')->tr($day);
+        }
+        return implode(", ", $days);
+    }
+
+    public function replaceFieldCompress($key, $row)
+    {
+        return sl('lang')->tr($row['compress']);
+    }
+
+    public function replaceFieldMode($key, $row)
+    {
+        return sl('lang')->tr($row['mode']);
+    }
+
+    public function customColumnHtmlMailto()
+    {
+        return (new MailtoSwitchButton())->getHtml();
+    }
+
+    public function replaceFieldMailto($key, $row)
+    {
+        return $row['mailto'] ? "on" : "off";
+
+    }
+
+    protected function loadData()
+    {
+        $scheduleRepository = new BackupScheduleRepository();
+        $scheduleRepository->setApi($this->api());
+        $scheduleRepository->findByVm($this->vm());
+        $data = [];
+        foreach ($scheduleRepository->fetch() as $job)
+        {
+            $row                     = $job->getAttributes();
+            $row['backupScheduleId'] = $row['id'];
+            unset($row['id'], $row['days']);
+            $data[] = array_merge(['id' => base64_encode(json_encode($row))], $row);
+        }
+        $dataProv = new ArrayDataProvider();
+        $dataProv->setDefaultSorting("displayId", 'DESC');
+        $dataProv->setData($data);
+        $this->setDataProvider($dataProv);
+    }
+
+
+}

+ 130 - 0
app/UI/BackupJob/Providers/BackupJobProvider.php

@@ -0,0 +1,130 @@
+<?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\ProxmoxVps\App\UI\BackupJob\Providers;
+
+use MGProvision\Proxmox\v2\models\BackupSchedule;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\ResponseTemplates\HtmlDataJsonResponse;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\DataProviders\BaseDataProvider;
+use ModulesGarden\Servers\ProxmoxVps\App\Enum\ConfigurableOption;
+
+class BackupJobProvider extends BaseDataProvider implements ClientArea
+{
+    use ApiService;
+    use ProductService;
+
+    public function read()
+    {
+        if ($this->actionElementId)
+        {
+            $this->data = json_decode(base64_decode($this->actionElementId), true);
+            //down
+            $dow               = $this->data['dow'];
+            $this->data['dow'] = explode(",", $dow);
+            //mailto
+            $mailto               = $this->data['mailto'];
+            $this->data['mailto'] = $mailto ? "on" : "off";
+        }
+    }
+
+    public function create()
+    {
+        $this->acl()->backupJob();
+        $this->resourceGuard()->backupJobLimit();
+        $storage        = $this->configuration()->getBackupStorage();
+        $routing        = $this->configuration()->isBackupRouting() ? 1 : 0;
+        $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"){
+            $maxFiles       = null;
+        }
+        $backupSchedule = new BackupSchedule();
+        $backupSchedule->setApi($this->api());
+        $backupSchedule->setAttributes([
+            "vmid"      => $this->vm()->getVmid(),
+            "storage"   => $storage,
+            "remove"    => $routing,
+            "maxfiles"  => $maxFiles,
+            "starttime" => $this->formData['starttime'],
+            "dow"       => implode(",", $this->formData['dow']),
+            "mode"      => $this->formData['mode'],
+            "compress"  => $this->formData['compress'],
+            "mailto"    => $this->formData['mailto'] == "on" ? $this->getWhmcsParamByKey('clientsdetails')['email'] : null,
+        ]);
+        $backupSchedule->create();
+        return (new HtmlDataJsonResponse())
+            ->setStatusSuccess()
+            ->setMessageAndTranslate('The backup job has been created successfully')
+            ->setRefreshTargetIds(['dackupJobDataTable'])
+            ->addData('createButtonStatus', $this->resourceGuard()->hasBackupJobLimit())
+            ->setCallBackFunction('toggleBackupButton');
+    }
+
+    public function update()
+    {
+        $this->acl()->backupJob();
+        $storage        = $this->configuration()->getBackupStorage();
+        $routing        = $this->configuration()->isBackupRouting() ? 1 : 0;
+        $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"){
+            $maxFiles       = null;
+        }
+        $backupSchedule = new BackupSchedule();
+        $backupSchedule->setApi($this->api());
+        $backupSchedule->setAttributes([
+            "id"        => $this->formData['backupScheduleId'],
+            "vmid"      => $this->vm()->getVmid(),
+            "storage"   => $storage,
+            "remove"    => $routing,
+            "maxfiles"  => $maxFiles,
+            "starttime" => $this->formData['starttime'],
+            "dow"       => implode(",", $this->formData['dow']),
+            "mode"      => $this->formData['mode'],
+            "compress"  => $this->formData['compress'],
+            "mailto"    => $this->formData['mailto'] == "on" ? $this->getWhmcsParamByKey('clientsdetails')['email'] : null,
+        ]);
+        $backupSchedule->update();
+        return (new HtmlDataJsonResponse())
+            ->setStatusSuccess()
+            ->setMessageAndTranslate('The backup job has been updated successfully');
+    }
+
+    public function delete()
+    {
+        $this->acl()->backupJob();
+        $backupSchedule = new BackupSchedule();
+        $backupSchedule->setApi($this->api());
+        $backupSchedule->setId($this->formData['backupScheduleId']);
+        $backupSchedule->delete();
+        return (new HtmlDataJsonResponse())
+            ->setStatusSuccess()
+            ->setMessageAndTranslate('The backup job has been deleted successfully')
+            ->setRefreshTargetIds(['dackupJobDataTable'])
+            ->addData('createButtonStatus', 1)
+            ->setCallBackFunction('toggleBackupButton');
+    }
+
+
+}

+ 21 - 0
app/UI/Client/Templates/assets/css/integration.css

@@ -0,0 +1,21 @@
+#contentarea > div > h1 {
+    display: block !important;
+}
+
+#contentarea {
+    margin: 10px;
+    padding: 15px;
+    min-height: 600px;
+    background-color: #fff;
+    border: 4px solid #e2e7e9;
+    -moz-border-radius: 10px;
+    -webkit-border-radius: 10px;
+    -o-border-radius: 10px;
+    border-radius: 10px;
+    overflow: auto;
+}
+
+.mg-integration-container .lu-app {
+    height: 0px;
+    visibility: hidden;
+}

+ 13 - 0
app/UI/Client/Templates/assets/css/module_styles.css

@@ -0,0 +1,13 @@
+#layers .lu-app .progress-bar[aria-valuenow="0"] {
+    min-width: 30px;
+    color: #777;
+    background-color: transparent;
+    background-image: none;
+    box-shadow: none;
+}
+
+.pm-resource-usege {
+    clear: both;
+    width: 40% !important;
+    margin-bottom: 2px !important;
+}

二進制
app/UI/Client/Templates/assets/img/buttons/backup.png


二進制
app/UI/Client/Templates/assets/img/buttons/backupJob.png


二進制
app/UI/Client/Templates/assets/img/buttons/disk.png


二進制
app/UI/Client/Templates/assets/img/buttons/firewall.png


二進制
app/UI/Client/Templates/assets/img/buttons/firewallOption.png


二進制
app/UI/Client/Templates/assets/img/buttons/graph.png


二進制
app/UI/Client/Templates/assets/img/buttons/network.png


二進制
app/UI/Client/Templates/assets/img/buttons/novnc.png


二進制
app/UI/Client/Templates/assets/img/buttons/rebootButton.png


二進制
app/UI/Client/Templates/assets/img/buttons/reinstall.png


二進制
app/UI/Client/Templates/assets/img/buttons/shutdownButton.png


二進制
app/UI/Client/Templates/assets/img/buttons/snapshot.png


二進制
app/UI/Client/Templates/assets/img/buttons/spice.png


二進制
app/UI/Client/Templates/assets/img/buttons/startButton.png


二進制
app/UI/Client/Templates/assets/img/buttons/stopButton.png


二進制
app/UI/Client/Templates/assets/img/buttons/taskHistory.png


二進制
app/UI/Client/Templates/assets/img/buttons/vnc.png


二進制
app/UI/Client/Templates/assets/img/buttons/xtermjs.png


+ 17 - 0
app/UI/Client/Templates/assets/js/backup/index.js

@@ -0,0 +1,17 @@
+
+function mgLocationReload(data) {
+    window.location.reload();
+}
+
+
+function pmToggleButton(data) {
+    let button = $("#backupDataTable .lu-top__toolbar a");
+    if(data.htmlData.createButtonStatus)
+    {
+        button.removeClass('hidden');
+    }
+    else
+    {
+        button.addClass('hidden');
+    }
+}

+ 18 - 0
app/UI/Client/Templates/assets/js/backupJob/index.js

@@ -0,0 +1,18 @@
+
+function toggleBackupButton(data) {
+    let button = $("#dackupJobDataTable .lu-top__toolbar a");
+    if(data.htmlData.createButtonStatus)
+    {
+        button.removeClass('hidden');
+    }
+    else
+    {
+        button.addClass('hidden');
+    }
+}
+
+
+function pmOnBackupJobChanged(data) {
+    mgPageControler.vueLoader.refreshingState = ['dackupJobDataTable'];
+    mgPageControler.vueLoader.runRefreshActions();
+}

+ 12 - 0
app/UI/Client/Templates/assets/js/disk/index.js

@@ -0,0 +1,12 @@
+
+function pmToggleButton(data) {
+    let button = $(".pmCreateButton");
+    if(data.htmlData.createButtonStatus)
+    {
+        button.removeClass('hidden');
+    }
+    else
+    {
+        button.addClass('hidden');
+    }
+}

+ 44 - 0
app/UI/Client/Templates/assets/js/firewall/index.js

@@ -0,0 +1,44 @@
+
+function pmToggleButton(data) {
+    let button = $(".pmCreateButton");
+    if(data.htmlData.createButtonStatus)
+    {
+        button.removeClass('hidden');
+        $(".lu-has-dropdown").removeClass('hidden');
+    }
+    else
+    {
+        button.addClass('hidden');
+        $(".lu-has-dropdown").addClass('hidden');
+    }
+}
+
+function pmToggleDropDownButtons(data) {
+
+    if($(".pmCreateButton").hasClass('hidden')){
+        $(".lu-has-dropdown").addClass('hidden');
+    }else{
+        $(".lu-has-dropdown").removeClass('hidden');
+    }
+}
+
+$(".mg-wrapper").on("change", "select[name='macro']", function () {
+    var disable = $(this).val()!='0';
+    if(disable){
+        $("input[name='sport']").closest(".lu-form-group").addClass("disabled");
+        $("input[name='dport']").closest(".lu-form-group").addClass("disabled");
+        $("select[name='proto']").closest(".lu-form-group").addClass("disabled");
+    }else{
+        $("input[name='sport']").closest(".lu-form-group").removeClass("disabled");
+        $("input[name='dport']").closest(".lu-form-group").removeClass("disabled");
+        $("select[name='proto']").closest(".lu-form-group").removeClass("disabled");
+    }
+});
+
+mgEventHandler.on('ModalLoaded', 'updateButton', function(id, params){
+    if(id != 'updateButton'){
+        return;
+    }
+     $(".mg-wrapper select[name='macro']").trigger('change');
+
+}, 1000);

+ 33 - 0
app/UI/Client/Templates/assets/js/graph/index.js

@@ -0,0 +1,33 @@
+function mgBytesToSize(bytes) {
+    var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
+    if (bytes <= 1) {
+        if (bytes !== 0) {
+            var bytes = Number(bytes).toFixed(1);
+        }
+        return bytes + ' Byte';
+    }
+    var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1000)));
+    return Math.round(bytes / Math.pow(1000, i), 2) + ' ' + sizes[i];
+}
+
+function mgTooltipCpu(tooltipItem, data) {
+    var used = Number(tooltipItem.yLabel).toFixed(2);
+    return used + "%";
+}
+
+function mgTooltipServerLoad(tooltipItem, data) {
+    var used = Number(tooltipItem.yLabel).toFixed(2);
+    return used;
+}
+
+function mgTooltipCallbackForMemory(tooltipItem, data) {
+    return mgBytesToSize(tooltipItem.yLabel) + "/s";
+}
+
+function mgTooltipCallbackForNet(tooltipItem, data) {
+    return mgBytesToSize(tooltipItem.yLabel) + "/s";
+}
+
+function mgTooltipCallbackForDisk(tooltipItem, data) {
+    return mgBytesToSize(tooltipItem.yLabel) + "/s";
+}

+ 12 - 0
app/UI/Client/Templates/assets/js/home/index.js

@@ -0,0 +1,12 @@
+
+$(document).on("click", ".sshPrivateKeyDownloadButton", function () {
+
+    $('#serviceInformationDataTable').find('table tr:last').hide();
+});
+
+function mgRedirect(data) {
+    if(data.rawData.redirectUrl)
+    {
+        window.location.href = data.rawData.redirectUrl;
+    }
+}

+ 12 - 0
app/UI/Client/Templates/assets/js/mountPoint/index.js

@@ -0,0 +1,12 @@
+
+function pmToggleButton(data) {
+    let button = $(".pmCreateButton");
+    if(data.htmlData.createButtonStatus)
+    {
+        button.removeClass('hidden');
+    }
+    else
+    {
+        button.addClass('hidden');
+    }
+}

+ 13 - 0
app/UI/Client/Templates/assets/js/network/index.js

@@ -0,0 +1,13 @@
+
+
+function pmToggleButton(data) {
+    let button = $(".pmCreateButton");
+    if(data.htmlData.createButtonStatus)
+    {
+        button.removeClass('hidden');
+    }
+    else
+    {
+        button.addClass('hidden');
+    }
+}

+ 10 - 0
app/UI/Client/Templates/assets/js/reinstall/index.js

@@ -0,0 +1,10 @@
+
+function mgLocationReload(data) {
+    window.location.reload();
+}
+function mgRedirect(data) {
+    if(data.rawData.redirectUrl)
+    {
+        window.location.href = data.rawData.redirectUrl;
+    }
+}

+ 24 - 0
app/UI/Client/Templates/assets/js/snapshot/index.js

@@ -0,0 +1,24 @@
+
+function pmToggleButton(data) {
+    let button = $(".pmCreateButton");
+    if(data.htmlData.createButtonStatus)
+    {
+        button.removeClass('hidden');
+    }
+    else
+    {
+        button.addClass('hidden');
+    }
+}
+
+function pmToggleCreateJobButton(data) {
+    let button = $(".pmCreateJobButton");
+    if(data.htmlData.createJobButtonStatus)
+    {
+        button.removeClass('hidden');
+    }
+    else
+    {
+        button.addClass('hidden');
+    }
+}

+ 61 - 0
app/UI/Disk/Buttons/BackupSwitchButton.php

@@ -0,0 +1,61 @@
+<?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\ProxmoxVps\App\UI\Disk\Buttons;
+
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\ResponseTemplates\DataJsonResponse;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonSwitchAjax;
+
+class BackupSwitchButton extends ButtonSwitchAjax implements ClientArea
+{
+    use ProductService;
+    use ApiService;
+    protected $switchColumn = 'backup';
+    protected $refreshActionIds = 'diskDataTable';
+
+    public function initContent()
+    {
+        parent::initContent();
+        $this->addHtmlAttribute(':disabled', 'dataRow.master == true');
+        if (!$this->configuration()->isPermissionAdditionalDiskBackup())
+        {
+            $this->htmlAttributes["disabled"] = "";
+        }
+    }
+
+    public function returnAjaxData()
+    {
+        try
+        {
+            $this->acl()->additionalDiskBackup();
+            $hdd = $this->vm()->findHardDiskById($this->getRequestValue('actionElementId'));
+            $hdd->setBackup($this->getRequestValue("value") == "on" ? null : 0);
+            $hdd->update();
+        }
+        catch (\Exception $exc)
+        {
+            return (new DataJsonResponse())->setStatusError()->setMessage($exc->getMessage())->setCallBackFunction($this->callBackFunction)->addRefreshTargetId($this->refreshActionIds);
+        }
+        return (new DataJsonResponse())->setMessageAndTranslate('changesSaved')->setCallBackFunction($this->callBackFunction)->addRefreshTargetId($this->refreshActionIds);
+    }
+
+}

+ 35 - 0
app/UI/Disk/Buttons/CreateButton.php

@@ -0,0 +1,35 @@
+<?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\ProxmoxVps\App\UI\Disk\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Disk\Modals\CreateModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonCreate;
+
+class CreateButton extends ButtonCreate implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('createButton');
+        $this->initLoadModalAction(new CreateModal());
+    }
+
+}

+ 37 - 0
app/UI/Disk/Buttons/DeleteButton.php

@@ -0,0 +1,37 @@
+<?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\ProxmoxVps\App\UI\Disk\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Disk\Modals\DeleteModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+
+class DeleteButton extends ButtonDataTableModalAction implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('deleteButton');
+        $this->setDisableByColumnValue("master", true);
+        $this->switchToRemoveBtn();
+        $this->initLoadModalAction(new DeleteModal());
+    }
+
+}

+ 36 - 0
app/UI/Disk/Buttons/UpdateButton.php

@@ -0,0 +1,36 @@
+<?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\ProxmoxVps\App\UI\Disk\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Disk\Modals\UpdateModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+
+class UpdateButton extends ButtonDataTableModalAction implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('updateButton');
+        $this->initLoadModalAction(new UpdateModal());
+        $this->setDisableByColumnValue("master", true);
+    }
+
+}

+ 83 - 0
app/UI/Disk/Forms/CreateForm.php

@@ -0,0 +1,83 @@
+<?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\ProxmoxVps\App\UI\Disk\Forms;
+
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\Enum\ConfigurableOption;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Validators\NumberValidator;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Disk\Providers\DiskProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Text;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+
+
+class CreateForm extends BaseForm implements ClientArea
+{
+    use ProductService;
+
+    public function initContent()
+    {
+        $this->initIds('createForm');
+        $this->setFormType('create');
+        $this->setProvider(new DiskProvider());
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['create'];
+    }
+
+    private function initFields()
+    {
+        $max = $this->getWhmcsConfigOption(ConfigurableOption::ADDITIONAL_DISKS_SIZE , $this->configuration()->getAdditionalDiskSize()) ;
+        //size
+        $field = new Text('size');
+        $field->addValidator(new NumberValidator(1, $max, true));
+        $this->addField($field);
+        //bus
+        $field = new Select('bus');
+        $options=[];
+        foreach( $this->configuration()->getAdditionalDiskType() as $entery){
+            $options[$entery] = sl("lang")->tr($entery);
+        }
+        $field->setAvailableValues($options);
+        $this->addField($field);
+        //format
+        $field = new Select('format');
+        $options=[];
+        foreach( $this->configuration()->getAdditionalDiskFormat() as $entery){
+            $options[$entery] = sl("lang")->tr($entery);
+        }
+        $field->setAvailableValues($options);
+        $this->addField($field);
+        //backup
+        if ($this->configuration()->isPermissionAdditionalDiskBackup())
+        {
+            $field = new Switcher('backup');
+            $this->addField($field);
+        }
+
+    }
+}

+ 51 - 0
app/UI/Disk/Forms/DeleteForm.php

@@ -0,0 +1,51 @@
+<?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\ProxmoxVps\App\UI\Disk\Forms;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Disk\Providers\DiskProvider;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Disk\Providers\FirewallOptionProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Hidden;
+
+
+class DeleteForm extends BaseForm implements ClientArea
+{
+    public function initContent()
+    {
+        $this->initIds('deleteForm');
+        $this->setFormType('delete');
+        $this->setProvider(new DiskProvider());
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['delete'];
+    }
+
+    private function initFields()
+    {
+        $this->setConfirmMessage('conforimDelete');
+        $this->addField(new Hidden("id"));
+    }
+
+}

+ 65 - 0
app/UI/Disk/Forms/UpdateForm.php

@@ -0,0 +1,65 @@
+<?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\ProxmoxVps\App\UI\Disk\Forms;
+
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Disk\Providers\DiskProvider;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Validators\NumberValidator;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Hidden;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Text;
+
+
+class UpdateForm extends BaseForm implements ClientArea
+{
+    use ProductService;
+
+    public function initContent()
+    {
+        $this->initIds('updateForm');
+        $this->setFormType('update');
+        $this->setProvider(new DiskProvider());
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['update'];
+    }
+
+    private function initFields()
+    {
+        //entity id
+        $this->addField(new Hidden("id"));
+        //size
+        $field = new Text('size');
+        $field->addValidator(new NumberValidator(1, 10000, true));
+        $this->addField($field);
+        //backup
+        if ($this->configuration()->isPermissionAdditionalDiskBackup())
+        {
+            $field = new Switcher('backup');
+            $this->addField($field);
+        }
+    }
+}

+ 35 - 0
app/UI/Disk/Modals/CreateModal.php

@@ -0,0 +1,35 @@
+<?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\ProxmoxVps\App\UI\Disk\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Disk\Forms\CreateForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\BaseEditModal;
+
+class CreateModal extends BaseEditModal implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('createModal');
+        $this->addForm(new CreateForm());
+    }
+
+}

+ 35 - 0
app/UI/Disk/Modals/DeleteModal.php

@@ -0,0 +1,35 @@
+<?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\ProxmoxVps\App\UI\Disk\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Disk\Forms\DeleteForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmDanger;
+
+class DeleteModal extends ModalConfirmDanger implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('deleteModal');
+        $this->addForm(new DeleteForm());
+    }
+
+}

+ 34 - 0
app/UI/Disk/Modals/UpdateModal.php

@@ -0,0 +1,34 @@
+<?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\ProxmoxVps\App\UI\Disk\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Disk\Forms\UpdateForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\BaseEditModal;
+class UpdateModal extends BaseEditModal implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('updateModal');
+        $this->addForm(new UpdateForm());
+    }
+
+}

+ 137 - 0
app/UI/Disk/Pages/DiskDataTable.php

@@ -0,0 +1,137 @@
+<?php
+/* * ********************************************************************
+*  ProxmoxVPS Product developed. (26.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\ProxmoxVps\App\UI\Disk\Pages;
+
+use ModulesGarden\ProxmoxAddon\App\Libs\Format;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Disk\Buttons\BackupSwitchButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Disk\Buttons\CreateButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Disk\Buttons\DeleteButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Disk\Buttons\DeleteMassButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Disk\Buttons\RestoreButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Disk\Buttons\UpdateButton;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\Column;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\DataProviders\Providers\ArrayDataProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\DataTable;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+
+class DiskDataTable extends DataTable implements ClientArea
+{
+    use ProductService;
+    use ApiService;
+    protected $id = 'diskDataTable';
+    protected $title = 'diskDataTable';
+
+    public function initContent()
+    {
+        if(!preg_match('/disk/',$this->vm()->config()['hotplug'])){
+            $this->setInternalAlertMessage("Adding, editing or removing disk will reboot the virtual machine.");
+        }
+        //Create
+        $createButton = new CreateButton();
+        $createButton->addClass("pmCreateButton");
+        if (!$this->resourceGuard()->hasDiskLimit())
+        {
+            $createButton->addClass("hidden");
+        }
+        $this->addButton($createButton);
+        //Update
+        $this->addActionButton(new UpdateButton());
+        //Delete
+        $this->addActionButton(new DeleteButton());
+    }
+
+    protected function loadHtml()
+    {
+        $this->addColumn((new Column('name'))->setSearchable(true, "string")->setOrderable('ASC'))
+            ->addColumn((new Column('bus'))->setSearchable(true, "string")->setOrderable())
+            ->addColumn((new Column('format'))->setSearchable(true)->setOrderable())
+            ->addColumn((new Column('backup'))->setSearchable(true)->setOrderable())
+            ->addColumn((new Column('bytes'))->setSearchable(true)->setOrderable());
+    }
+
+    public function replaceFieldName($key, $row)
+    {
+        $id = preg_replace('/[^0-9]/', '', $row[$key]);
+        $id++;
+        sl("lang")->addReplacementConstant("id",$id);
+        return sl("lang")->abtr('Disk :id:');
+    }
+
+    public function replaceFieldBus($key, $row)
+    {
+        return sl("lang")->tr($row[$key]);
+    }
+
+    public function replaceFieldFormat($key, $row)
+    {
+        if ($row[$key])
+        {
+            return $row[$key];
+        }
+        return "raw";
+    }
+
+    public function replaceFieldBytes($key, $row)
+    {
+        return Format::convertBytes($row['bytes']);
+    }
+
+    public function replaceFieldCompress($key, $row)
+    {
+        return sl('lang')->tr($row['compress']);
+    }
+
+    public function customColumnHtmlBackup()
+    {
+        return (new BackupSwitchButton())->getHtml();
+    }
+
+    public function replaceFieldBackup($key, $row)
+    {
+        return $row['backup'] == "0" ? "off" : "on";
+    }
+
+    protected function loadData()
+    {
+        $data = [];
+        foreach ($this->vm()->getHardDisks() as $entity)
+        {
+            $data[] = [
+                "id"     => $entity->getId(),
+                "bus"    => $entity->getId(),
+                "name"   => $entity->getName(),
+                "format" => $entity->getFormat(),
+                "backup" => $entity->getBackup(),
+                "size"   => $entity->getSize(),
+                "bytes"  => $entity->getBytes(),
+                "master" => $entity->isMaster(),
+            ];
+        }
+        $dataProv = new ArrayDataProvider();
+        $dataProv->setDefaultSorting("name", 'ASC');
+        $dataProv->setData($data);
+        $this->setDataProvider($dataProv);
+    }
+
+
+}

+ 169 - 0
app/UI/Disk/Providers/DiskProvider.php

@@ -0,0 +1,169 @@
+<?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\ProxmoxVps\App\UI\Disk\Providers;
+
+use MGProvision\Proxmox\v2\models\HardDisk;
+use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\RebootVmJob;
+use ModulesGarden\ProxmoxAddon\App\Models\Job;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\ResponseTemplates\HtmlDataJsonResponse;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\DataProviders\BaseDataProvider;
+use function ModulesGarden\ProxmoxAddon\Core\Helper\queue;
+
+
+class DiskProvider extends BaseDataProvider implements ClientArea
+{
+    use ProductService;
+    use ApiService;
+
+    public function read()
+    {
+        if ($this->actionElementId && $this->actionElementId != "diskDataTable")
+        {
+            $disk = $this->vm()->findHardDiskById($this->actionElementId);
+            $this->data       = $disk->getAttributes();
+            $this->data['id'] = $this->actionElementId;
+            //backup
+            $backup               = $this->data['backup'];
+            $this->data['backup'] = $backup == "0" ? "off" : "on";
+            //size
+            $this->data['size'] = $disk->getGb();
+        }
+    }
+
+    public function create()
+    {
+        $this->resourceGuard()->diskLimit($this->formData['size']);
+        $storage = $this->configuration()->getAdditionalDiskStorage();
+        $ide     = $this->vm()->findFreeIde($this->formData['bus']);
+        $id      = $this->formData['bus'] . $ide;
+        $hdd     = new HardDisk($id);
+        $hdd->setApi($this->api());
+        $hdd->setPath($this->vm()->getPath() . "/config");
+        $hdd->setStorage($storage)
+            ->setSize($this->formData['size'])
+            ->setMedia("disk")
+            ->setFormat($this->formData['format'])
+            ->setBackup($this->configuration()->isPermissionAdditionalDiskBackup() && $this->formData['backup'] == "on" ? null : 0);
+        //disk speed
+        $hdd->setMbps_rd($this->configuration()->getAdditionalDiskMbpsRd())
+            ->setMbps_wr($this->configuration()->getAdditionalDiskMbpsWr());
+        //IOPS
+        $hdd->setIops_rd($this->configuration()->getAdditionalDiskIopsRd())
+            ->setIops_rd_max($this->configuration()->getAdditionalDiskIopsRdMax())
+            ->setIops_wr($this->configuration()->getAdditionalDiskIopsWr())
+            ->setIops_wr_max($this->configuration()->getAdditionalDiskIopsWrMax());
+        //cach
+        $hdd->setCache($this->configuration()->getAdditionalDiskCache());
+        //replicate
+        if ($this->configuration()->isAdditionalDiskReplicate())
+        {
+            $hdd->setReplicate(0);
+        }
+        //discard
+        if ($this->configuration()->isAdditionalDiskDiscard())
+        {
+            $hdd->setDiscard('on');
+        }
+        //iothread for VirtlO & SCSI 'VIRTIO', 'SCSI'
+        if ($this->configuration()->isAdditionalDiskIoThread() && in_array($this->formData['bus'], ['virtio', 'scsi']))
+        {
+            $hdd->setIothread(1);
+        }
+        $hdd->create();
+        return (new HtmlDataJsonResponse())
+            ->setStatusSuccess()
+            ->setMessageAndTranslate('The hard disk has been created successfully')
+            ->addData('createButtonStatus', $this->resourceGuard()->hasDiskLimit())
+            ->setCallBackFunction('pmToggleButton');
+    }
+
+    public function update()
+    {
+
+        $this->resourceGuard()->diskLimit($this->formData['size'], $this->formData['id']);
+        $hdd = $this->vm()->findHardDiskById($this->formData['id']);
+        if($hdd->isMaster()){
+            return (new HtmlDataJsonResponse())
+                ->setStatusError()
+                ->setMessageAndTranslate('Update the master disk size is restricted');
+        }
+        if ((int)$hdd->getGb() > (int)$this->formData['size'])
+        {
+            return (new HtmlDataJsonResponse())
+                ->setStatusError()
+                ->setMessageAndTranslate('Downgrading the disk size is restricted');
+        }
+        //resize
+        if ((int)$hdd->getGb() < (int)$this->formData['size'])
+        {
+            $size = "+" . abs((int)$this->formData['size'] - (int)$hdd->getGb()) . "G";
+            $hdd->resize($size);
+        }
+        //backup
+        $backup = $this->formData['backup'] == "on" ? null : 0;
+        if ($this->configuration()->isPermissionAdditionalDiskBackup() && $backup != $hdd->getBackup())
+        {
+            $hdd->setBackup($backup);
+            $hdd->update();
+        }
+        //reboot
+        if ($this->vm()->isRunning() &&
+            !Job::waiting()->ofJob(RebootVmJob::class)->ofHostingId($this->getWhmcsParamByKey("serviceid"))->count())
+        {
+            queue(RebootVmJob::class, [], null, "hosting", $this->getWhmcsParamByKey("serviceid"));
+        }
+        return (new HtmlDataJsonResponse())
+            ->setStatusSuccess()
+            ->setMessageAndTranslate('The hard disk has been updated successfully')
+            ->addData('createButtonStatus', $this->resourceGuard()->hasDiskLimit())
+            ->setCallBackFunction('pmToggleButton');
+    }
+
+    public function delete()
+    {
+        $hdd = $this->vm()->findHardDiskById($this->formData['id']);
+        if($hdd->isMaster()){
+            return (new HtmlDataJsonResponse())
+                ->setStatusError()
+                ->setMessageAndTranslate('The master hard disk cannot be deleted');
+        }
+        $hdd->delete();
+        unset($this->vm);
+        foreach($this->vm()->getHardDisks() as $hd){
+            if($hd->isMaster()){
+                continue;
+            }
+            if(preg_match('/unused/', $hd->getId())){
+                $hd->delete();
+                break;
+            }
+        }
+        return (new HtmlDataJsonResponse())
+            ->setStatusSuccess()
+            ->setMessageAndTranslate('The hard disk has been deleted successfully')
+            ->addData('createButtonStatus', $this->resourceGuard()->hasDiskLimit())
+            ->setCallBackFunction('pmToggleButton');
+    }
+
+
+}

+ 37 - 0
app/UI/Firewall/Buttons/CreateGroupButton.php

@@ -0,0 +1,37 @@
+<?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\ProxmoxVps\App\UI\Firewall\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Firewall\Modals\CreateGroupModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonCreate;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\DropdawnButtonWrappers\ButtonDropdownItem;
+
+
+class CreateGroupButton extends ButtonDropdownItem  implements ClientArea
+{
+    protected $icon  = 'lu-dropdown__link-icon lu-zmdi  lu-zmdi-shield-security';
+
+    public function initContent()
+    {
+        $this->initIds('createGroupButton');
+        $this->initLoadModalAction(new CreateGroupModal());
+    }
+}

+ 33 - 0
app/UI/Firewall/Buttons/CreateRuleButton.php

@@ -0,0 +1,33 @@
+<?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\ProxmoxVps\App\UI\Firewall\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Firewall\Modals\CreateRuleModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonCreate;
+
+class CreateRuleButton extends ButtonCreate implements ClientArea
+{
+    public function initContent()
+    {
+        $this->initIds('createRuleButton');
+        $this->initLoadModalAction(new CreateRuleModal());
+    }
+}

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

@@ -0,0 +1,36 @@
+<?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\ProxmoxVps\App\UI\Firewall\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Firewall\Modals\DeleteModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+
+class DeleteButton extends ButtonDataTableModalAction implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('deleteButton');
+        $this->switchToRemoveBtn();
+        $this->initLoadModalAction(new DeleteModal());
+    }
+
+}

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

@@ -0,0 +1,56 @@
+<?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\ProxmoxVps\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\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\ResponseTemplates\DataJsonResponse;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonSwitchAjax;
+
+class EnableSwitchButton extends ButtonSwitchAjax implements ClientArea
+{
+
+    use ProductService;
+    use ApiService;
+    protected $switchColumn = 'enable';
+    protected $refreshActionIds = 'enableSwitchDataTable';
+
+    public function returnAjaxData()
+    {
+        try
+        {
+            $data         = json_decode(base64_decode($this->getRequestValue('actionElementId')), true);
+            $firewallRule = new FirewallRule();
+            $firewallRule->setApi($this->api());
+            $pos = $data['pos'];
+            $firewallRule->setPath($this->vm()->getPath() . "/firewall/rules/{$pos}");
+            $firewallRule->setEnable($this->getRequestValue("value") == "on" ? 1 : 0);
+            $firewallRule->update();
+        }
+        catch (\Exception $exc)
+        {
+            return (new DataJsonResponse())->setStatusError()->setMessage($exc->getMessage())->setCallBackFunction($this->callBackFunction)->addRefreshTargetId($this->refreshActionIds);
+        }
+        return (new DataJsonResponse())->setMessageAndTranslate('changesSaved')->setCallBackFunction($this->callBackFunction)->addRefreshTargetId($this->refreshActionIds);
+    }
+}

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

@@ -0,0 +1,54 @@
+<?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\ProxmoxVps\App\UI\Firewall\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Firewall\Modals\UpdateGroupModal;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Firewall\Modals\UpdateRuleModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+
+class UpdateRuleButton extends ButtonDataTableModalAction implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('updateButton');
+
+        if ($this->isUpdateGroup())
+        {
+            $this->initLoadModalAction(new UpdateGroupModal());
+            return;
+        }
+        $this->initLoadModalAction(new UpdateRuleModal());
+    }
+
+    private function isUpdateGroup()
+    {
+        $this->loadRequestObj();
+        $this->request->get('ajax') && $this->request->get('actionElementId');
+        if ($this->request->get('ajax') && $this->request->get('actionElementId'))
+        {
+            $this->data = json_decode(base64_decode($this->request->get('actionElementId')), true);
+            return $this->data['type'] == "group";
+        }
+        return false;
+    }
+
+}

+ 44 - 0
app/UI/Firewall/Forms/CreateGroupForm.php

@@ -0,0 +1,44 @@
+<?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\ProxmoxVps\App\UI\Firewall\Forms;
+
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Firewall\Providers\FirewallProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+
+class CreateGroupForm extends GroupForm implements ClientArea
+{
+    use ApiService;
+
+    public function initContent()
+    {
+        $this->initIds('createGroupForm');
+        $this->setFormType('create');
+        $this->setProvider(new FirewallProvider());
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['create'];
+    }
+
+}

+ 42 - 0
app/UI/Firewall/Forms/CreateRuleForm.php

@@ -0,0 +1,42 @@
+<?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\ProxmoxVps\App\UI\Firewall\Forms;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Firewall\Providers\FirewallProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+
+class CreateRuleForm extends RuleForm implements ClientArea
+{
+    public function initContent()
+    {
+        $this->initIds('createRuleForm');
+        $this->setFormType('create');
+        $this->setProvider(new FirewallProvider());
+        $this->addClass('lu-row');
+        $this->initSections();
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['create'];
+    }
+}

+ 50 - 0
app/UI/Firewall/Forms/DeleteForm.php

@@ -0,0 +1,50 @@
+<?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\ProxmoxVps\App\UI\Firewall\Forms;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Firewall\Providers\FirewallProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Hidden;
+
+
+class DeleteForm extends BaseForm implements ClientArea
+{
+    public function initContent()
+    {
+        $this->initIds('deleteForm');
+        $this->setFormType('delete');
+        $this->setProvider(new FirewallProvider());
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['delete'];
+    }
+
+    private function initFields()
+    {
+        $this->setConfirmMessage('conforimDelete');
+        $this->addField(new Hidden("pos"));
+    }
+
+}

+ 81 - 0
app/UI/Firewall/Forms/GroupForm.php

@@ -0,0 +1,81 @@
+<?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\ProxmoxVps\App\UI\Firewall\Forms;
+
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Hidden;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Text;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+
+class GroupForm extends BaseForm implements ClientArea
+{
+    use ApiService;
+    use ProductService;
+
+
+    protected function initFields()
+    {
+        //enable
+        $field = new Switcher('enable');
+        $this->addField($field);
+        //pos
+        if ($this->getFormType() == "update")
+        {
+            $this->addField(new Hidden("pos"));
+        }
+        //action
+        $field   = new Select('action');
+        $options = [];
+        foreach ($this->api()->get("/cluster/firewall/groups", []) as $response)
+        {
+            $options[$response['group']] = sl("lang")->tr($response['group']);
+        }
+        $field->setAvailableValues($options);
+        $this->addField($field);
+        //iface
+        $field      = new Select('iface');
+        $ifaces     = [];
+        $interfaces = $this->configuration()->getFirewallInterfaces();
+        if (in_array("venet", $interfaces))
+        {
+            $ifaces["venet"] = sl('lang')->tr("venet");
+        }
+        if (in_array("eth", $interfaces))
+        {
+            foreach ($this->vm()->getNetworkDevices() as $nd)
+            {
+                $ifaces[$nd->getId()] = $nd->getId();
+            }
+        }
+        $field->setAvailableValues($ifaces);
+        $this->addField($field);
+        //comment
+        $field = new Text('comment');
+        $this->addField($field);
+        //type
+        $this->addField((new Hidden("type"))->setDefaultValue('group'));
+    }
+
+}

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

@@ -0,0 +1,202 @@
+<?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\ProxmoxVps\App\UI\Firewall\Forms;
+
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Validators\PortValidator;
+use ModulesGarden\Servers\ProxmoxVps\Core\FileReader\Reader\Json;
+use ModulesGarden\Servers\ProxmoxVps\Core\ModuleConstants;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\BaseField;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Hidden;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Text;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\HalfPageSection;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Sections\RawSection;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+
+
+class RuleForm extends BaseForm implements ClientArea
+{
+    use  ApiService;
+    use ProductService;
+    private $mainSection;
+    private $topSection;
+    private $leftSection;
+    private $rightSection;
+    private $bottomSection;
+    private $sectionFields=[];
+
+    protected function initSections()
+    {
+        //Main
+        $this->mainSection = new RawSection('mainSection');
+        $this->mainSection->setMainContainer($this->mainContainer);
+        //Left
+        $this->leftSection = new HalfPageSection('leftSection');
+        $this->leftSection->setMainContainer($this->mainContainer);
+        //Right
+        $this->rightSection = new HalfPageSection('rightSection');
+        $this->rightSection->setMainContainer($this->mainContainer);
+        //Add Top
+        $this->topSection = new RawSection('topSection');
+        $this->topSection->setMainContainer($this->mainContainer);
+        //add main
+        $this->mainSection->addSection( $this->topSection )->addSection($this->leftSection)->addSection($this->rightSection);
+        $this->addSection($this->mainSection);
+        //Bottom
+        $this->bottomSection = new RawSection('bottomSection');
+        $this->bottomSection->setMainContainer($this->mainContainer);
+        $this->addSection($this->bottomSection);
+    }
+
+    protected function initFields()
+    {
+        /*Left*/
+        //enable
+        $field = new Switcher('enable');
+        $this->topSection->addField($field);
+        //type
+        $this->addFieldType();
+        //action
+        $this->addFieldAction();
+        //iface
+        $this->addFieldIface();
+        //source
+        $field = new Text('source');
+        $this->addSectionField($field);
+        //dest
+        $field = new Text('dest');
+        $this->addSectionField($field);
+        /*Right*/
+        //macro
+        $this->addFieldMacro();
+        //proto
+        $this->addFieldProto();
+        //sport
+        $field = new Text('sport');
+        $field->addValidator(new PortValidator());
+        $this->addSectionField($field);
+        //dport
+        $field = new Text('dport');
+        $field->addValidator(new PortValidator());
+        $this->addSectionField($field);
+        //comment
+        $field = new Text('comment');
+        $this->bottomSection->addField($field);
+        $this->addFieldsToSections();
+    }
+
+    protected function addFieldPos()
+    {
+        $field = new Hidden('pos');
+        $this->bottomSection->addField($field);
+    }
+
+    private function addFieldType()
+    {
+        $field = new Select('type');
+        $field->setAvailableValues([
+            "in"  => sl('lang')->tr("in"),
+            "out" => sl('lang')->tr("out")
+        ]);
+        $this->addSectionField($field);
+    }
+
+    private function addFieldAction()
+    {
+        $field    = new Select('action');
+        $enteries = new Json('actions.json', ModuleConstants::getFullPath('storage', 'app', "firewall"));
+        $options  = [];
+        foreach ($enteries->get() as $key => $v)
+        {
+            $options[$key] = sl('lang')->tr($v);
+        }
+        $field->setAvailableValues($options);
+        $this->addSectionField($field);
+    }
+
+    private function addFieldIface()
+    {
+        $field      = new Select('iface');
+        $ifaces     = [];
+        $interfaces = $this->configuration()->getFirewallInterfaces();
+        if (in_array("venet", $interfaces))
+        {
+            $ifaces["venet"] = sl('lang')->tr("venet");
+        }
+        if (in_array("eth", $interfaces))
+        {
+            foreach ($this->vm()->getNetworkDevices() as $nd)
+            {
+                $ifaces[$nd->getId()] = $nd->getId();
+            }
+        }
+        $field->setAvailableValues($ifaces);
+        $this->addSectionField($field);
+    }
+
+    private function addFieldMacro()
+    {
+        $field  = new Select('macro');
+        $macros = ["0" => sl("lang")->tr("None")];
+        foreach ($this->api()->get("/cluster/firewall/macros", []) as $response)
+        {
+            $macros[$response['macro']] = sl("lang")->tr($response['descr']);
+        }
+        $field->setAvailableValues($macros);
+        $this->addSectionField($field);
+    }
+
+    private function addFieldProto()
+    {
+        $field    = new Select('proto');
+        $enteries = new Json('protocols.json', ModuleConstants::getFullPath('storage', 'app', "firewall"));
+        $options  = [];
+        foreach ($enteries->get() as $key => $v)
+        {
+            $options[$key] = sl('lang')->tr($v);
+        }
+        $field->setAvailableValues($options);
+        $this->addSectionField($field);
+    }
+
+    public function addSectionField(BaseField $field)
+    {
+        $this->sectionFields[] = $field;
+        return $this;
+    }
+
+    private function addFieldsToSections(){
+        foreach($this->sectionFields as $k => $field){
+            if($k % 2 == 0 ){
+                $this->leftSection->addField($field);
+            }else{
+                $this->rightSection->addField($field);
+            }
+        }
+        unset($this->sectionFields);
+    }
+
+
+}

+ 45 - 0
app/UI/Firewall/Forms/UpdateGroupForm.php

@@ -0,0 +1,45 @@
+<?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\ProxmoxVps\App\UI\Firewall\Forms;
+
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Firewall\Providers\FirewallProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+
+class UpdateGroupForm extends GroupForm implements ClientArea
+{
+    use ApiService;
+
+    public function initContent()
+    {
+        $this->initIds('createGroupForm');
+        $this->setFormType('update');
+        $this->setProvider(new FirewallProvider());
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['update'];
+    }
+
+
+}

+ 44 - 0
app/UI/Firewall/Forms/UpdateRuleForm.php

@@ -0,0 +1,44 @@
+<?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\ProxmoxVps\App\UI\Firewall\Forms;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Firewall\Providers\FirewallProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+
+
+class UpdateRuleForm extends RuleForm implements ClientArea
+{
+    public function initContent()
+    {
+        $this->initIds('updateForm');
+        $this->setFormType('update');
+        $this->setProvider(new FirewallProvider());
+        $this->addClass('lu-row');
+        $this->initSections();
+        $this->addFieldPos();
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['update'];
+    }
+}

+ 36 - 0
app/UI/Firewall/Modals/CreateGroupModal.php

@@ -0,0 +1,36 @@
+<?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\ProxmoxVps\App\UI\Firewall\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Firewall\Forms\CreateGroupForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\BaseEditModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmSuccess;
+
+class CreateGroupModal extends BaseEditModal implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('createGroupModal');
+        $this->addForm(new CreateGroupForm());
+    }
+
+}

+ 36 - 0
app/UI/Firewall/Modals/CreateRuleModal.php

@@ -0,0 +1,36 @@
+<?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\ProxmoxVps\App\UI\Firewall\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Firewall\Forms\CreateRuleForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\BaseEditModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmSuccess;
+
+class CreateRuleModal extends BaseEditModal implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('createRuleModal');
+        $this->addForm(new CreateRuleForm());
+    }
+
+}

+ 35 - 0
app/UI/Firewall/Modals/DeleteModal.php

@@ -0,0 +1,35 @@
+<?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\ProxmoxVps\App\UI\Firewall\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Firewall\Forms\DeleteForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmDanger;
+
+class DeleteModal extends ModalConfirmDanger implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('deleteModal');
+        $this->addForm(new DeleteForm());
+    }
+
+}

+ 36 - 0
app/UI/Firewall/Modals/UpdateGroupModal.php

@@ -0,0 +1,36 @@
+<?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\ProxmoxVps\App\UI\Firewall\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Firewall\Forms\UpdateGroupForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\BaseEditModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmSuccess;
+
+class UpdateGroupModal extends BaseEditModal implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('updateGroupModal');
+        $this->addForm(new UpdateGroupForm());
+    }
+
+}

+ 36 - 0
app/UI/Firewall/Modals/UpdateRuleModal.php

@@ -0,0 +1,36 @@
+<?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\ProxmoxVps\App\UI\Firewall\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Firewall\Forms\UpdateRuleForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\BaseEditModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmSuccess;
+
+class UpdateRuleModal extends BaseEditModal implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('updateModal');
+        $this->addForm(new UpdateRuleForm());
+    }
+
+}

+ 175 - 0
app/UI/Firewall/Pages/FirewallDataTable.php

@@ -0,0 +1,175 @@
+<?php
+/* * ********************************************************************
+*  ProxmoxVPS Product developed. (26.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\ProxmoxVps\App\UI\Firewall\Pages;
+
+use MGProvision\Proxmox\v2\repository\FirewallRulesRepository;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Firewall\Buttons\CreateGroupButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Firewall\Buttons\CreateRuleButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Firewall\Buttons\DeleteButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Firewall\Buttons\DeleteMassButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Firewall\Buttons\EnableSwitchButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Firewall\Buttons\RestoreButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Firewall\Buttons\UpdateRuleButton;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\Column;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\DataProviders\Providers\ArrayDataProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\DataTable;
+
+class FirewallDataTable extends DataTable implements ClientArea
+{
+    use ApiService;
+    use ProductService;
+    protected $id = 'firewallDataTable';
+    protected $title = 'firewallDataTable';
+
+    public function initContent()
+    {
+        //Create Rule
+        $createRule = new CreateRuleButton();
+        //Create Group
+        $createGroup = new CreateGroupButton();
+        $createRule->addClass("pmCreateButton");
+        $createGroup->addClass("pmCreateButton");
+        if (!$this->resourceGuard()->hasfirewallLimit())
+        {
+            $createRule->addClass("hidden");
+            $createGroup->addClass("hidden");
+        }
+        $this->addButton($createRule);
+        $this->addButton($createGroup);
+        //Update
+        $this->addActionButton(new UpdateRuleButton());
+        //Delete
+        $this->addActionButton(new DeleteButton());
+    }
+
+    protected function loadHtml()
+    {
+        $this->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())
+            ->addColumn((new Column('comment'))->setSearchable(true, "string")->setOrderable());
+    }
+
+    public function customColumnHtmlEnable()
+    {
+        return (new EnableSwitchButton())->getHtml();
+    }
+
+    public function replaceFieldEnable($key, $row)
+    {
+        return $row[$key] == "1" ? "on" : "off";
+    }
+
+    public function replaceFieldMacro($key, $row)
+    {
+        if ($row[$key])
+        {
+            return $row[$key];
+        }
+        return '-';
+    }
+
+    public function replaceFieldIface($key, $row)
+    {
+        if ($row[$key])
+        {
+            return $row[$key];
+        }
+        return '-';
+    }
+
+    public function replaceFieldSource($key, $row)
+    {
+        if ($row[$key])
+        {
+            return $row[$key];
+        }
+        return '-';
+    }
+
+    public function replaceFieldDest($key, $row)
+    {
+        if ($row[$key])
+        {
+            return $row[$key];
+        }
+        return '-';
+    }
+
+    public function replaceFieldProto($key, $row)
+    {
+        if ($row[$key])
+        {
+            return $row[$key];
+        }
+        return '-';
+    }
+
+    public function replaceFieldDport($key, $row)
+    {
+        if ($row[$key])
+        {
+            return $row[$key];
+        }
+        return '-';
+    }
+
+    public function replaceFieldSport($key, $row)
+    {
+        if ($row[$key])
+        {
+            return $row[$key];
+        }
+        return '-';
+    }
+
+    public function replaceFieldComment($key, $row)
+    {
+        if ($row[$key])
+        {
+            return $row[$key];
+        }
+        return '-';
+    }
+
+    protected function loadData()
+    {
+        $repository = new FirewallRulesRepository();
+        $repository->setApi($this->api());
+        $repository->findByVm($this->vm());
+        $data = [];
+        foreach ($repository->fetch() as $entity)
+        {
+            $row    = $entity->toArray();
+            $data[] = array_merge(['id' => base64_encode(json_encode($row))], $row);
+        }
+        $this->setCallBackFunction('pmToggleDropDownButtons');
+
+        $dataProv = new ArrayDataProvider();
+        $dataProv->setData($data);
+        $this->setDataProvider($dataProv);
+    }
+
+
+}

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

@@ -0,0 +1,105 @@
+<?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\ProxmoxVps\App\UI\Firewall\Providers;
+
+use MGProvision\Proxmox\v2\models\FirewallRule;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\ResponseTemplates\HtmlDataJsonResponse;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\DataProviders\BaseDataProvider;
+
+
+class FirewallProvider extends BaseDataProvider implements ClientArea
+{
+    use ProductService;
+    use ApiService;
+
+    public function read()
+    {
+        if ($this->actionElementId)
+        {
+            $this->data = json_decode(base64_decode($this->actionElementId), true);
+            //enable
+            $enable               = $this->data['enable'];
+            $this->data['enable'] = $enable == "1" ? "on" : "off";
+        }
+    }
+
+    public function create()
+    {
+        $this->acl()->firewall();
+        $this->resourceGuard()->firewallLimit();
+        $firewallRule = new FirewallRule();
+        $firewallRule->setApi($this->api());
+        $firewallRule->setPath($this->vm()->getPath() . "/firewall/rules/");
+        $attributes           = $this->formData;
+        $attributes['enable'] = $this->formData['enable'] == "on" ? 1 : 0;
+        if ($attributes['proto'] == "0")
+        {
+            unset($attributes['proto']);
+        }
+        $firewallRule->setAttributes($attributes);
+        $firewallRule->create();
+        return (new HtmlDataJsonResponse())
+            ->setStatusSuccess()
+            ->setMessageAndTranslate('The firewall rule has been created successfully')
+            ->addData('createButtonStatus', $this->resourceGuard()->hasfirewallLimit())
+            ->setCallBackFunction('pmToggleButton');
+    }
+
+    public function update()
+    {
+        $this->acl()->firewall();
+        $firewallRule = new FirewallRule();
+        $firewallRule->setApi($this->api());
+        $pos = $this->formData['pos'];
+        unset($this->formData['pos']);
+        $firewallRule->setPath($this->vm()->getPath() . "/firewall/rules/{$pos}");
+        $attributes           = $this->formData;
+        $attributes['enable'] = $this->formData['enable'] == "on" ? 1 : 0;
+        if ($attributes['proto'] == "0")
+        {
+            unset($attributes['proto']);
+        }
+        $firewallRule->setAttributes($attributes);
+        $firewallRule->update();
+        return (new HtmlDataJsonResponse())
+            ->setStatusSuccess()
+            ->setMessageAndTranslate('The firewall rule has been updated successfully');
+    }
+
+    public function delete()
+    {
+        $this->acl()->firewall();
+        $firewallRule = new FirewallRule();
+        $firewallRule->setApi($this->api());
+        $pos = $this->formData['pos'];
+        $firewallRule->setPath($this->vm()->getPath() . "/firewall/rules/{$pos}");
+        $firewallRule->delete();
+        return (new HtmlDataJsonResponse())
+            ->setStatusSuccess()
+            ->setMessageAndTranslate('The firewall rule has been deleted successfully')
+            ->addData('createButtonStatus', $this->resourceGuard()->hasfirewallLimit())
+            ->setCallBackFunction('pmToggleButton');
+    }
+
+
+}

+ 38 - 0
app/UI/FirewallOption/Buttons/UpdateButton.php

@@ -0,0 +1,38 @@
+<?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\ProxmoxVps\App\UI\FirewallOption\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\FirewallOption\Modals\UpdateModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+
+
+class UpdateButton extends ButtonDataTableModalAction implements ClientArea
+{
+
+    protected $icon = 'lu-zmdi lu-zmdi-edit';
+
+    public function initContent()
+    {
+        $this->initIds('updateButton');
+        $this->initLoadModalAction(new UpdateModal());
+    }
+
+}

+ 121 - 0
app/UI/FirewallOption/Forms/UpdateForm.php

@@ -0,0 +1,121 @@
+<?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\ProxmoxVps\App\UI\FirewallOption\Forms;
+
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\FirewallOption\Providers\FirewallOptionProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+
+
+class UpdateForm extends BaseForm implements ClientArea
+{
+    use ProductService;
+
+    public function initContent()
+    {
+        $this->initIds('updateForm');
+        $this->setFormType('update');
+        $this->setProvider(new FirewallOptionProvider());
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['update'];
+    }
+
+    private function initFields()
+    {
+        //logLevel
+        $logLevels = [
+            "nolog"   => sl("lang")->tr("nolog"),
+            "info"    => sl("lang")->tr("info"),
+            "err"     => sl("lang")->tr("err"),
+            "warning" => sl("lang")->tr("warning"),
+            "crit"    => sl("lang")->tr("crit"),
+            "alert"   => sl("lang")->tr("alert"),
+            "emerg"   => sl("lang")->tr("emerg"),
+            "debug"   => sl("lang")->tr("debug"),
+        ];
+        //enable
+        if($this->acl()->hasFirewallOption("enable")){
+            $field = new Switcher("enable");
+            $this->addField($field);
+        }
+        //dhcp
+        if($this->acl()->hasFirewallOption("dhcp")){
+            $field = new Switcher("dhcp");
+            $this->addField($field);
+        }
+        //ndp
+        if($this->acl()->hasFirewallOption("ndp")){
+            $field = new Switcher("ndp");
+            $field->setDefaultValue("on");
+            $this->addField($field);
+        }
+        //radv
+        if($this->acl()->hasFirewallOption("radv")){
+            $field = new Switcher("radv");
+            $this->addField($field);
+        }
+        //macfilter
+        if($this->acl()->hasFirewallOption("macfilter")){
+            $field = new Switcher("macfilter");
+            $field->setDefaultValue("on");
+            $this->addField($field);
+        }
+        //ipfilter
+        if($this->acl()->hasFirewallOption("ipfilter")){
+            $field = new Switcher("ipfilter");
+            $this->addField($field);
+        }
+        //log_level_in
+        $field = new Select('log_level_in');
+        $field->setAvailableValues($logLevels);
+        $this->addField($field);
+        //log_level_out
+        $field = new Select('log_level_out');
+        $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);
+        //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);
+    }
+}

+ 35 - 0
app/UI/FirewallOption/Modals/CreateModal.php

@@ -0,0 +1,35 @@
+<?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\ProxmoxVps\App\UI\FirewallOption\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\FirewallOption\Forms\CreateForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmSuccess;
+
+class CreateModal extends ModalConfirmSuccess implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('createModal');
+        $this->addForm(new CreateForm());
+    }
+
+}

+ 35 - 0
app/UI/FirewallOption/Modals/DeleteModal.php

@@ -0,0 +1,35 @@
+<?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\ProxmoxVps\App\UI\FirewallOption\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\FirewallOption\Forms\DeleteForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmDanger;
+
+class DeleteModal extends ModalConfirmDanger implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('deleteModal');
+        $this->addForm(new DeleteForm());
+    }
+
+}

+ 36 - 0
app/UI/FirewallOption/Modals/UpdateModal.php

@@ -0,0 +1,36 @@
+<?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\ProxmoxVps\App\UI\FirewallOption\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\FirewallOption\Forms\UpdateForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\BaseEditModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmSuccess;
+
+class UpdateModal extends BaseEditModal implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('updateModal');
+        $this->addForm(new UpdateForm());
+    }
+
+}

+ 81 - 0
app/UI/FirewallOption/Pages/FirewallOption.php

@@ -0,0 +1,81 @@
+<?php
+/* * ********************************************************************
+*  ProxmoxVPS Product developed. (26.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\ProxmoxVps\App\UI\FirewallOption\Pages;
+
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\FirewallOption\Buttons\UpdateButton;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Builder\BaseContainer;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AjaxElementInterface;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\ResponseTemplates\RawDataJsonResponse;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+
+/**
+ * Class FirewallOption
+ * @package ModulesGarden\Servers\ProxmoxVps\App\UI\FirewallOption\Pages
+ * @todo - move html code to new class - new Label(some text, Label::DANGER)
+ */
+class FirewallOption extends BaseContainer implements ClientArea, AjaxElementInterface
+{
+    use ApiService;
+    use ProductService;
+
+    protected $id = 'firewallOption';
+    protected $title = 'firewallOption';
+    protected $vueComponent = true;
+    protected $defaultVueComponentName = 'mg-firewallOption';
+
+    public function initContent()
+    {
+        $this->addButton(new UpdateButton());
+    }
+
+    public function returnAjaxData()
+    {
+        $vars = ['enteries' => []];
+        $lang = sl("lang");
+        $allowed = ['log_level_in', 'log_level_out', 'policy_in', 'policy_out'];
+        foreach ($this->vm()->firewallOptions()->read()->toArray() as $key => $value)
+        {
+            if(!in_array($key, $allowed) && !$this->acl()->hasFirewallOption($key)){
+                continue;
+            }
+            if (is_numeric($value) && $value == 1)
+            {
+                $vars['enteries'][$lang->tr($key)] = '<span class="lu-label lu-label--success lu-label--status">' . sl('lang')->tr($value) . '</span>';
+            }
+            else
+            {
+                if (is_numeric($value) && $value == 0)
+                {
+                    $vars['enteries'][$lang->tr($key)] = '<span class="lu-label lu-label--danger lu-label--status">' . sl('lang')->tr($value) . '</span>';
+                }
+                else
+                {
+                    $vars['enteries'][$lang->tr($key)] = $lang->tr($value);
+                }
+            }
+        }
+        return (new RawDataJsonResponse(['data' => $vars]));
+    }
+
+
+}

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

@@ -0,0 +1,81 @@
+<?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\ProxmoxVps\App\UI\FirewallOption\Providers;
+
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\ResponseTemplates\HtmlDataJsonResponse;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\DataProviders\BaseDataProvider;
+
+
+class FirewallOptionProvider extends BaseDataProvider implements ClientArea
+{
+    use ApiService;
+    use ProductService;
+
+    public function read()
+    {
+        $this->data              = $this->vm()->firewallOptions()->read()->getAttributes();
+        $this->data["enable"]    = str_replace(["1", "0"], ["on", "off"], $this->data["enable"]);
+        $this->data["dhcp"]      = str_replace(["1", "0"], ["on", "off"], $this->data["dhcp"]);
+        $this->data["ndp"]       = str_replace(["1", "0"], ["on", "off"], $this->data["ndp"]);
+        $this->data["radv"]      = str_replace(["1", "0"], ["on", "off"], $this->data["radv"]);
+        $this->data["macfilter"] = str_replace(["1", "0"], ["on", "off"], $this->data["macfilter"]);
+        $this->data["ipfilter"]  = str_replace(["1", "0"], ["on", "off"], $this->data["ipfilter"]);
+    }
+
+
+    public function update()
+    {
+        $attributes              = $this->formData;
+        $attributes["enable"]    = str_replace(["on", "off"], ["1", "0"], $attributes["enable"]);
+        if(!$this->acl()->hasFirewallOption("enable")){
+            unset($attributes["enable"] );
+        }
+        $attributes["dhcp"]      = str_replace(["on", "off"], ["1", "0"], $attributes["dhcp"]);
+        if(!$this->acl()->hasFirewallOption("dhcp")){
+            unset($attributes["dhcp"] );
+        }
+        $attributes["ndp"]       = str_replace(["on", "off"], ["1", "0"], $attributes["ndp"]);
+        if(!$this->acl()->hasFirewallOption("ndp")){
+            unset($attributes["ndp"] );
+        }
+        $attributes["radv"]      = str_replace(["on", "off"], ["1", "0"], $attributes["radv"]);
+        if(!$this->acl()->hasFirewallOption("radv")){
+            unset($attributes["radv"] );
+        }
+        $attributes["macfilter"] = str_replace(["on", "off"], ["1", "0"], $attributes["macfilter"]);
+        if(!$this->acl()->hasFirewallOption("macfilter")){
+            unset($attributes["macfilter"] );
+        }
+        $attributes["ipfilter"]  = str_replace(["on", "off"], ["1", "0"], $attributes["ipfilter"]);
+        if(!$this->acl()->hasFirewallOption("ipfilter")){
+            unset($attributes["ipfilter"] );
+        }
+        $this->vm()->firewallOptions()->setAttributes($attributes)->update();
+        return (new HtmlDataJsonResponse())
+            ->setStatusSuccess()
+            ->setMessageAndTranslate('The firewall options has been updated successfully')
+            ->setRefreshTargetIds(["firewallOption"]);
+    }
+
+
+}

+ 5 - 0
app/UI/FirewallOption/Templates/pages/firewallOption.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}>

+ 56 - 0
app/UI/FirewallOption/Templates/pages/firewallOption_components.js

@@ -0,0 +1,56 @@
+mgJsComponentHandler.addDefaultComponent('mg-firewallOption', {
+    template: '#t-mg-firewallOption',
+    props: [
+        'component_id',
+        'component_namespace',
+        'component_index'
+    ],
+    data: function () {
+        return {
+            data: {
+                enteries: {}
+            },
+            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();
+            }
+        }
+    }
+});

+ 48 - 0
app/UI/FirewallOption/Templates/pages/firewallOption_components.tpl

@@ -0,0 +1,48 @@
+<script type="text/x-template" id="t-mg-firewallOption-{$elementId|strtolower}"
+        :component_id="component_id"
+        :component_namespace="component_namespace"
+        :component_index="component_index"
+>
+    <div class="lu-row lu-row--eq-height" id="{$rawObject->getId()}" namespace="{$namespace}"
+         index="{$rawObject->getIndex()}" actionid="{$rawObject->getIndex()}">
+        <div class="lu-col-lg-12">
+            <div class="lu-widget">
+                <div class="lu-widget__header" style="border-bottom: none;">
+                    <div class="lu-widget__top lu-top">
+                        <div class="lu-top__title">
+                            {$MGLANG->absoluteT($title)}
+                        </div>
+
+                        <div class="lu-top__toolbar">
+                            {foreach from=$rawObject->getButtons() key=buttonKey item=buttonValue}
+                                {$buttonValue->getHtml()}
+                            {/foreach}
+                        </div>
+                    </div>
+                </div>
+                <div class="lu-widget__body">
+                    <div class="no-footer">
+                        <div>
+                            <table role="grid" class="lu-table lu-table--mob-collapsible no-footer dtr-column"
+                                   width="100%" v-if="data.enteries">
+                                <tbody>
+                                <tr v-for="(value, key) in data.enteries">
+                                    <td>{{ key }}</td>
+                                    <td v-html="value"></td>
+                                </tr>
+                                </tbody>
+                            </table>
+                            <div v-else style="padding: 15px; text-align: center; border-top: 1px solid #e9ebf0;">
+                                {$MGLANG->absoluteT('noDataAvalible')}
+                            </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>

+ 100 - 0
app/UI/Graph/Pages/CpuGraph.php

@@ -0,0 +1,100 @@
+<?php
+
+/* * ********************************************************************
+ * ProxmoxAddon product developed. (Oct 1, 2018)
+ * *
+ *
+ *  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\ProxmoxVps\App\UI\Graph\Pages;
+
+use ModulesGarden\ProxmoxAddon\Core\Helper\DatabaseCache;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Graphs\Line;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Graphs\Models\DataSet;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+
+class CpuGraph extends Line implements ClientArea, AdminArea
+{
+
+    use GraphData;
+    protected $id = 'cpuGraph';
+    protected $name = 'cpuGraph';
+    protected $graphSettingsEnabled = true;
+    protected $graphSettingsKey = 'cpuGraphSettings';
+
+    public function initContent()
+    {
+        $selectScope = new Select('timeframe');
+        $selectScope->setAvailableValues($this->chartOptions());
+        $selectScope->setDefaultValue('week');
+        $this->addSettingField($selectScope);
+        //yAxes
+        $this->updateChartScale('yAxes', [
+            [
+                'scaleLabel' => [
+                    'display'     => true,
+                    'labelString' => sl('lang')->tr("Percentage (%)")
+                ],
+                'ticks'      => [
+                    'beginAtZero' => true
+                ],
+            ]]);
+        //Tooltip
+        $this->updateChartOption('tooltips', [
+            'callbacks' => [
+                'label' => 'mgTooltipCpu'
+            ]
+        ]);
+    }
+
+    public function prepareAjaxData()
+    {
+
+        if ($this->configChartsSettings->timeframe)
+        {
+            $this->timeframe = $this->configChartsSettings->timeframe;
+        }
+        $rrdata     = DatabaseCache::loadData(
+            $this->graphSettingsKey.$this->timeframe .$this->getWhmcsParamByKey('serviceid'). '_cacheData', [$this, 'chartData'], 30, true);
+        $labels     = [];
+        $dataSets   = [
+            'cpu'   => []
+        ];
+        $dateFormat = in_array($this->timeframe, ['hour', 'day']) ? "H:i:s" : "Y-m-d";
+        foreach ($rrdata as $rrd)
+        {
+            $labels[]           = date($dateFormat, $rrd['time']);
+            $dataSets['cpu'][]  = (isset($rrd['cpu']) ? (float)$rrd['cpu'] : 0) * 100;
+        }
+
+        //Labels
+        $this->setLabels($labels);
+        //CPU Usage
+        $lang    = sl('lang');
+        $dataSet = new DataSet();
+        $dataSet->setTitle($lang->tr('CPU Usage'))
+            ->setData($dataSets['cpu'])
+            ->setConfigurationDataSet([
+                "backgroundColor" => "rgba(174, 198, 57, 0.79)",
+                "borderColor"     => "rgba(174, 198, 57, 1)"
+            ]);
+        $this->addDataSet($dataSet);
+    }
+
+
+}

+ 108 - 0
app/UI/Graph/Pages/DiskGraph.php

@@ -0,0 +1,108 @@
+<?php
+
+/* * ********************************************************************
+ * ProxmoxAddon product developed. (Oct 1, 2018)
+ * *
+ *
+ *  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\ProxmoxVps\App\UI\Graph\Pages;
+
+use ModulesGarden\ProxmoxAddon\Core\Helper\DatabaseCache;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Graphs\Line;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Graphs\Models\DataSet;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+
+
+class DiskGraph extends Line implements ClientArea, AdminArea
+{
+    use GraphData;
+    protected $id = 'diskGraph';
+    protected $name = 'diskkGraph';
+    protected $graphSettingsEnabled = true;
+    protected $graphSettingsKey = 'diskGraphSettings';
+
+    public function initContent()
+    {
+        $selectScope = new Select('timeframe');
+        $selectScope->setAvailableValues($this->chartOptions());
+        $selectScope->setDefaultValue('week');
+        $this->addSettingField($selectScope);
+        $this->updateChartScale('yAxes', [
+            [
+                'scaleLabel' => [
+                    'display'     => true,
+                    'labelString' => sl('lang')->tr('Bytes/s')
+                ],
+                'ticks'      => [
+                    'callback' => 'mgBytesToSize'
+                ],
+            ]]);
+        $this->updateChartOption('tooltips', [
+            'callbacks' => [
+                'label' => 'mgTooltipCallbackForDisk'
+            ]
+        ]);
+
+    }
+
+    public function prepareAjaxData()
+    {
+        if ($this->configChartsSettings->timeframe)
+        {
+            $this->timeframe = $this->configChartsSettings->timeframe;
+        }
+        $rrdata     = DatabaseCache::loadData(
+            $this->graphSettingsKey .$this->timeframe .$this->getWhmcsParamByKey('serviceid'). '_cacheData', [$this, 'chartData'], 30, true);
+        $labels     = [];
+        $dataSets   = [
+            'diskread'  => [],
+            'diskwrite' => [],
+        ];
+        $dateFormat = in_array($this->timeframe, ['hour', 'day']) ? "H:i:s" : "Y-m-d";
+        foreach ($rrdata as $rrd)
+        {
+            $labels[]                   = date($dateFormat, $rrd['time']);
+            $dataSets['diskread'][]     = (isset($rrd['diskread']) ? $rrd['diskread'] : 0);
+            $dataSets['diskwrite'][]    = (isset($rrd['diskwrite']) ? $rrd['diskwrite'] : 0);
+        }
+
+        //Labels
+        $this->setLabels($labels);
+        //Memory
+        $lang    = sl('lang');
+        $dataSet = new DataSet();
+        $dataSet->setTitle($lang->tr('Disk Read'))
+            ->setData($dataSets['diskread'])
+            ->setConfigurationDataSet([
+                "backgroundColor" => 'rgba(174, 198, 57, 0.79)',
+                "borderColor"     => 'rgba(174, 198, 57, 1)',
+            ]);
+        $this->addDataSet($dataSet);
+        //Total
+        $dataSet = new DataSet();
+        $dataSet->setTitle($lang->tr('Disk Write'))
+            ->setData($dataSets['diskwrite'])
+            ->setConfigurationDataSet([
+                "backgroundColor" => 'rgba(39, 133, 134, 0.91)',
+                "borderColor"     => 'rgba(39, 133, 134, 1)',
+            ]);
+        $this->addDataSet($dataSet);
+    }
+
+}

+ 62 - 0
app/UI/Graph/Pages/GraphData.php

@@ -0,0 +1,62 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Graph\Pages;
+
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\ProxmoxAddon\Core\Models\ModuleSettings\Model;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+
+trait GraphData
+{
+    use ProductService;
+    use ApiService;
+
+    protected $timeframe = "week";
+
+    public function chartData()
+    {
+        $request = [
+            "timeframe" => $this->timeframe,
+            "cf"        => "MAX",
+        ];
+        return $this->vm()->rrdData($request);
+    }
+
+    protected function chartOptions()
+    {
+        $registrationDate = new \DateTime($this->getWhmcsParamByKey('model')->registrationDate->format("Y-m-d"));
+        $options          = ['hour' => sl("lang")->tr("Hour")];
+        $dnow             = new \DateTime();
+        $dDiff            = $registrationDate->diff($dnow);
+        if ($dDiff->days >= 1)
+        {
+            $options['day'] = sl("lang")->tr("Day");
+        }
+        if ($dDiff->days >= 7)
+        {
+            $options['week'] = sl("lang")->tr("Week");
+        }
+        if ($dDiff->days >= 30)
+        {
+            $options['month'] = sl("lang")->tr("Month");
+        }
+        if ($dDiff->y >= 1)
+        {
+            $options['year'] = sl("lang")->tr("year");
+        }
+        return $options;
+    }
+
+    protected function loadSettings()
+    {
+        $this->configChartsSettings = json_decode(Model::where('setting', $this->graphSettingsKey)->first()->value);
+
+        if ($this->configChartsSettings)
+        {
+            $this->setGraphFilterInfo(null, $this->configChartsSettings->start, $this->configChartsSettings->end);
+        }
+
+        return $this;
+    }
+}

+ 106 - 0
app/UI/Graph/Pages/MemoryGraph.php

@@ -0,0 +1,106 @@
+<?php
+
+/* * ********************************************************************
+ * ProxmoxAddon product developed. (Oct 1, 2018)
+ * *
+ *
+ *  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\ProxmoxVps\App\UI\Graph\Pages;
+
+use ModulesGarden\ProxmoxAddon\Core\Helper\DatabaseCache;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Graphs\Line;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Graphs\Models\DataSet;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+
+
+class MemoryGraph extends Line implements ClientArea, AdminArea
+{
+    use GraphData;
+    protected $id = 'memoryGraph';
+    protected $name = 'memoryGraph';
+    protected $graphSettingsEnabled = true;
+    protected $graphSettingsKey = 'memoryGraphSettings';
+
+    public function initContent()
+    {
+        $selectScope = new Select('timeframe');
+        $selectScope->setAvailableValues($this->chartOptions());
+        $selectScope->setDefaultValue('week');
+        $this->addSettingField($selectScope);
+        $this->updateChartScale('yAxes', [
+            [
+                'scaleLabel' => [
+                    'display'     => true,
+                    'labelString' => sl('lang')->tr('Bytes/s')
+                ],
+                'ticks'      => [
+                    'callback' => 'mgBytesToSize'
+                ],
+            ]]);
+        $this->updateChartOption('tooltips', [
+            'callbacks' => [
+                'label' => 'mgTooltipCallbackForMemory'
+            ]
+        ]);
+
+    }
+
+    public function prepareAjaxData()
+    {
+        if ($this->configChartsSettings->timeframe)
+        {
+            $this->timeframe = $this->configChartsSettings->timeframe;
+        }
+        $rrdata     = DatabaseCache::loadData(
+            $this->graphSettingsKey .$this->timeframe .$this->getWhmcsParamByKey('serviceid'). '_cacheData', [$this, 'chartData'], 30, true);
+        $labels     = [];
+        $dataSets   = [
+            'maxmem'   => [],
+        ];
+        $dateFormat = in_array($this->timeframe, ['hour', 'day']) ? "H:i:s" : "Y-m-d";
+        foreach ($rrdata as $rrd)
+        {
+            $labels[]               = date($dateFormat, $rrd['time']);
+            $dataSets['mem'][]      = isset($rrd['mem']) ? $rrd['mem'] : 0;
+            $dataSets['maxmem'][]   = isset($rrd['maxmem']) ? $rrd['maxmem'] : 0;
+        }
+
+        //Labels
+        $this->setLabels($labels);
+        //Memory
+        $lang    = sl('lang');
+        $dataSet = new DataSet();
+        $dataSet->setTitle($lang->tr('Memory Usage'))
+            ->setData($dataSets['mem'])
+            ->setConfigurationDataSet([
+                "backgroundColor" => 'rgba(39, 133, 134, 0.91)',
+                "borderColor"     => 'rgba(39, 133, 134, 1)',
+            ]);
+        $this->addDataSet($dataSet);
+        //Total
+        $dataSet = new DataSet();
+        $dataSet->setTitle($lang->tr('Total'))
+            ->setData($dataSets['maxmem'])
+            ->setConfigurationDataSet([
+                "backgroundColor" => 'rgba(174, 198, 57, 0.79)',
+                "borderColor"     => 'rgba(174, 198, 57, 1)',
+            ]);
+        $this->addDataSet($dataSet);
+    }
+}

+ 109 - 0
app/UI/Graph/Pages/NetworkGraph.php

@@ -0,0 +1,109 @@
+<?php
+
+/* * ********************************************************************
+ * ProxmoxAddon product developed. (Oct 1, 2018)
+ * *
+ *
+ *  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\ProxmoxVps\App\UI\Graph\Pages;
+
+use ModulesGarden\ProxmoxAddon\Core\Helper\DatabaseCache;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Graphs\Line;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Graphs\Models\DataSet;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+
+
+class NetworkGraph extends Line implements ClientArea, AdminArea
+{
+    use GraphData;
+    protected $id = 'networkGraph';
+    protected $name = 'networkGraph';
+    protected $graphSettingsEnabled = true;
+    protected $graphSettingsKey = 'networkGraphSettings';
+
+    public function initContent()
+    {
+        $selectScope = new Select('timeframe');
+        $selectScope->setAvailableValues($this->chartOptions());
+        $selectScope->setDefaultValue('week');
+        $this->addSettingField($selectScope);
+        $this->updateChartScale('yAxes', [
+            [
+                'scaleLabel' => [
+                    'display'     => true,
+                    'labelString' => sl('lang')->tr('Bytes/s')
+                ],
+                'ticks'      => [
+                    'callback' => 'mgBytesToSize'
+                ],
+            ]]);
+        $this->updateChartOption('tooltips', [
+            'callbacks' => [
+                'label' => 'mgTooltipCallbackForNet'
+            ]
+        ]);
+
+    }
+
+    public function prepareAjaxData()
+    {
+        if ($this->configChartsSettings->timeframe)
+        {
+            $this->timeframe = $this->configChartsSettings->timeframe;
+        }
+        $rrdata     = DatabaseCache::loadData(
+            $this->graphSettingsKey.$this->timeframe  .$this->getWhmcsParamByKey('serviceid'). '_cacheData', [$this, 'chartData'], 30, true);
+        $labels     = [];
+        $dataSets   = [
+            'netin'     => [],
+            'netout'    => [],
+        ];
+        $dateFormat = in_array($this->timeframe, ['hour', 'day']) ? "H:i:s" : "Y-m-d";
+
+        foreach ($rrdata as $rrd)
+        {
+            $labels[]               = date($dateFormat, $rrd['time']);
+            $dataSets['netin'][]    = isset($rrd['netin']) ? (float)$rrd['netin'] : 0;
+            $dataSets['netout'][]   = isset($rrd['netout']) ? (float)$rrd['netout'] : 0;
+        }
+
+
+        //Labels
+        $this->setLabels($labels);
+        //Memory
+        $lang    = sl('lang');
+        $dataSet = new DataSet();
+        $dataSet->setTitle($lang->tr('Net In'))
+            ->setData($dataSets['netin'])
+            ->setConfigurationDataSet([
+                "backgroundColor" => 'rgba(174, 198, 57, 0.79)',
+                "borderColor"     => 'rgba(174, 198, 57, 1)',
+            ]);
+        $this->addDataSet($dataSet);
+        //Total
+        $dataSet = new DataSet();
+        $dataSet->setTitle($lang->tr('Net Out'))
+            ->setData($dataSets['netout'])
+            ->setConfigurationDataSet([
+                "backgroundColor" => 'rgba(39, 133, 134, 0.91)',
+                "borderColor"     => 'rgba(39, 133, 134, 1)',
+            ]);
+        $this->addDataSet($dataSet);
+    }
+}

+ 41 - 0
app/UI/Home/Buttons/MigrateButton.php

@@ -0,0 +1,41 @@
+<?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\ProxmoxVps\App\UI\Home\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Home\Modals\MigrateModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\Helper\BuildUrl;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonModal;
+
+class MigrateButton extends ButtonModal implements AdminArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('migrateButton');
+        $this->setIcon('lu-zmdi lu-zmdi-power');
+        $this->initLoadModalAction(new MigrateModal());
+    }
+
+    public function getImageUrl()
+    {
+        return BuildUrl::getAppAssetsURL() . DS . 'img' . DS . 'buttons' . DS . 'reinstall.png';
+    }
+}

+ 42 - 0
app/UI/Home/Buttons/RebootButton.php

@@ -0,0 +1,42 @@
+<?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\ProxmoxVps\App\UI\Home\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Home\Modals\RebootModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\Helper\BuildUrl;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonModal;
+
+class RebootButton extends ButtonModal implements ClientArea, AdminArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('rebootButton');
+        $this->setIcon('lu-zmdi lu-zmdi-power');
+        $this->initLoadModalAction(new RebootModal());
+    }
+
+    public function getImageUrl()
+    {
+        return BuildUrl::getAppAssetsURL() . DS . 'img' . DS . 'buttons' . DS . $this->name . '.png';
+    }
+}

+ 83 - 0
app/UI/Home/Buttons/RedirectButton.php

@@ -0,0 +1,83 @@
+<?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\ProxmoxVps\App\UI\Home\Buttons;
+
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonRedirect;
+
+class RedirectButton extends ButtonRedirect implements ClientArea, AdminArea
+{
+
+    protected $id = 'redirectButton';
+    protected $class = ['lu-tile lu-tile--btn'];
+    protected $icon = 'lu-zmdi lu-zmdi-plus';
+    protected $title = 'redirectButton';
+    protected $imageUrl = null;
+    protected $htmlAttributes = [
+        'data-toggle' => 'lu-tooltip',
+    ];
+
+    public function afterInitContent()
+    {
+
+    }
+
+    public function initContent()
+    {
+
+    }
+
+    /**
+     * @return string
+     */
+    public function getHref()
+    {
+        return $this->getHtmlAttribute("href");
+    }
+
+    /**
+     * @param string $href
+     */
+    public function setHref($href)
+    {
+        $this->addHtmlAttribute("href", $href);
+        return $this;
+    }
+
+    /**
+     * @return null
+     */
+    public function getImageUrl()
+    {
+        return $this->imageUrl;
+    }
+
+    /**
+     * @param null $imageUrl
+     */
+    public function setImageUrl($imageUrl)
+    {
+        $this->imageUrl = $imageUrl;
+    }
+
+}

+ 42 - 0
app/UI/Home/Buttons/ShutdownButton.php

@@ -0,0 +1,42 @@
+<?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\ProxmoxVps\App\UI\Home\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Home\Modals\ShutdownModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\Helper\BuildUrl;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonModal;
+
+class ShutdownButton extends ButtonModal implements ClientArea, AdminArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('shutdownButton');
+        $this->setIcon('lu-zmdi lu-zmdi-power');
+        $this->initLoadModalAction(new ShutdownModal());
+    }
+
+    public function getImageUrl()
+    {
+        return BuildUrl::getAppAssetsURL() . DS . 'img' . DS . 'buttons' . DS . $this->name . '.png';
+    }
+}

+ 42 - 0
app/UI/Home/Buttons/StartButton.php

@@ -0,0 +1,42 @@
+<?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\ProxmoxVps\App\UI\Home\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Home\Modals\StartModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\Helper\BuildUrl;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonModal;
+
+class StartButton extends ButtonModal implements ClientArea, AdminArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('startButton');
+        $this->setIcon('lu-zmdi lu-zmdi-power');
+        $this->initLoadModalAction(new StartModal());
+    }
+
+    public function getImageUrl()
+    {
+        return BuildUrl::getAppAssetsURL() . DS . 'img' . DS . 'buttons' . DS . $this->name . '.png';
+    }
+}

+ 42 - 0
app/UI/Home/Buttons/StopButton.php

@@ -0,0 +1,42 @@
+<?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\ProxmoxVps\App\UI\Home\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Home\Modals\StopModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\Helper\BuildUrl;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonModal;
+
+class StopButton extends ButtonModal implements ClientArea, AdminArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('stopButton');
+        $this->setIcon('lu-zmdi lu-zmdi-power');
+        $this->initLoadModalAction(new StopModal());
+    }
+
+    public function getImageUrl()
+    {
+        return BuildUrl::getAppAssetsURL() . DS . 'img' . DS . 'buttons' . DS . $this->name . '.png';
+    }
+}

+ 54 - 0
app/UI/Home/Forms/MigrateForm.php

@@ -0,0 +1,54 @@
+<?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\ProxmoxVps\App\UI\Home\Forms;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Home\Providers\MigrateProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Helpers\AlertTypesConstants;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+
+class MigrateForm extends BaseForm implements AdminArea
+{
+    public function initContent()
+    {
+        $this->initIds('migrateForm');
+        $this->setFormType('update');
+        $this->setProvider(new MigrateProvider());
+        $this->setInternalAlertMessage('confirmMigrate');
+        $this->setInternalAlertMessageType(AlertTypesConstants::DANGER);
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['update'];
+    }
+
+    private function initFields()
+    {
+        //target
+        $this->addField(new Select('target'));
+        //online
+        $this->addField((new Switcher('online'))->setDescription('tip'));
+    }
+}

+ 42 - 0
app/UI/Home/Forms/RebootForm.php

@@ -0,0 +1,42 @@
+<?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\ProxmoxVps\App\UI\Home\Forms;
+
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Home\Providers\StatusProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+
+class RebootForm extends BaseForm implements ClientArea
+{
+    public function initContent()
+    {
+        $this->initIds('rebootForm');
+        $this->setFormType('reboot');
+        $this->setProvider(new StatusProvider());
+        $this->setConfirmMessage('conforimReboot');
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['reboot'];
+    }
+}

+ 42 - 0
app/UI/Home/Forms/ShutdownForm.php

@@ -0,0 +1,42 @@
+<?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\ProxmoxVps\App\UI\Home\Forms;
+
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Home\Providers\StatusProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+
+class ShutdownForm extends BaseForm implements ClientArea
+{
+    public function initContent()
+    {
+        $this->initIds('shutdownForm');
+        $this->setFormType('shutdown');
+        $this->setProvider(new StatusProvider());
+        $this->setConfirmMessage('conforimShutdown');
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['shutdown'];
+    }
+}

+ 42 - 0
app/UI/Home/Forms/StartForm.php

@@ -0,0 +1,42 @@
+<?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\ProxmoxVps\App\UI\Home\Forms;
+
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Home\Providers\StatusProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+
+class StartForm extends BaseForm implements ClientArea
+{
+    public function initContent()
+    {
+        $this->initIds('startForm');
+        $this->setFormType('start');
+        $this->setProvider(new StatusProvider());
+        $this->setConfirmMessage('conforimStart');
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['start'];
+    }
+}

+ 42 - 0
app/UI/Home/Forms/StopForm.php

@@ -0,0 +1,42 @@
+<?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\ProxmoxVps\App\UI\Home\Forms;
+
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Home\Providers\StatusProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+
+class StopForm extends BaseForm implements ClientArea
+{
+    public function initContent()
+    {
+        $this->initIds('stopForm');
+        $this->setFormType('stop');
+        $this->setProvider(new StatusProvider());
+        $this->setConfirmMessage('conforimStop');
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['stop'];
+    }
+}

+ 36 - 0
app/UI/Home/Modals/MigrateModal.php

@@ -0,0 +1,36 @@
+<?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\ProxmoxVps\App\UI\Home\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Home\Forms\MigrateForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmDanger;
+
+class MigrateModal extends ModalConfirmDanger implements AdminArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('migrateModal');
+        $this->setModalSizeLarge();
+        $this->addForm(new  MigrateForm());
+    }
+
+}

+ 36 - 0
app/UI/Home/Modals/RebootModal.php

@@ -0,0 +1,36 @@
+<?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\ProxmoxVps\App\UI\Home\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Home\Forms\RebootForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmDanger;
+
+class RebootModal extends ModalConfirmDanger implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('rebootModal');
+        $this->setModalSizeLarge();
+        $this->addForm(new RebootForm());
+    }
+
+}

+ 36 - 0
app/UI/Home/Modals/ShutdownModal.php

@@ -0,0 +1,36 @@
+<?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\ProxmoxVps\App\UI\Home\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Home\Forms\ShutdownForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmDanger;
+
+class ShutdownModal extends ModalConfirmDanger implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('shutdownModal');
+        $this->setModalSizeLarge();
+        $this->addForm(new ShutdownForm());
+    }
+
+}

+ 36 - 0
app/UI/Home/Modals/StartModal.php

@@ -0,0 +1,36 @@
+<?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\ProxmoxVps\App\UI\Home\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Home\Forms\StartForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\BaseModal;
+
+class StartModal extends BaseModal implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('startModal');
+        $this->setModalSizeLarge();
+        $this->addForm(new StartForm());
+    }
+
+}

+ 36 - 0
app/UI/Home/Modals/StopModal.php

@@ -0,0 +1,36 @@
+<?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\ProxmoxVps\App\UI\Home\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Home\Forms\StopForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmDanger;
+
+class StopModal extends ModalConfirmDanger implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('stopModal');
+        $this->setModalSizeLarge();
+        $this->addForm(new StopForm());
+    }
+
+}

+ 108 - 0
app/UI/Home/Pages/ServiceActions.php

@@ -0,0 +1,108 @@
+<?php
+/* * ********************************************************************
+*  ProxmoxVPS Product developed. (26.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\ProxmoxVps\App\UI\Home\Pages;
+
+
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\UrlService;
+use ModulesGarden\Servers\ProxmoxVps\App\Helpers\UrlServiceHelper;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Home\Buttons\MigrateButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Home\Buttons\RebootButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Home\Buttons\RedirectButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Home\Buttons\ShutdownButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Home\Buttons\StartButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Home\Buttons\StopButton;
+use ModulesGarden\Servers\ProxmoxVps\Core\Helper\BuildUrl;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Builder\BaseContainer;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\isAdmin;
+
+
+class ServiceActions extends BaseContainer implements ClientArea, AdminArea
+{
+    use ProductService;
+    use ApiService;
+
+    public function initContent()
+    {
+        $this->initIds('serviceActions');
+        //Start
+        if (isAdmin() || $this->configuration()->isPermissionStart())
+        {
+            $this->addButton(new StartButton("startButton"));
+        }
+        //Reboot
+        if (isAdmin() || $this->configuration()->isPermissionReboot())
+        {
+            $this->addButton(new RebootButton("rebootButon"));
+        }
+        //Stop
+        if (isAdmin() || $this->configuration()->isPermissionStop())
+        {
+            $this->addButton(new StopButton("stopButton"));
+        }
+        //Shutdown
+        if (isAdmin() || $this->configuration()->isPermissionShutdown())
+        {
+            $this->addButton(new ShutdownButton("shutdownButton"));
+        }
+        //noVNC
+
+        $serviceUrl = new UrlServiceHelper();
+        if (isAdmin() || $this->configuration()->isPermissionNovnc())
+        {
+
+            $redirectButton = new RedirectButton('novnc');
+            $redirectButton->setImageUrl(BuildUrl::getAppAssetsURL() . DS . 'img' . DS . 'buttons' . DS . 'novnc.png');
+            $redirectButton->addHtmlAttribute("onclick", "window.open('{$serviceUrl->getNoVncConsoleUrl()}', '', 'width=900,height=700'); return false;");
+            $redirectButton->setHref("#");
+            $this->addButton($redirectButton);
+        }
+        //Spice Console
+        if (isAdmin() || $this->configuration()->isPermissionSpice())
+        {
+            $redirectButton = new RedirectButton('spice');
+            $redirectButton->setImageUrl(BuildUrl::getAppAssetsURL() . DS . 'img' . DS . 'buttons' . DS . 'spice.png');
+            $redirectButton->setHref($serviceUrl->getSpiceConsoleUrl());
+           if(!$this->hasVm()  || !$this->vm()->hasSpiceproxy()){
+               $redirectButton->addHtmlAttribute("disabled",true);
+           }
+            $this->addButton($redirectButton);
+        }
+        //Xterm.js Console
+        if (isAdmin() || $this->configuration()->isPermissionXtermjs())
+        {
+            $redirectButton = new RedirectButton('xtermjs');
+            $redirectButton->setImageUrl(BuildUrl::getAppAssetsURL() . DS . 'img' . DS . 'buttons' . DS . 'xtermjs.png');
+            $redirectButton->addHtmlAttribute("onclick", "window.open('{$serviceUrl->getXTermConsoleUrl()}', '', 'width=900,height=700'); return false;");
+            $this->addButton($redirectButton);
+        }
+        //Migration
+        if (isAdmin())
+        {
+            $this->addButton(new MigrateButton());
+        }
+    }
+
+
+}

+ 107 - 0
app/UI/Home/Pages/ServiceManagement.php

@@ -0,0 +1,107 @@
+<?php
+/* * ********************************************************************
+*  ProxmoxVPS Product developed. (26.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\ProxmoxVps\App\UI\Home\Pages;
+
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\UrlService;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Home\Buttons\RedirectButton;
+use ModulesGarden\Servers\ProxmoxVps\Core\Helper\BuildUrl;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Builder\BaseContainer;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\isAdmin;
+
+
+class ServiceManagement extends BaseContainer implements ClientArea, AdminArea
+{
+    use ProductService;
+    /**
+     * @var UrlService
+     */
+    private $urlService;
+
+    public function initContent()
+    {
+        $this->initIds('serviceManagement');
+        //Url Service
+        $this->urlService = new UrlService();
+        //Reinstall
+        if (isAdmin() || $this->configuration()->isPermissionReinstall())
+        {
+            $this->addServiceButton('reinstall');
+        }
+        //Backups
+        if (isAdmin() || $this->configuration()->isPermissionBackup() || $this->configuration()->isPermissionBackupJob())
+        {
+            $this->addServiceButton('backup');
+        }
+        //Backup Jobs
+        if (isAdmin() || $this->configuration()->isPermissionBackupJob())
+        {
+            $this->addServiceButton('backupJob');
+        }
+        //Graphs
+        if (isAdmin() || $this->configuration()->isPermissionGraph())
+        {
+            $this->addServiceButton('graph');
+        }
+        //Task History
+        if (isAdmin() || $this->configuration()->isPermissionTaskHistory())
+        {
+            $this->addServiceButton('taskHistory');
+        }
+        //Network
+        if (isAdmin() || $this->configuration()->isPermissionNetwork())
+        {
+            $this->addServiceButton('network');
+        }
+        //Snapshots
+        if (isAdmin() || $this->configuration()->isPermissionSnapshot())
+        {
+            $this->addServiceButton('snapshot');
+        }
+        //Firewall
+        if (isAdmin() || $this->configuration()->isPermissionFirewall())
+        {
+            $this->addServiceButton('firewall');
+        }
+        //Firewall Options
+        if (isAdmin() || $this->configuration()->isPermissionFirewallOption())
+        {
+            $this->addServiceButton('firewallOption');
+        }
+        //Disks
+        if (isAdmin() || $this->configuration()->isPermissionDisk())
+        {
+            $this->addServiceButton('disk');
+        }
+    }
+
+    private function addServiceButton($id)
+    {
+        $rd = new RedirectButton($id);
+        $rd->setHref($this->urlService->getUrl($id));
+        $rd->setImageUrl(BuildUrl::getAppAssetsURL() . DS . 'img' . DS . 'buttons' . DS . $id . '.png');
+        $this->addButton($rd);
+    }
+
+
+}

+ 89 - 0
app/UI/Home/Pages/VpsBuild.php

@@ -0,0 +1,89 @@
+<?php
+
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Home\Pages;
+
+
+use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\CloneQemuJob;
+use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\CreateLxcJob;
+use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\CreateQemuJob;
+use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\LoadBalancer\UpgradeVmJob;
+use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\MigrateVmJob;
+use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\Reinstall\CreateVmJob;
+use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\Reinstall\RestoreVm;
+use ModulesGarden\ProxmoxAddon\App\Models\Job;
+use ModulesGarden\Servers\ProxmoxVps\App\Helpers\UrlServiceHelper;
+use ModulesGarden\Servers\ProxmoxVps\App\Http\Client\BaseClientController;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Builder\BaseContainer;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AjaxElementInterface;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\ResponseTemplates\RawDataJsonResponse;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+
+class VpsBuild extends BaseContainer implements ClientArea, AdminArea, AjaxElementInterface
+{
+    use  BaseClientController;
+
+    protected $id = 'vpsBuild';
+    protected $title = 'vpsBuild';
+    protected $name = 'vpsBuild';
+    protected $vueComponent = true;
+    protected $defaultVueComponentName = 'mg-vpsBuild';
+
+    public function initContent()
+    {
+        if ($this->isVmCreate())
+        {
+            $this->customTplVars['warning'] = sl("lang")->abtr('Creating VM in progress. Please try again later.');
+        }
+        else if ($this->isVmReinstall()) {
+                $this->customTplVars['warning'] = sl("lang")->abtr('Rebuild VM in progress. Please try again later.');
+        } else if ($this->isVmUpgrade()){
+            $this->customTplVars['warning'] = sl("lang")->abtr('Upgrading VM in progress. Please try again later.');
+        }else if(!$this->getWhmcsCustomField("vmid")){
+            $this->customTplVars['warning'] = sl("lang")->abtr('Custom field VMID is empty.');
+        }
+    }
+
+    private function isVmCreate()
+    {
+        $jobs = [
+            CloneQemuJob::class,
+            CreateQemuJob::class,
+            CreateLxcJob::class,
+        ];
+        return Job::waiting()->ofHostingId($this->getWhmcsParamByKey("serviceid"))->ofJobs($jobs)->count();
+    }
+
+    private function isVmReinstall()
+    {
+        $jobs = [
+            CreateVmJob::class
+        ];
+        return Job::waiting()->ofHostingId($this->getWhmcsParamByKey("serviceid"))->ofJobs($jobs)->count();
+    }
+
+    private function isVmUpgrade()
+    {
+        $jobs = [
+            MigrateVmJob::class,
+            \ModulesGarden\ProxmoxAddon\App\Jobs\Vps\RestoreVm::class,
+            UpgradeVmJob::class
+        ];
+        return Job::waiting()->ofHostingId($this->getWhmcsParamByKey("serviceid"))->ofJobs($jobs)->count();
+    }
+
+    public function returnAjaxData()
+    {
+        $vars                = [];
+        $response = new RawDataJsonResponse();
+        if($this->isVpsCreated()){
+            $response->setCallBackFunction('mgRedirect');
+            $response->addData('redirectUrl' , ( new UrlServiceHelper())->home());
+
+        }
+        return  $response;
+    }
+}

+ 81 - 0
app/UI/Home/Providers/MigrateProvider.php

@@ -0,0 +1,81 @@
+<?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\ProxmoxVps\App\UI\Home\Providers;
+
+use MGProvision\Proxmox\v2\repository\NodeRepository;
+use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\MigrateVmJob;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\ResponseTemplates\HtmlDataJsonResponse;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\DataProviders\BaseDataProvider;
+use function ModulesGarden\ProxmoxAddon\Core\Helper\queue;
+use ModulesGarden\ProxmoxAddon\Core\Queue\Models\Job;
+
+class MigrateProvider extends BaseDataProvider implements AdminArea
+{
+    use ProductService;
+    use ApiService;
+
+    public function read()
+    {
+        $nodeRepository = new NodeRepository();
+        $nodeRepository->setApi($this->api());
+        $nodeRepository->findOnline(true);
+        foreach ($nodeRepository->fetch() as $item)
+        {
+            if ($item->getNode() == $this->vm()->getNode())
+            {
+                continue;
+            }
+            $this->availableValues['target'][$item->getNode()] =  $item->getNode();
+        }
+        if ($this->vm()->isRunning())
+        {
+            $this->data['online'] = "on";
+        }
+    }
+
+    public function update()
+    {
+        $attributes = [
+            "targetNode" => $this->formData['target'],
+            "online"     => $this->formData['online'] == "on" ? 1 : 0
+        ];
+        if (Job::where("job", MigrateVmJob::class. '@handle')->whereIn("status", ['waiting', "running", ""])
+                                                  ->where("rel_id", $this->getWhmcsParamByKey("serviceid"))
+                                                  ->where("rel_type", "hosting")->count())
+        {
+            return (new HtmlDataJsonResponse())
+                ->setStatusError()
+                ->setMessageAndTranslate("Task 'MigrateVm' already exist");
+        }
+        queue(MigrateVmJob::class, $attributes, null, "hosting", $this->getWhmcsParamByKey("serviceid"));
+        sl("lang")-> addReplacementConstant("vmid",$this->vm()->getVmid())-> addReplacementConstant("node", $this->formData['target']);
+        return (new HtmlDataJsonResponse())
+            ->setStatusSuccess()
+            ->setMessageAndTranslate("Starting migration of VM :vmid: to :node:")
+            ->addData('refreshState', 'serverinformationTable')
+            ->setCallBackFunction('refreshTable');
+    }
+
+
+}

+ 103 - 0
app/UI/Home/Providers/StatusProvider.php

@@ -0,0 +1,103 @@
+<?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\ProxmoxVps\App\UI\Home\Providers;
+
+use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\RebootVmJob;
+use ModulesGarden\ProxmoxAddon\App\Models\Job;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\HighAvailabilityClusterService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\ResponseTemplates\HtmlDataJsonResponse;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\DataProviders\BaseDataProvider;
+use function ModulesGarden\ProxmoxAddon\Core\Helper\queue;
+
+
+class StatusProvider extends BaseDataProvider implements ClientArea
+{
+    use ProductService;
+    use ApiService;
+
+    public function start()
+    {
+        $this->vm()->start();
+        return (new HtmlDataJsonResponse())
+            ->setStatusSuccess()
+            ->setMessageAndTranslate('The container has been booted successfully')
+            ->addData('refreshState', 'serverinformationTable')
+            ->addRefreshTargetId('serviceInformationDataTable');
+    }
+
+    public function reboot()
+    {
+        $ha = new HighAvailabilityClusterService();
+        if ($ha->exist())
+        {
+            //reboot
+            if (!Job::waiting()->ofJob(RebootVmJob::class)->ofHostingId($this->getWhmcsParamByKey("serviceid"))->count())
+            {
+                queue(RebootVmJob::class, [], null, "hosting", $this->getWhmcsParamByKey("serviceid"));
+            }
+            return (new HtmlDataJsonResponse())
+                ->setStatusSuccess()
+                ->setMessageAndTranslate('Rebooting container in progress')
+                ->addData('refreshState', 'serverinformationTable')
+                ->addRefreshTargetId('serviceInformationDataTable');
+        }
+        else
+        {
+            $this->vm()->restart();
+            return (new HtmlDataJsonResponse())
+                ->setStatusSuccess()
+                ->setMessageAndTranslate('The container has been rebooted successfully')
+                ->addData('refreshState', 'serverinformationTable')
+                ->addRefreshTargetId('serviceInformationDataTable');
+        }
+
+    }
+
+    public function stop()
+    {
+        $this->vm()->stop();
+        return (new HtmlDataJsonResponse())
+            ->setStatusSuccess()
+            ->setMessageAndTranslate('The container has been stopped successfully')
+            ->addData('refreshState', 'serverinformationTable')
+            ->addRefreshTargetId('serviceInformationDataTable');
+    }
+
+    public function shutdown()
+    {
+        $this->vm()->shutdown();
+        return (new HtmlDataJsonResponse())
+            ->setStatusSuccess()
+            ->setMessageAndTranslate('The container has been shut down successfully')
+            ->addData('refreshState', 'serverinformationTable')
+            ->addRefreshTargetId('serviceInformationDataTable');
+    }
+
+    public function read()
+    {
+    }
+
+    public function update()
+    {
+    }
+}

+ 15 - 0
app/UI/Home/Templates/pages/manageService.tpl

@@ -0,0 +1,15 @@
+<div class="h4 lu-m-b-3x lu-m-t-3x">{$MGLANG->absoluteT('serverCA','home','pagesHeader')}</div>
+<div class="lu-tiles lu-row lu-row--eq-height">
+    {foreach from=$rawObject->getPages() key=controller item=settings}
+        <div class="lu-col-sm-20p" style="justify-content: center;">
+            <a class="lu-tile lu-tile--btn" href="{$rawObject->getURL($controller)}">
+                <div class="lu-i-c-6x">
+                    <img src="{$rawObject->getImageUrl($controller)}"
+                         alt="{$MGLANG->absoluteT('serverCA' , 'iconTitle' ,$controller)}"/>
+                </div>
+                <div class="lu-tile__title">{$MGLANG->absoluteT('serverCA' , 'iconTitle' ,$controller)}</div>
+            </a>
+        </div>
+    {/foreach}
+</div>
+

+ 17 - 0
app/UI/Home/Templates/pages/serviceActions.tpl

@@ -0,0 +1,17 @@
+<div class="h4 lu-m-b-3x lu-m-t-3x">{$MGLANG->absoluteT('serverCA','home','serviceActions')}</div>
+<div class="lu-tiles lu-row lu-row--eq-height">
+    {foreach from=$rawObject->getButtons() key=setting item=dataElement}
+        <div class="lu-col-sm-20p" style="justify-content: center;">
+            <a class="lu-tile lu-tile--btn  {$rawObject->getClasses()}" {foreach $dataElement->getHtmlAttributes() as $aValue} {$aValue@key}="{$aValue}" {/foreach}
+            data-title="{$MGLANG->absoluteT('buttons','actions', $dataElement->getTitle())}">
+            <div class="lu-i-c-6x">
+                <img src="{$dataElement->getImageUrl()}"
+                     alt="{$MGLANG->absoluteT('serverCA' , 'iconTitle' ,$dataElement->getTitle())}"/>
+            </div>
+            <div class="lu-tile__title">{$MGLANG->absoluteT('serverCA' , 'iconTitle' ,$dataElement->getTitle())}</div>
+            </a>
+        </div>
+    {/foreach}
+</div>
+
+

+ 17 - 0
app/UI/Home/Templates/pages/serviceManagement.tpl

@@ -0,0 +1,17 @@
+<div class="h4 lu-m-b-3x lu-m-t-3x">{$MGLANG->absoluteT('serverCA','home',$rawObject->getId())}</div>
+<div class="lu-tiles lu-row lu-row--eq-height">
+    {foreach from=$rawObject->getButtons() key=setting item=dataElement}
+        <div class="lu-col-sm-20p" style="justify-content: center;">
+            <a class="{$dataElement->getClasses()}" href="{$dataElement->getHref()}" {if $dataElement->isRawTitle()}title="{$dataElement->getRawTitle()}"{elseif $dataElement->getTitle()}title="{$MGLANG->T('button', $dataElement->getTitle())}"{/if}  {foreach $dataElement->getHtmlAttributes() as $aValue} {$aValue@key}="{$aValue}"{/foreach}>
+                <div class="lu-i-c-6x">
+                    {if $dataElement->getImageUrl()}
+                        <img src="{$dataElement->getImageUrl()}"
+                             alt="{$MGLANG->absoluteT('serverCA' , 'iconTitle' , $dataElement->getId())}"/>
+                    {/if}
+                </div>
+                <div class="lu-tile__title">{$MGLANG->absoluteT('serverCA' , 'iconTitle' , $dataElement->getId())}</div>
+            </a>
+        </div>
+    {/foreach}
+</div>
+

+ 5 - 0
app/UI/Home/Templates/pages/vpsBuild.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}>

+ 55 - 0
app/UI/Home/Templates/pages/vpsBuild_components.js

@@ -0,0 +1,55 @@
+mgJsComponentHandler.addDefaultComponent('mg-vpsBuild', {
+    template: '#t-mg-vpsBuild',
+    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);
+        /*reload each 30 sec*/
+        setInterval(function(){
+            mgPageControler.vueLoader.refreshingState = ['vpsBuild'];
+            mgPageControler.vueLoader.runRefreshActions();
+        }, 1000*30);
+
+    },
+    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;
+            });
+        },
+        updateMgData: function(toReloadId){
+            if(this.component_id === toReloadId)
+            {
+                this.loadAjaxData();
+            }
+        }
+    }
+});

+ 16 - 0
app/UI/Home/Templates/pages/vpsBuild_components.tpl

@@ -0,0 +1,16 @@
+<script type="text/x-template" id="t-mg-vpsBuild-{$elementId|strtolower}"
+        :component_id="component_id"
+        :component_namespace="component_namespace"
+        :component_index="component_index"
+>
+    <div class="lu-row lu-row--eq-height {$rawObject->getClasses()}" id="{$rawObject->getId()}" namespace="{$namespace}"
+         index="{$rawObject->getIndex()}" actionid="{$rawObject->getIndex()}">
+        <div class="lu-col-lg-12">
+            <div class="alert alert-warning" role="alert">
+                <button type="button" class="close" data-dismiss="alert"></button>
+                <p>{$customTplVars.warning}</p>
+                {if $customTplVars.warningMessage}<p>{$customTplVars.warningMessage}</p>{/if}
+            </div>
+        </div>
+    </div>
+</script>

+ 35 - 0
app/UI/IpAddress/Buttons/CreateButton.php

@@ -0,0 +1,35 @@
+<?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\ProxmoxVps\App\UI\IpAddress\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\IpAddress\Modals\CreateModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonCreate;
+
+class CreateButton extends ButtonCreate implements AdminArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('createButton');
+        $this->initLoadModalAction(new CreateModal());
+    }
+
+}

+ 37 - 0
app/UI/IpAddress/Buttons/DeleteButton.php

@@ -0,0 +1,37 @@
+<?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\ProxmoxVps\App\UI\IpAddress\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\IpAddress\Modals\DeleteModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+
+class DeleteButton extends ButtonDataTableModalAction implements AdminArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('deleteButton');
+        $this->setDisableByColumnValue("master", true);
+        $this->switchToRemoveBtn();
+        $this->initLoadModalAction(new DeleteModal());
+    }
+
+}

+ 78 - 0
app/UI/IpAddress/Forms/CreateForm.php

@@ -0,0 +1,78 @@
+<?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\ProxmoxVps\App\UI\IpAddress\Forms;
+
+
+use ModulesGarden\ProxmoxAddon\App\UI\Validators\MacAddressValidator;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\IpAddress\Providers\DiskProvider;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\IpAddress\Providers\IpAddressProvider;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Validators\CidrValidator;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Validators\IpAddressValidator;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Text;
+
+
+class CreateForm extends BaseForm implements AdminArea
+{
+    public function initContent()
+    {
+        $this->initIds('createForm');
+        $this->setFormType('create');
+        $this->setProvider(new IpAddressProvider());
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['create'];
+    }
+
+    private function initFields()
+    {
+        //ip
+        $field = new Text('ip');
+        $field->addValidator(new IpAddressValidator(true));
+        $this->addField($field);
+        // mac_address
+        $field = new Text('mac_address');
+        $field->addValidator(new MacAddressValidator());
+        $this->addField($field);
+        //subnet_mask
+        $field = new Text('subnet_mask');
+        $field->addValidator(new IpAddressValidator(false));
+        $this->addField($field);
+        //gateway
+        $field = new Text('gateway');
+        $field->addValidator(new IpAddressValidator(false));
+        $this->addField($field);
+        $field = new Text('cidr');
+        $field->addValidator(new CidrValidator(true));
+        $field->setPlaceholder('24');
+        $this->addField($field);
+        //network
+        $field = new Switcher('network');
+        $field->setDescription('description');
+        $this->addField($field);
+
+    }
+}

+ 53 - 0
app/UI/IpAddress/Forms/DeleteForm.php

@@ -0,0 +1,53 @@
+<?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\ProxmoxVps\App\UI\IpAddress\Forms;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\IpAddress\Providers\DiskProvider;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\IpAddress\Providers\FirewallOptionProvider;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\IpAddress\Providers\IpAddressProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Hidden;
+
+
+class DeleteForm extends BaseForm implements AdminArea
+{
+    public function initContent()
+    {
+        $this->initIds('deleteForm');
+        $this->setFormType('delete');
+        $this->setProvider(new IpAddressProvider());
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['delete'];
+    }
+
+    private function initFields()
+    {
+        $this->setConfirmMessage('conforimDelete', ["ip" => null]);
+        $this->addField(new Hidden("id"));
+        $this->addField(new Hidden("ip"));
+    }
+
+}

+ 35 - 0
app/UI/IpAddress/Modals/CreateModal.php

@@ -0,0 +1,35 @@
+<?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\ProxmoxVps\App\UI\IpAddress\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\IpAddress\Forms\CreateForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmSuccess;
+
+class CreateModal extends ModalConfirmSuccess implements AdminArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('createModal');
+        $this->addForm(new CreateForm());
+    }
+
+}

+ 35 - 0
app/UI/IpAddress/Modals/DeleteModal.php

@@ -0,0 +1,35 @@
+<?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\ProxmoxVps\App\UI\IpAddress\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\IpAddress\Forms\DeleteForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmDanger;
+
+class DeleteModal extends ModalConfirmDanger implements AdminArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('deleteModal');
+        $this->addForm(new DeleteForm());
+    }
+
+}

+ 95 - 0
app/UI/IpAddress/Pages/IpAddressDataTable.php

@@ -0,0 +1,95 @@
+<?php
+/* * ********************************************************************
+*  ProxmoxVPS Product developed. (26.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\ProxmoxVps\App\UI\IpAddress\Pages;
+
+use ModulesGarden\ProxmoxAddon\App\Models\VmIpAddress;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\IpAddress\Buttons\CreateButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\IpAddress\Buttons\DeleteButton;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\Column;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\DataProviders\Providers\QueryDataProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\DataTable;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\isAdmin;
+
+class IpAddressDataTable extends DataTable implements ClientArea, AdminArea
+{
+
+    protected $id = 'ipAddressDataTable';
+    protected $title = 'ipAddressDataTable';
+    protected $searchable = false;
+    protected $tableLength = "100";
+
+    public function initContent()
+    {
+        $this->addClass('lu-text-left');
+
+        if (isAdmin())
+        {
+            $this->addButton(new CreateButton());
+            $this->addActionButton(new DeleteButton());
+        }
+    }
+
+    protected function loadHtml()
+    {
+        $this->addColumn((new Column('ip')))
+            ->addColumn((new Column('mac_address')))
+            ->addColumn((new Column('subnet_mask')))
+            ->addColumn((new Column('gateway')));
+    }
+
+    public function replaceFieldMac_address($key, $row)
+    {
+        return $row->{$key} ? $row->{$key} : '-';
+    }
+
+    public function replaceFieldSubnet_mask($key, $row)
+    {
+        return $row->{$key} ? $row->{$key} : '-';
+    }
+
+    public function replaceFieldGateway($key, $row)
+    {
+        return $row->{$key} ? $row->{$key} : '-';
+    }
+
+    protected function loadData()
+    {
+        $query    = VmIpAddress::select("id", "ip", "mac_address", "subnet_mask", "gateway")
+            ->ofHostingId($this->getWhmcsParamByKey('serviceid'))
+            ->getQuery();
+        $dataProv = new QueryDataProvider();
+        $dataProv->setDefaultSorting("ip", 'ASC');
+        $dataProv->setData($query);
+        $this->setDataProvider($dataProv);
+    }
+
+    public function isViewFooter()
+    {
+        return false;
+    }
+
+    public function isViewTopBody()
+    {
+        return isAdmin();
+    }
+
+}

+ 121 - 0
app/UI/IpAddress/Providers/IpAddressProvider.php

@@ -0,0 +1,121 @@
+<?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\ProxmoxVps\App\UI\IpAddress\Providers;
+
+use MGProvision\Proxmox\v2\Api;
+use ModulesGarden\ProxmoxAddon\App\Models\IpAddress;
+use ModulesGarden\ProxmoxAddon\App\Models\VmIpAddress;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Utility;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\HostingService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\IpSetIpFilterService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\NetworkService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\VmIpAddressConveter;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\ResponseTemplates\HtmlDataJsonResponse;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\DataProviders\BaseDataProvider;
+use Illuminate\Database\Capsule\Manager as DB;
+
+
+class IpAddressProvider extends BaseDataProvider implements ClientArea
+{
+    use ApiService;
+    use ProductService;
+    use HostingService;
+
+    private $networkService;
+    /**
+     * @var IpSetIpFilterService
+     */
+    private $ipSetIpFilterService;
+
+    /**
+     * IpAddressProvider constructor.
+     */
+    public function __construct()
+    {
+        parent::__construct();
+        $this->networkService       = new NetworkService();
+        $this->ipSetIpFilterService = new IpSetIpFilterService();
+    }
+
+    public function read()
+    {
+        if ($this->actionElementId && $this->actionElementId != "diskDataTable")
+        {
+            $this->data['id'] = $this->actionElementId;
+            $this->data['ip'] = VmIpAddress::where("id", $this->actionElementId)->value("ip");
+        }
+    }
+
+    public function create()
+    {
+        try{
+            DB::beginTransaction();
+            Api::beginTransaction();
+            $ip = new VmIpAddress();
+            $ip->fill($this->formData);
+            $ip->hosting_id = $this->getWhmcsParamByKey("serviceid");
+            $ip->server_id  = $this->getWhmcsParamByKey("serverid");
+            $this->setHostingId($this->getWhmcsParamByKey("serviceid"));
+            if($this->getFormDataValues()['network']=='on'){
+                $ipConveter = new VmIpAddressConveter([$ip], $this->vm());
+                $config = $ipConveter->asConfig();
+                $this->vm()->updateConfig($config);
+            }
+            //insert to data base
+            $ip->save();
+            $this->hosting()->ipAdd($ip->ip);
+            //lock ip in proxmox addon
+            if (!Utility::isIpManagerProxmoxVPSIntegration())
+            {
+                IpAddress::where('ip', $ip->ip)
+                    ->update(["hosting_id" => $ip->hosting_id]);
+            }
+            DB::commit();
+        }catch (\Exception $ex){
+            Api::commit();
+            DB::rollBack();
+            throw $ex;
+        }
+        return (new HtmlDataJsonResponse())
+            ->setStatusSuccess()
+            ->setMessageAndTranslate('The IP Address has been added successfully');
+    }
+
+    public function update()
+    {
+    }
+
+    public function delete()
+    {
+        $this->networkService->deleteByIpAddresses([$this->formData['id']]);
+        if ($this->configuration()->isIpsetIpFilter())
+        {
+            $this->ipSetIpFilterService->create();
+        }
+        return (new HtmlDataJsonResponse())
+            ->setStatusSuccess()
+            ->setMessageAndTranslate('The IP Address has been deleted successfully');
+    }
+
+
+}

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

@@ -0,0 +1,63 @@
+<?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\ProxmoxVps\App\UI\MountPoint\Buttons;
+
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\ResponseTemplates\DataJsonResponse;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonSwitchAjax;
+
+class BackupSwitchButton extends ButtonSwitchAjax implements ClientArea
+{
+
+    use ApiService;
+    use ProductService;
+    protected $switchColumn = 'backup';
+    protected $refreshActionIds = 'diskDataTable';
+
+    public function initContent()
+    {
+        parent::initContent();
+        $this->addHtmlAttribute(':disabled', 'dataRow.master == true');
+        if (!$this->configuration()->isPermissionMountPointBackup())
+        {
+            $this->addHtmlAttribute('disabled', '');
+        }
+
+    }
+
+    public function returnAjaxData()
+    {
+        try
+        {
+            $this->acl()->backup();
+            $hdd = $this->vm()->getMounPoints()->findMountPointById($this->getRequestValue('actionElementId'));
+            $hdd->setBackup($this->getRequestValue("value") == "on" ? 1 : null);
+            $hdd->update();
+        }
+        catch (\Exception $exc)
+        {
+            return (new DataJsonResponse())->setStatusError()->setMessage($exc->getMessage())->setCallBackFunction($this->callBackFunction)->addRefreshTargetId($this->refreshActionIds);
+        }
+        return (new DataJsonResponse())->setMessageAndTranslate('changesSaved')->setCallBackFunction($this->callBackFunction)->addRefreshTargetId($this->refreshActionIds);
+    }
+
+}

+ 35 - 0
app/UI/MountPoint/Buttons/CreateButton.php

@@ -0,0 +1,35 @@
+<?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\ProxmoxVps\App\UI\MountPoint\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\MountPoint\Modals\CreateModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonCreate;
+
+class CreateButton extends ButtonCreate implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('createButton');
+        $this->initLoadModalAction(new CreateModal());
+    }
+
+}

+ 37 - 0
app/UI/MountPoint/Buttons/DeleteButton.php

@@ -0,0 +1,37 @@
+<?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\ProxmoxVps\App\UI\MountPoint\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\MountPoint\Modals\DeleteModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+
+class DeleteButton extends ButtonDataTableModalAction implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('deleteButton');
+        $this->setDisableByColumnValue("master", true);
+        $this->switchToRemoveBtn();
+        $this->initLoadModalAction(new DeleteModal());
+    }
+
+}

+ 36 - 0
app/UI/MountPoint/Buttons/UpdateButton.php

@@ -0,0 +1,36 @@
+<?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\ProxmoxVps\App\UI\MountPoint\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\MountPoint\Modals\UpdateModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+
+class UpdateButton extends ButtonDataTableModalAction implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('updateButton');
+        $this->initLoadModalAction(new UpdateModal());
+        $this->setDisableByColumnValue("master", true);
+    }
+
+}

+ 67 - 0
app/UI/MountPoint/Forms/CreateForm.php

@@ -0,0 +1,67 @@
+<?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\ProxmoxVps\App\UI\MountPoint\Forms;
+
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\MountPoint\Providers\MountPointProvider;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Validators\NumberValidator;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Text;
+
+
+class CreateForm extends BaseForm implements ClientArea
+{
+    use ProductService;
+
+    public function initContent()
+    {
+        $this->initIds('createForm');
+        $this->setFormType('create');
+        $this->setProvider(new MountPointProvider());
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['create'];
+    }
+
+    private function initFields()
+    {
+        //size
+        $field = new Text('size');
+        $field->addValidator(new NumberValidator(1, 10000, true));
+        $this->addField($field);
+        //mp
+        $field = new Text('mp');
+        $field->setPlaceholder("/some/path");
+        $field->notEmpty();
+        $this->addField($field);
+        //backup
+        if ($this->configuration()->isPermissionMountPointBackup())
+        {
+            $field = new Switcher('backup');
+            $this->addField($field);
+        }
+    }
+}

+ 51 - 0
app/UI/MountPoint/Forms/DeleteForm.php

@@ -0,0 +1,51 @@
+<?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\ProxmoxVps\App\UI\MountPoint\Forms;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\MountPoint\Providers\FirewallOptionProvider;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\MountPoint\Providers\MountPointProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Hidden;
+
+
+class DeleteForm extends BaseForm implements ClientArea
+{
+    public function initContent()
+    {
+        $this->initIds('deleteForm');
+        $this->setFormType('delete');
+        $this->setProvider(new MountPointProvider());
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['delete'];
+    }
+
+    private function initFields()
+    {
+        $this->setConfirmMessage('conforimDelete');
+        $this->addField(new Hidden("id"));
+    }
+
+}

+ 65 - 0
app/UI/MountPoint/Forms/UpdateForm.php

@@ -0,0 +1,65 @@
+<?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\ProxmoxVps\App\UI\MountPoint\Forms;
+
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\MountPoint\Providers\MountPointProvider;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Validators\NumberValidator;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Hidden;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Text;
+
+class UpdateForm extends BaseForm implements ClientArea
+{
+    use ProductService;
+
+    public function initContent()
+    {
+        $this->initIds('updateForm');
+        $this->setFormType('update');
+        $this->setProvider(new MountPointProvider());
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['update'];
+    }
+
+    private function initFields()
+    {
+        //entity id
+        $this->addField(new Hidden("id"));
+        //size
+        $field = new Text('size');
+        $field->addValidator(new NumberValidator(1, 100, true));
+        $this->addField($field);
+        //backup
+        if ($this->configuration()->isPermissionMountPointBackup())
+        {
+            $field = new Switcher('backup');
+            $this->addField($field);
+        }
+
+    }
+}

+ 35 - 0
app/UI/MountPoint/Modals/CreateModal.php

@@ -0,0 +1,35 @@
+<?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\ProxmoxVps\App\UI\MountPoint\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\MountPoint\Forms\CreateForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\BaseEditModal;
+
+class CreateModal extends BaseEditModal implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('createModal');
+        $this->addForm(new CreateForm());
+    }
+
+}

+ 35 - 0
app/UI/MountPoint/Modals/DeleteModal.php

@@ -0,0 +1,35 @@
+<?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\ProxmoxVps\App\UI\MountPoint\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\MountPoint\Forms\DeleteForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmDanger;
+
+class DeleteModal extends ModalConfirmDanger implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('deleteModal');
+        $this->addForm(new DeleteForm());
+    }
+
+}

+ 35 - 0
app/UI/MountPoint/Modals/UpdateModal.php

@@ -0,0 +1,35 @@
+<?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\ProxmoxVps\App\UI\MountPoint\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\MountPoint\Forms\UpdateForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\BaseEditModal;
+
+class UpdateModal extends BaseEditModal implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('updateModal');
+        $this->addForm(new UpdateForm());
+    }
+
+}

+ 125 - 0
app/UI/MountPoint/Pages/MountPointDataTable.php

@@ -0,0 +1,125 @@
+<?php
+/* * ********************************************************************
+*  ProxmoxVPS Product developed. (26.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\ProxmoxVps\App\UI\MountPoint\Pages;
+
+use ModulesGarden\ProxmoxAddon\App\Libs\Format;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\MountPoint\Buttons\BackupSwitchButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\MountPoint\Buttons\CreateButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\MountPoint\Buttons\DeleteButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\MountPoint\Buttons\DeleteMassButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\MountPoint\Buttons\RestoreButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\MountPoint\Buttons\UpdateButton;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\Column;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\DataProviders\Providers\ArrayDataProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\DataTable;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+
+class MountPointDataTable extends DataTable implements ClientArea
+{
+    use ApiService;
+    use ProductService;
+    protected $id = 'mountPointDataTable';
+    protected $title = 'mountPointDataTable';
+
+    public function initContent()
+    {
+        $this->setInternalAlertMessage("Adding, editing or removing disk will reboot the virtual machine.");
+        //Create
+        $createButton = new CreateButton();
+        $createButton->addClass("pmCreateButton");
+        if (!$this->resourceGuard()->hasMountPointLimit())
+        {
+            $createButton->addClass("hidden");
+        }
+        $this->addButton($createButton);
+        //Update
+        $this->addActionButton(new UpdateButton());
+        //Delete
+        $this->addActionButton(new DeleteButton());
+    }
+
+    protected function loadHtml()
+    {
+        $this->addColumn((new Column('id'))->setSearchable(true, "string")->setOrderable('DESC'))
+            ->addColumn((new Column('name'))->setSearchable(true, "string")->setOrderable())
+            ->addColumn((new Column('mp'))->setSearchable(true)->setOrderable())
+            ->addColumn((new Column('backup'))->setSearchable(true)->setOrderable())
+            ->addColumn((new Column('bytes'))->setSearchable(true)->setOrderable());
+    }
+
+    public function replaceFieldName($key, $row)
+    {
+        return sl("lang")->tr($row[$key]);
+    }
+
+    public function replaceFieldPath($key, $row)
+    {
+        if ($row[$key])
+        {
+            return $row[$key];
+        }
+        return '-';
+    }
+
+    public function customColumnHtmlBackup()
+    {
+        return (new BackupSwitchButton())->getHtml();
+    }
+
+    public function replaceFieldBackup($key, $row)
+    {
+        if ($row['master'])
+        {
+            return "on";
+        }
+        return $row['backup'] == "1" ? "on" : "off";
+    }
+
+    public function replaceFieldBytes($key, $row)
+    {
+        return Format::convertBytes($row['bytes']);
+    }
+
+    protected function loadData()
+    {
+        $data = [];
+        foreach ($this->vm()->getMounPoints()->fetch() as $entity)
+        {
+            $data[] = [
+                "id"     => $entity->getId(),
+                "name"   => $entity->getName(),
+                "mp"   => $entity->getMp(),
+                "backup" => $entity->getBackup(),
+                "size"   => $entity->getSize(),
+                "bytes"  => $entity->getBytes(),
+                "master" => $entity->getId() == "rootfs"
+            ];
+        }
+        $dataProv = new ArrayDataProvider();
+        $dataProv->setDefaultSorting("id", 'DESC');
+        $dataProv->setData($data);
+        $this->setDataProvider($dataProv);
+    }
+
+
+}

+ 135 - 0
app/UI/MountPoint/Providers/MountPointProvider.php

@@ -0,0 +1,135 @@
+<?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\ProxmoxVps\App\UI\MountPoint\Providers;
+
+use MGProvision\Proxmox\v2\models\MountPoint;
+use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\RebootVmJob;
+use ModulesGarden\ProxmoxAddon\App\Models\Job;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\ResponseTemplates\HtmlDataJsonResponse;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\DataProviders\BaseDataProvider;
+use function ModulesGarden\ProxmoxAddon\Core\Helper\queue;
+
+
+class MountPointProvider extends BaseDataProvider implements ClientArea
+{
+    use ApiService;
+    use ProductService;
+
+    public function read()
+    {
+        if ($this->actionElementId && $this->actionElementId != "mountPointDataTable")
+        {
+            $disk = $this->vm()->getMounPoints()->findMountPointById($this->actionElementId);
+            $this->data       = $disk->toArray();
+            $this->data['id'] = $this->actionElementId;
+            //backup
+            $backup               = $this->data['backup'];
+            $this->data['backup'] = $backup == "1" ? "on" : "off";
+            //size
+            $this->data['size'] = (int)$disk->getGb();
+        }
+    }
+
+    public function create()
+    {
+        $this->resourceGuard()->mountPointLimit($this->formData['size']);
+        //disk storage
+        $storage              = $this->configuration()->getMountPointStorage();
+        $mountPointRepository = $this->vm()->getMounPoints();
+        $hdd                  = new MountPoint($mountPointRepository->nextId());
+        $hdd->setLocation($storage . ":" . $this->formData['size'])
+            ->setAcl($this->configuration()->getMountPointAcl() == "default" ? null : $this->configuration()->getMountPointAcl())
+            ->setRo($this->configuration()->isMountPointRo() ? 1 : null)
+            ->setQuota($this->configuration()->isMountPointQuota() ? 1 : null)
+            ->setBackup($this->configuration()->isPermissionMountPointBackup() && $this->formData['backup'] == "on" ? 1 : null)
+            ->setReplicate($this->configuration()->isMountPointReplicate() ? '0' : null)
+            ->setMp($this->formData['mp'])
+            ->setPath($this->vm()->getPath() . "/config")
+            ->setApi($this->api())
+            ->create();
+        return (new HtmlDataJsonResponse())
+            ->setStatusSuccess()
+            ->setMessageAndTranslate('The hard disk has been created successfully')
+            ->addData('createButtonStatus', $this->resourceGuard()->hasMountPointLimit())
+            ->setCallBackFunction('pmToggleButton');
+    }
+
+    public function update()
+    {
+        $this->resourceGuard()->mountPointLimit($this->formData['size'], $this->formData['id']);
+        $hdd = $this->vm()->getMounPoints()->findMountPointById($this->formData['id']);
+        if($hdd->isMaster()){
+            return (new HtmlDataJsonResponse())
+                ->setStatusError()
+                ->setMessageAndTranslate('Update the master disk size is restricted');
+        }
+        if ((int)$hdd->getGb() > (int)$this->formData['size'])
+        {
+            return (new HtmlDataJsonResponse())
+                ->setStatusError()
+                ->setMessageAndTranslate('Downgrading the disk size is restricted');
+        }
+        //resize
+        if ((int)$hdd->getGb() < (int)$this->formData['size'])
+        {
+            $size = "+" . abs((int)$this->formData['size'] - (int)$hdd->getGb()) . "G";
+            $hdd->resize($size);
+        }
+        //backup
+        $backup = $this->configuration()->isPermissionMountPointBackup() && $this->formData['backup'] == "on" ? 1 : null;
+        if ($backup != $hdd->getBackup())
+        {
+            $hdd->setBackup($backup);
+            $hdd->update();
+        }
+        //reboot
+        if ($this->vm()->isRunning() &&
+            !Job::waiting()->ofJob(RebootVmJob::class)->ofHostingId($this->getWhmcsParamByKey("serviceid"))->count())
+        {
+            queue(RebootVmJob::class, [], null, "hosting", $this->getWhmcsParamByKey("serviceid"));
+        }
+        return (new HtmlDataJsonResponse())
+            ->setStatusSuccess()
+            ->setMessageAndTranslate('The hard disk has been updated successfully')
+            ->addData('createButtonStatus', $this->resourceGuard()->hasMountPointLimit())
+            ->setCallBackFunction('pmToggleButton');
+    }
+
+    public function delete()
+    {
+        $hdd =  $this->vm()->getMounPoints()->findMountPointById($this->formData['id']);
+        if($hdd->getId() == "rootfs"){
+            return (new HtmlDataJsonResponse())
+                ->setStatusError()
+                ->setMessageAndTranslate('The master hard disk cannot be deleted');
+        }
+        $hdd->delete();
+        return (new HtmlDataJsonResponse())
+            ->setStatusSuccess()
+            ->setMessageAndTranslate('The hard disk has been deleted successfully')
+            ->addData('createButtonStatus', $this->resourceGuard()->hasMountPointLimit())
+            ->setCallBackFunction('pmToggleButton');
+    }
+
+
+}

+ 35 - 0
app/UI/Network/Buttons/CreateButton.php

@@ -0,0 +1,35 @@
+<?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\ProxmoxVps\App\UI\Network\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Network\Modals\CreateModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonCreate;
+
+class CreateButton extends ButtonCreate implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('createButton');
+        $this->initLoadModalAction(new CreateModal());
+    }
+
+}

+ 40 - 0
app/UI/Network/Buttons/DeleteButton.php

@@ -0,0 +1,40 @@
+<?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\ProxmoxVps\App\UI\Network\Buttons;
+
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Network\Modals\DeleteModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+
+class DeleteButton extends ButtonDataTableModalAction implements ClientArea
+{
+
+    use ProductService;
+
+    public function initContent()
+    {
+        $this->initIds('deleteButton');
+        $this->switchToRemoveBtn();
+        $this->setDisableByColumnValue("bridge", $this->configuration()->getBridge());
+        $this->initLoadModalAction(new DeleteModal());
+    }
+
+}

+ 38 - 0
app/UI/Network/Buttons/InfoButton.php

@@ -0,0 +1,38 @@
+<?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\ProxmoxVps\App\UI\Network\Buttons;
+
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Network\Modals\InfoModal;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Network\Modals\UpdateModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+
+class InfoButton extends ButtonDataTableModalAction implements ClientArea
+{
+    protected $icon = 'lu-btn__con lu-zmdi lu-zmdi-info-outline';
+
+    public function initContent()
+    {
+        $this->initIds('infoButton');
+        $this->initLoadModalAction(new InfoModal());
+    }
+
+}

+ 51 - 0
app/UI/Network/Forms/CreateForm.php

@@ -0,0 +1,51 @@
+<?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\ProxmoxVps\App\UI\Network\Forms;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Network\Providers\NetworkProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Hidden;
+
+
+class CreateForm extends BaseForm implements ClientArea
+{
+    public function initContent()
+    {
+        $this->initIds('createForm');
+        $this->setFormType('create');
+        $this->setProvider(new NetworkProvider());
+        $this->setConfirmMessage('confirmCreate');
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['create'];
+    }
+
+    private function initFields()
+    {
+        //bridge
+        $field = new Hidden('bridge');
+        $this->addField($field);
+    }
+}

+ 50 - 0
app/UI/Network/Forms/DeleteForm.php

@@ -0,0 +1,50 @@
+<?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\ProxmoxVps\App\UI\Network\Forms;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Network\Providers\NetworkProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Hidden;
+
+
+class DeleteForm extends BaseForm implements ClientArea
+{
+    public function initContent()
+    {
+        $this->initIds('deleteForm');
+        $this->setFormType('delete');
+        $this->setProvider(new NetworkProvider());
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['delete'];
+    }
+
+    private function initFields()
+    {
+        $this->setConfirmMessage('conforimDelete');
+        $this->addField(new Hidden("id"));
+    }
+
+}

+ 35 - 0
app/UI/Network/Modals/CreateModal.php

@@ -0,0 +1,35 @@
+<?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\ProxmoxVps\App\UI\Network\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Network\Forms\CreateForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmSuccess;
+
+class CreateModal extends ModalConfirmSuccess implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('createModal');
+        $this->addForm(new CreateForm());
+    }
+
+}

+ 35 - 0
app/UI/Network/Modals/DeleteModal.php

@@ -0,0 +1,35 @@
+<?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\ProxmoxVps\App\UI\Network\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Network\Forms\DeleteForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmDanger;
+
+class DeleteModal extends ModalConfirmDanger implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('deleteModal');
+        $this->addForm(new DeleteForm());
+    }
+
+}

+ 68 - 0
app/UI/Network/Modals/InfoModal.php

@@ -0,0 +1,68 @@
+<?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\ProxmoxVps\App\UI\Network\Modals;
+
+use MGProvision\Proxmox\v2\models\Kvm;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Network\Forms\InfoForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ModalActionButtons\BaseCancelButton;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\BaseEditModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmDanger;
+
+class InfoModal extends  BaseEditModal implements ClientArea
+{
+
+    use ProductService;
+    use ApiService;
+
+    public function initContent()
+    {
+        $this->initIds('infoModal');
+        $networkId = $this->getRequestValue('actionElementId');
+        foreach ($this->vm()->getNetworkDevices() as $nd)
+        {
+            if($nd->getId() != $networkId){
+                continue;
+            }
+            if($this->vm() instanceof  Kvm){
+                $ipConfig = $this->vm()->getIpConfig()->findByNetworkId($nd->getId())->fetch()[0];
+            }
+            if ($ipConfig)
+            {
+                $this->customTplVars['network'] = array_merge($nd->getAttributes(), $ipConfig->getAttributes());
+            }else{
+                $this->customTplVars['network'] =  $nd->getAttributes();
+            }
+            break;
+        }
+    }
+
+    protected function initActionButtons()
+    {
+        if (!empty($this->actionButtons))
+        {
+            return $this;
+        }
+        $this->addActionButton(new BaseCancelButton());
+        return $this;
+    }
+}

+ 162 - 0
app/UI/Network/Pages/NetworkLxcDataTable.php

@@ -0,0 +1,162 @@
+<?php
+/* * ********************************************************************
+*  ProxmoxVPS Product developed. (26.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\ProxmoxVps\App\UI\Network\Pages;
+
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Network\Buttons\CreateButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Network\Buttons\DeleteButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Network\Buttons\DeleteMassButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Network\Buttons\InfoButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Network\Buttons\MailtoSwitchButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Network\Buttons\RestoreButton;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\Column;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\DataProviders\Providers\ArrayDataProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\DataTable;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+
+class NetworkLxcDataTable extends DataTable implements ClientArea
+{
+    use ProductService;
+    use ApiService;
+
+    protected $id = 'networkLxcDataTable';
+    protected $title = 'networkLxcDataTable';
+
+    public function initContent()
+    {
+        $createButton = new CreateButton();
+        $createButton->addClass("pmCreateButton");
+        if (!$this->configuration()->getPrivateBridge() || $this->vm()->getNetworkDevices($this->configuration()->getPrivateBridge()))
+        {
+            $createButton->addClass("hidden");
+        }
+        //Create
+        $this->addButton($createButton);
+        //Info
+        $this->addActionButton(new InfoButton());
+        //Delete
+        $this->addActionButton(new DeleteButton());
+    }
+
+    protected function loadHtml()
+    {
+        $this->addColumn((new Column('id'))->setSearchable(true, "string")->setOrderable('ASC'))
+            ->addColumn((new Column('name'))->setSearchable(true)->setOrderable())
+            ->addColumn((new Column('firewall'))->setSearchable(true)->setOrderable())
+            ->addColumn((new Column('hwaddr'))->setSearchable(true)->setOrderable())
+            ->addColumn((new Column('ip'))->setSearchable(true)->setOrderable())
+            ->addColumn((new Column('gw'))->setSearchable(true)->setOrderable())
+            ->addColumn((new Column('rate'))->setSearchable(true)->setOrderable());
+    }
+
+
+    public function replaceFieldFirewall($key, $row)
+    {
+        if ($row['firewall'])
+        {
+            return '<span class="lu-label lu-label--success lu-label--status">' . sl('lang')->tr("Active") . '</span>';
+        }
+        return '<span class="lu-label lu-label--danger lu-label--status">' . sl('lang')->tr("Disabled") . '</span>';
+    }
+
+    public function replaceFieldIp($key, $row)
+    {
+        if (!$row['ip'] && !$row['ip6'])
+        {
+            return '-';
+        }
+        $ip = [];
+        if ($row['ip'] && $row['cidr'])
+        {
+            $ip[] = sprintf("%s/%s", $row['ip'], $row['cidr']);
+        }
+        else
+        {
+            if ($row['ip'])
+            {
+                $ip[] = $row['ip'];
+            }
+        }
+        if ($row['ip6'] && $row['cidr6'])
+        {
+            $ip[] = sprintf("%s/%s", $row['ip6'], $row['cidr6']);
+        }
+        else
+        {
+            if ($row['ip6'])
+            {
+                $ip[] = $row['ip6'];
+            }
+        }
+        return implode("<br/>", $ip);
+    }
+
+    public function replaceFieldGw($key, $row)
+    {
+        if ($row['gw'] && $row['gw6'])
+        {
+            return sprintf('%s<br>%s', $row['gw'], $row['gw6']);
+        }
+        if ($row['gw'])
+        {
+            return $row['gw'];
+        }
+        if ($row['gw6'])
+        {
+            return $row['gw6'];
+        }
+        return "-";
+    }
+
+    public function replaceFieldTag($key, $row)
+    {
+        if ($row['tag'])
+        {
+            return $row['tag'];
+        }
+        return '-';
+    }
+
+    public function replaceFieldRate($key, $row)
+    {
+        if (isset($row['rate']))
+        {
+            return sprintf('%s MB/s %s (Mbps)', $row['rate'], $row['rate'] * 8);
+        }
+        return sl('lang')->abtr("Unlimited");
+    }
+
+    protected function loadData()
+    {
+        $data = [];
+        foreach ($this->vm()->getNetworkDevices() as $nd)
+        {
+            $data[] = $nd->getAttributes();
+        }
+        $dataProv = new ArrayDataProvider();
+        $dataProv->setDefaultSorting("id", 'ASC');
+        $dataProv->setData($data);
+        $this->setDataProvider($dataProv);
+    }
+
+
+}

+ 166 - 0
app/UI/Network/Pages/NetworkQemuDataTable.php

@@ -0,0 +1,166 @@
+<?php
+/* * ********************************************************************
+*  ProxmoxVPS Product developed. (26.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\ProxmoxVps\App\UI\Network\Pages;
+
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Network\Buttons\CreateButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Network\Buttons\DeleteButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Network\Buttons\DeleteMassButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Network\Buttons\InfoButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Network\Buttons\RestoreButton;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\Column;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\DataProviders\Providers\ArrayDataProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\DataTable;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+
+class NetworkQemuDataTable extends DataTable implements ClientArea
+{
+    use ProductService;
+    use ApiService;
+    protected $id = 'networkQemuDataTable';
+    protected $title = 'networkQemuDataTable';
+
+    public function initContent()
+    {
+        //Create
+        $createButton = new CreateButton();
+        $createButton->addClass("pmCreateButton");
+        if (!$this->configuration()->getPrivateBridge()  || $this->vm()->getNetworkDevices($this->configuration()->getPrivateBridge()))
+        {
+            $createButton->addClass("hidden");
+        }
+        $this->addButton($createButton);
+        //Info
+        $this->addActionButton(new InfoButton());
+        //Delete
+        $this->addActionButton(new DeleteButton());
+    }
+
+    protected function loadHtml()
+    {
+        $this->addColumn((new Column('id'))->setSearchable(true, "string")->setOrderable('ASC'))
+            ->addColumn((new Column('firewall'))->setSearchable(true)->setOrderable())
+            ->addColumn((new Column('macAddress'))->setSearchable(true)->setOrderable())
+            ->addColumn((new Column('ip'))->setSearchable(true)->setOrderable())
+            ->addColumn((new Column('gw'))->setSearchable(true)->setOrderable())
+            ->addColumn((new Column('rate'))->setSearchable(true)->setOrderable());
+    }
+
+    public function replaceFieldFirewall($key, $row)
+    {
+        if ($row['firewall'])
+        {
+            return '<span class="lu-label lu-label--success lu-label--status">' . sl('lang')->tr("Active") . '</span>';
+        }
+        return '<span class="lu-label lu-label--danger lu-label--status">' . sl('lang')->tr("Disabled") . '</span>';
+    }
+
+    public function replaceFieldTag($key, $row)
+    {
+        if ($row['tag'])
+        {
+            return $row['tag'];
+        }
+        return '-';
+    }
+
+    public function replaceFieldIp($key, $row)
+    {
+        if (!$row['ip'] && !$row['ip6'])
+        {
+            return '-';
+        }
+        $ip = [];
+        if ($row['ip'] && $row['cidr'])
+        {
+            $ip[] = sprintf("%s/%s", $row['ip'], $row['cidr']);
+        }
+        else
+        {
+            if ($row['ip'])
+            {
+                $ip[] = $row['ip'];
+            }
+        }
+        if ($row['ip6'] && $row['cidr6'])
+        {
+            $ip[] = sprintf("%s/%s", $row['ip6'], $row['cidr6']);
+        }
+        else
+        {
+            if ($row['ip6'])
+            {
+                $ip[] = $row['ip6'];
+            }
+        }
+        return implode("<br/>", $ip);
+    }
+
+    public function replaceFieldGw($key, $row)
+    {
+        if ($row['gw'] && $row['gw6'])
+        {
+            return sprintf('%s<br>%s', $row['gw'], $row['gw6']);
+        }
+        if ($row['gw'])
+        {
+            return $row['gw'];
+        }
+        if ($row['gw6'])
+        {
+            return $row['gw6'];
+        }
+        return "-";
+    }
+
+    public function replaceFieldRate($key, $row)
+    {
+        if (isset($row['rate']))
+        {
+            return sprintf('%s MB/s %s (Mbps)', $row['rate'], $row['rate'] * 8);
+        }
+        return sl('lang')->abtr("Unlimited");
+    }
+
+    protected function loadData()
+    {
+        $data = [];
+        foreach ($this->vm()->getNetworkDevices() as $nd)
+        {
+            $ipConfig = $this->vm()->getIpConfig()->findByNetworkId($nd->getId())->fetch()[0];
+            if ($ipConfig)
+            {
+                $data[] = array_merge($nd->getAttributes(), $ipConfig->getAttributes());
+            }
+            else
+            {
+                $data[] = $nd->getAttributes();
+            }
+        }
+        $dataProv = new ArrayDataProvider();
+        $dataProv->setDefaultSorting("id", 'ASC');
+        $dataProv->setData($data);
+        $this->setDataProvider($dataProv);
+    }
+
+
+}

+ 128 - 0
app/UI/Network/Providers/NetworkProvider.php

@@ -0,0 +1,128 @@
+<?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\ProxmoxVps\App\UI\Network\Providers;
+
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\IpSetIpFilterService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\NetworkService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\ResponseTemplates\HtmlDataJsonResponse;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\DataProviders\BaseDataProvider;
+
+
+class NetworkProvider extends BaseDataProvider implements ClientArea
+{
+    use ProductService;
+    use ApiService;
+    /**
+     * @var NetworkService
+     */
+    private $networkService;
+
+    public function read()
+    {
+        if ($this->actionElementId)
+        {
+            $this->data['id'] = $this->actionElementId;
+        }
+        $this->data['bridge'] = $this->configuration()->getPrivateBridge();
+    }
+
+    public function create()
+    {
+        if ($this->vm()->getNetworkDevices($this->configuration()->getPrivateBridge()))
+        {
+            return (new HtmlDataJsonResponse())
+                ->setStatusError()
+                ->setMessageAndTranslate('Private network limit exceeded');
+        }
+        $this->networkService = new NetworkService();
+        if (!$this->networkService->hasPrivateIpAddress())
+        {
+            throw new \Exception("Private IP Addresses are not available.");
+        }
+        if ($this->configuration()->isLxc())
+        {
+            $this->lxc();
+        }
+        else
+        {
+            if ($this->configuration()->isQemu())
+            {
+                $this->qemu();
+            }
+        }
+        if($this->configuration()->isIpsetIpFilter()){
+            $ipSetIpFilterService = new IpSetIpFilterService();
+            $ipSetIpFilterService->create();
+        }
+
+        return (new HtmlDataJsonResponse())
+            ->setStatusSuccess()
+            ->setMessageAndTranslate('The Network Device has been created successfully')
+            ->addData('createButtonStatus', false)
+            ->setCallBackFunction('pmToggleButton');
+    }
+
+    private function lxc()
+    {
+        //Get Private IP Addresses
+        $ip = $this->networkService->getPrivateIpAddress();
+        //Create network device
+        $this->networkService->addPrivate([$ip]);
+
+    }
+
+    private function qemu()
+    {
+        //Get Private IP Addresses
+        $ip = $this->networkService->getPrivateIpAddress();
+        //Create network device
+        $this->networkService->addPrivate([$ip]);
+    }
+
+    public function update()
+    {
+    }
+
+    public function delete()
+    {
+        if (!$this->vm()->getNetworkDevices($this->configuration()->getPrivateBridge()))
+        {
+            return (new HtmlDataJsonResponse())
+                ->setStatusError()
+                ->setMessageAndTranslate('Private network device not found');
+        }
+        $this->networkService = new NetworkService();
+        $this->networkService->deleteByNetworkId([$this->formData['id']]);
+        if($this->configuration()->isIpsetIpFilter()){
+            $ipSetIpFilterService = new IpSetIpFilterService();
+            $ipSetIpFilterService->create();
+        }
+        return (new HtmlDataJsonResponse())
+            ->setStatusSuccess()
+            ->setMessageAndTranslate('The Network Device has been deleted successfully')
+            ->addData('createButtonStatus', true)
+            ->setCallBackFunction('pmToggleButton');
+    }
+
+
+}

+ 142 - 0
app/UI/Network/Templates/modals/infoModal.tpl

@@ -0,0 +1,142 @@
+{**********************************************************************
+* ProxmoxAddon product developed. (2017-11-16)
+* *
+*
+*  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-modal show lu-modal--{$rawObject->getModalSize()}" id="confirmationModal"
+     namespace="{$rawObject->getNamespace()}" index="{$rawObject->getId()}">
+    <div class="lu-modal__dialog">
+        <div class="lu-modal__content" id="mgModalContainer">
+            <div class="lu-modal__top lu-top">
+                <div class="lu-top__title lu-type-6">
+                    <span class="lu-text-faded lu-font-weight-normal">
+                {if $rawObject->isRawTitle()}{$rawObject->getRawTitle()}{elseif $rawObject->getTitle()}{$MGLANG->T('modal', $rawObject->getTitle())}{/if}
+            </span>
+                </div>
+                <div class="lu-top__toolbar">
+                    <button class="lu-btn lu-btn--xs lu-btn--default lu-btn--icon lu-btn--link lu-btn--plain closeModal"
+                            data-dismiss="lu-modal" aria-label="Close" @click='closeModal($event)'>
+                        <i class="lu-btn__icon lu-zmdi lu-zmdi-close"></i>
+                    </button>
+                </div>
+            </div>
+            <div class="lu-modal__body">
+                <div class="lu-col-md-12">
+                    <ul class="lu-list lu-list--info">
+                        <li class="lu-list__item">
+                            <span class="lu-list__item-title">{$MGLANG->tr('ID')}</span>
+                            <span class="lu-list__value"> {$customTplVars.network.id} </span>
+                        </li>
+                        {if $customTplVars.network.name}
+                            <li class="lu-list__item">
+                                <span class="lu-list__item-title">{$MGLANG->tr('Name')} </span>
+                                 <span class="lu-list__value"> {$customTplVars.network.name} </span>
+                            </li>
+                        {/if}
+                        <li class="lu-list__item">
+                            <span class="lu-list__item-title">{$MGLANG->tr('Bridge')}</span>
+                            <span class="lu-list__value">{$customTplVars.network.bridge}</span>
+                        </li>
+                        <li class="lu-list__item">
+                            <span class="lu-list__item-title">{$MGLANG->tr('Firewall')}</span>
+                            <span class="lu-list__value">
+                                {if $customTplVars.network.firewall}
+                                    <span class="lu-label lu-label--success lu-label--status">{$MGLANG->tr('Active')}</span>
+                                {else}
+                                    <span class="lu-label lu-label--danger lu-label--status">{$MGLANG->tr('Disabled')}</span>
+                                {/if}
+                            </span>
+                        </li>
+                        <li class="lu-list__item">
+                            <span class="lu-list__item-title">{$MGLANG->tr('MAC Address')}</span>
+                            <span class="lu-list__value">{$customTplVars.network.hwaddr} {$customTplVars.network.macAddress}</span>
+                        </li>
+                        <li class="lu-list__item">
+                            <span class="lu-list__item-title">{$MGLANG->tr('IP Address')}</span>
+                            <span class="lu-list__value">
+                                {if !$customTplVars.network.ip && !$customTplVars.network.ip6}
+                                    -
+                                {elseif $customTplVars.network.ip && $customTplVars.network.cidr }
+                                    {$customTplVars.network.ip}/{$customTplVars.network.cidr}
+                                    <br/>
+                                {elseif $customTplVars.network.ip }
+                                    {$customTplVars.network.ip}   <br/>
+                                {/if}
+                                {if $customTplVars.network.ip6 && $customTplVars.network.cidr6 }
+                                    {$customTplVars.network.ip6}/{$customTplVars.network.cidr6}
+                                {elseif $customTplVars.network.ip6}
+                                    {$customTplVars.network.ip6}
+                                {/if}
+                            </span>
+                        </li>
+                        <li class="lu-list__item">
+                            <span class="lu-list__item-title">{$MGLANG->tr('Gateway')}</span>
+                            <span class="lu-list__value">
+                                {if !$customTplVars.network.gw && !$customTplVars.network.gw6}
+                                    -
+                                {elseif $customTplVars.network.gw && $customTplVars.network.gw6}
+                                    {$customTplVars.network.gw}
+                                    <br/>
+                                    {$customTplVars.network.gw6}
+                                {else}
+                                    {$customTplVars.network.gw}
+                                    {$customTplVars.network.gw6}
+                                {/if}
+                            </span>
+                        </li>
+                        <li class="lu-list__item">
+                            <span class="lu-list__item-title">{$MGLANG->tr('Tag')}</span>
+                            <span class="lu-list__value">
+                                {if !$customTplVars.network.tag}
+                                    -
+                                {/if}
+                                {$customTplVars.network.tag}
+                            </span>
+                        </li>
+                        <li class="lu-list__item">
+                            <span class="lu-list__item-title">{$MGLANG->tr('Rate')}</span>
+                            <span class="lu-list__value">
+                                {if $customTplVars.network.rate}
+                                    {$customTplVars.network.rate} MB/s {$customTplVars.network.rate*8} (Mbps)
+                                {else}
+                                    {$MGLANG->tr('Unlimited')}
+                                {/if}
+                            </span>
+                        </li>
+                    </ul>
+                </div>
+
+            </div>
+            <div class="lu-modal__actions">
+                {foreach from=$rawObject->getActionButtons() item=actionButton}
+                    {$actionButton->getHtml()}
+                {/foreach}
+            </div>
+            {if ($isDebug eq true AND (count($MGLANG->getMissingLangs()) != 0))}{literal}
+                <div class="lu-modal__actions">
+                <div class="lu-row">
+            {/literal}{foreach from=$MGLANG->getMissingLangs() key=varible item=value}{literal}
+                <div class="lu-col-md-12"><b>{/literal}{$varible}{literal}</b> = '{/literal}{$value}{literal}';</div>
+            {/literal}{/foreach}{literal}
+                </div>
+                </div>
+            {/literal}{/if}
+        </div>
+    </div>
+</div>

+ 38 - 0
app/UI/Reinstall/Buttons/IsoInstallButton.php

@@ -0,0 +1,38 @@
+<?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\ProxmoxVps\App\UI\Reinstall\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Reinstall\Modals\IsoInstallModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+
+class IsoInstallButton extends ButtonDataTableModalAction implements ClientArea, AdminArea
+{
+
+    protected $icon = 'lu-zmdi lu-zmdi-time-restore-setting';
+
+    public function initContent()
+    {
+        $this->initIds('isoInstallButton');
+        $this->initLoadModalAction(new IsoInstallModal());
+    }
+
+}

+ 38 - 0
app/UI/Reinstall/Buttons/TemplateInstallButton.php

@@ -0,0 +1,38 @@
+<?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\ProxmoxVps\App\UI\Reinstall\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Reinstall\Modals\TemplateInstallModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+
+class TemplateInstallButton extends ButtonDataTableModalAction implements ClientArea, AdminArea
+{
+
+    protected $icon = 'lu-zmdi lu-zmdi-time-restore-setting';
+
+    public function initContent()
+    {
+        $this->initIds('templateInstallButton');
+        $this->initLoadModalAction(new TemplateInstallModal());
+    }
+
+}

+ 52 - 0
app/UI/Reinstall/Forms/IsoInstallForm.php

@@ -0,0 +1,52 @@
+<?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\ProxmoxVps\App\UI\Reinstall\Forms;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Reinstall\Providers\IsoInstallProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Hidden;
+
+
+class IsoInstallForm extends BaseForm implements ClientArea
+{
+    public function initContent()
+    {
+
+        $this->initIds('isoInstallForm');
+        $this->setFormType("processQemu");
+        $this->setProvider(new IsoInstallProvider());
+        $this->setConfirmMessage('confirmReinstall');
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ["processQemu"];
+    }
+
+    private function initFields()
+    {
+        //entity id
+        $this->addField(new Hidden("id"));
+
+    }
+}

+ 68 - 0
app/UI/Reinstall/Forms/TemplateInstallForm.php

@@ -0,0 +1,68 @@
+<?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\ProxmoxVps\App\UI\Reinstall\Forms;
+
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Reinstall\Providers\TemplateInstallProvider;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Validators\PasswordValidator;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Helpers\AlertTypesConstants;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Hidden;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Text;
+
+
+class TemplateInstallForm extends BaseForm implements ClientArea, AdminArea
+{
+    use ProductService;
+    use ApiService;
+
+    public function initContent()
+    {
+
+        $this->initIds('templateInstallForm');
+        $this->setFormType("process" . ucfirst($this->vm()->getVirtualization()));
+        $this->setProvider(new TemplateInstallProvider());
+        $this->setInternalAlertMessage('confirmReinstall');
+        $this->setInternalAlertMessageType(AlertTypesConstants::DANGER);
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ["processQemu", "processLxc"];
+    }
+
+    private function initFields()
+    {
+
+        //entity id
+        $this->addField(new Hidden("id"));
+        //password
+        $field = new Text('password');
+        $field->notEmpty();
+        $field->addValidator(new PasswordValidator(true, 5));
+        $this->addField($field);
+
+    }
+}

+ 36 - 0
app/UI/Reinstall/Modals/IsoInstallModal.php

@@ -0,0 +1,36 @@
+<?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\ProxmoxVps\App\UI\Reinstall\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Reinstall\Forms\IsoInstallForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmDanger;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmSuccess;
+
+class IsoInstallModal extends ModalConfirmDanger implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('isoInstallModal');
+        $this->addForm(new IsoInstallForm());
+    }
+
+}

+ 37 - 0
app/UI/Reinstall/Modals/TemplateInstallModal.php

@@ -0,0 +1,37 @@
+<?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\ProxmoxVps\App\UI\Reinstall\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Reinstall\Forms\TemplateInstallForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmDanger;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmSuccess;
+
+class TemplateInstallModal extends ModalConfirmDanger implements ClientArea, AdminArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('templateInstallModal');
+        $this->addForm(new TemplateInstallForm());
+    }
+
+}

+ 42 - 0
app/UI/Reinstall/Pages/IsoDataTable.php

@@ -0,0 +1,42 @@
+<?php
+/* * ********************************************************************
+*  ProxmoxVPS Product developed. (26.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\ProxmoxVps\App\UI\Reinstall\Pages;
+
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Reinstall\Buttons\BackupSwitchButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Reinstall\Buttons\CreateButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Reinstall\Buttons\DeleteButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Reinstall\Buttons\DeleteMassButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Reinstall\Buttons\RestoreButton;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\DataTable;
+
+class IsoDataTable extends DataTable implements ClientArea
+{
+    use ApiService;
+    use ProductService;
+    use IsoTrait;
+
+    protected $id = 'isoDataTable';
+    protected $title = 'isoDataTable';
+
+
+}

+ 38 - 0
app/UI/Reinstall/Pages/IsoRawDataTable.php

@@ -0,0 +1,38 @@
+<?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\ProxmoxVps\App\UI\Reinstall\Pages;
+
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\RawDataTable\RawDataTable;
+
+class IsoRawDataTable extends RawDataTable implements ClientArea, AdminArea
+{
+    use ApiService;
+    use ProductService;
+    use IsoTrait;
+
+    protected $id = 'isoDataTable';
+    protected $title = 'isoDataTable';
+
+
+}

+ 70 - 0
app/UI/Reinstall/Pages/IsoTrait.php

@@ -0,0 +1,70 @@
+<?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\ProxmoxVps\App\UI\Reinstall\Pages;
+
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Reinstall\Buttons\IsoInstallButton;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\Column;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\DataProviders\Providers\ArrayDataProvider;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+
+trait IsoTrait
+{
+
+
+    public function initContent()
+    {
+        $this->setInternalAlertMessage("Select the template for reinstallation. If you proceed, all data located on the virtual machine will be lost.");
+        //Install
+        $this->addActionButton(new IsoInstallButton());
+    }
+
+    protected function loadHtml()
+    {
+        $this->addColumn((new Column('name'))->setSearchable(true, "string")->setOrderable('ASC'));
+    }
+
+    public function replaceFieldName($key, $row)
+    {
+        return sl("lang")->abtr("template", $row[$key]);
+    }
+
+    protected function loadData()
+    {
+        $data = [];
+        foreach ($this->isoRepository()->fetch() as $entity)
+        {
+
+            if ($this->configuration()->isPermissionIsoImages() && !in_array($entity->getVolid(), $this->configuration()->getPermissionIsoImages()))
+            {
+                continue;
+            }
+            $data[] = [
+                "id"   => $entity->getVolid(),
+                "name" => $entity->getFriendlyName(),
+            ];
+        }
+        $dataProv = new ArrayDataProvider();
+        $dataProv->setDefaultSorting("name", 'ASC');
+        $dataProv->setData($data);
+        $this->setDataProvider($dataProv);
+    }
+
+}

+ 40 - 0
app/UI/Reinstall/Pages/ReinstallTab.php

@@ -0,0 +1,40 @@
+<?php
+/* * ********************************************************************
+*  ProxmoxVPS Product developed. (26.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\ProxmoxVps\App\UI\Reinstall\Pages;
+
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\TabsWidget\TabsWidget;
+
+class ReinstallTab extends TabsWidget implements ClientArea, AdminArea
+{
+    protected $id = 'reinstallTab';
+    protected $name = 'reinstallTab';
+    protected $title = 'reinstallTab';
+    protected $vueComponent = true;
+
+    public function initContent()
+    {
+        $this->addElement(new TemplateRawDataTable());
+        $this->addElement(new IsoRawDataTable());
+
+    }
+}

+ 39 - 0
app/UI/Reinstall/Pages/TemplateDataTable.php

@@ -0,0 +1,39 @@
+<?php
+/* * ********************************************************************
+*  ProxmoxVPS Product developed. (26.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\ProxmoxVps\App\UI\Reinstall\Pages;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Reinstall\Buttons\BackupSwitchButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Reinstall\Buttons\CreateButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Reinstall\Buttons\DeleteButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Reinstall\Buttons\DeleteMassButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Reinstall\Buttons\RestoreButton;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\DataTable;
+
+class TemplateDataTable extends DataTable implements ClientArea, AdminArea
+{
+    use TemplateTrait; 
+
+    protected $id = 'templatDataTable';
+    protected $title = 'templatDataTable';
+
+
+}

+ 19 - 0
app/UI/Reinstall/Pages/TemplateRawDataTable.php

@@ -0,0 +1,19 @@
+<?php
+
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Reinstall\Pages;
+
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\RawDataTable\RawDataTable;
+
+class TemplateRawDataTable extends RawDataTable implements ClientArea, AdminArea
+{
+    use TemplateTrait;
+
+    protected $id = 'templatDataTable';
+    protected $title = 'templatDataTable';
+
+
+}

+ 101 - 0
app/UI/Reinstall/Pages/TemplateTrait.php

@@ -0,0 +1,101 @@
+<?php
+
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Reinstall\Pages;
+
+
+use MGProvision\Proxmox\v2\repository\ClusterResourcesRepository;
+use MGProvision\Proxmox\v2\repository\FileRepository;
+use MGProvision\Proxmox\v2\repository\StorageRepository;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Reinstall\Buttons\TemplateInstallButton;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\Column;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\DataProviders\Providers\ArrayDataProvider;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+
+trait TemplateTrait
+{
+    use ApiService;
+    use ProductService;
+
+    public function initContent()
+    {
+        $this->setInternalAlertMessage("Select the template for reinstallation. If you proceed, all data located on the virtual machine will be lost.");
+        //Update
+        $this->addActionButton(new TemplateInstallButton());
+    }
+
+    protected function loadHtml()
+    {
+        $this->addColumn((new Column('name'))->setSearchable(true, "string")->setOrderable('ASC'));
+    }
+
+    public function replaceFieldName($key, $row)
+    {
+        return sl("lang")->abtr("template", $row[$key]);
+    }
+
+    protected function loadData()
+    {
+        $data           = [];
+        $fileRepository = new FileRepository();
+        $nodes          = [$this->vm()->getNode()];
+        //LXC
+        if ($this->configuration()->isLxc())
+        {
+            $storageRepository = new StorageRepository();
+            $storageRepository->findByNodes($nodes);
+            $storageRepository->findEnabed();
+            $storages = $storageRepository->fetchAsArray();
+            $fileRepository->findByNodes($nodes)
+                ->findByStorages($storages);
+            $fileRepository->findByContent('vztmpl');
+            foreach ($fileRepository->fetch() as $entity)
+            {
+                if ($this->configuration()->isPermissionOsTemplates() && !in_array($entity->getVolid(), $this->configuration()->getPermissionOsTemplates()))
+                {
+                    continue;
+                }
+                $data[] = [
+                    "id"   => $entity->getVolid(),
+                    "name" => $entity->getFriendlyName(),
+                ];
+            }
+        }//KVM
+        else
+        {
+            if ($this->configuration()->isQemu())
+            {
+                $clusterResurces = new ClusterResourcesRepository();
+                $clusterResurces->findKvmTemplate();
+                if (!$this->configuration()->isOsTemplatesInAllNodes())
+                {
+                    $clusterResurces->findByNodes($this->vm()->getNode());
+                }
+
+                foreach ($clusterResurces->fetchWithUniqueNames($this->vm()->getNode()) as $entity)
+                {
+                    if ($entity->isCustom() && !$entity->matchName($this->getWhmcsParamByKey("serviceid")))
+                    {
+                        continue;
+                    }
+                    if ($this->configuration()->isPermissionOsTemplates() && !in_array($entity->getName(), $this->configuration()->getPermissionOsTemplates()))
+                    {
+                        continue;
+                    }
+                    $id     = "{$entity->getNode()}/{$entity->getVmid()}";
+                    $data[] = [
+                        "id" => $id,
+                        "name"     => $entity->getName(),
+                    ];
+                }
+            }
+        }
+        $dataProv = new ArrayDataProvider();
+        $dataProv->setDefaultSorting("name", 'ASC');
+        $dataProv->setData($data);
+        $this->setDataProvider($dataProv);
+    }
+
+}

+ 142 - 0
app/UI/Reinstall/Providers/IsoInstallProvider.php

@@ -0,0 +1,142 @@
+<?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\ProxmoxVps\App\UI\Reinstall\Providers;
+
+
+use MGProvision\Proxmox\v2\repository\SnapshotRepository;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\HighAvailabilityClusterService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\IpSetIpFilterService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\ResponseTemplates\HtmlDataJsonResponse;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\DataProviders\BaseDataProvider;
+
+class IsoInstallProvider extends BaseDataProvider implements ClientArea
+{
+    use ProductService;
+    use ApiService;
+    /**
+     * @var HighAvailabilityClusterService
+     */
+    private $highAvailabilityClusterService;
+    /**
+     * @var IpSetIpFilterService
+     */
+    private $ipSetIpFilterService;
+
+    public function read()
+    {
+        if ($this->actionElementId)
+        {
+            $this->data['id'] = $this->actionElementId;
+        }
+    }
+
+    public function update()
+    {
+
+    }
+
+    private function initServices()
+    {
+        $this->highAvailabilityClusterService = new HighAvailabilityClusterService();
+        $this->ipSetIpFilterService           = new IpSetIpFilterService();
+    }
+
+    public function processQemu()
+    {
+        $this->initServices();
+        //Empyty template
+        if (!$this->formData['id'])
+        {
+            throw new \Exception ("Provide OS Template");
+        }
+        $spanshootRepostiory = new SnapshotRepository();
+        $spanshootRepostiory->findByVm($this->vm())
+            ->ignoreCurrent(true);
+        if ($spanshootRepostiory->count())
+        {
+            return (new HtmlDataJsonResponse())
+                ->setStatusError()
+                ->setMessageAndTranslate('Remove the snapshots before reinstallation.');
+        }
+        //ha
+        if ($this->highAvailabilityClusterService->exist())
+        {
+            $this->highAvailabilityClusterService->delete();
+        }
+        //stop
+        if ($this->vm()->isRunning())
+        {
+            $this->vm()->stop();
+        }
+        //Remove cloud-init drive
+        foreach ($this->vm()->config() as $id => $v)
+        {
+            if (preg_match('/cloudinit/', $v))
+            {
+                $this->vm()->deleteConfig($id);
+            }
+        }
+        //insert unattended iso
+        $this->vm()->changeIso($this->formData['id']);
+        //remove hard drive and recreate a new one, (the drive have to be empty)
+        $masterHdd = $this->vm()->getMasterHardDisk();
+        $masterHdd->delete();
+        sleep(1);
+        //Delete Unused Disk
+        foreach ($this->vm()->config(true) as $id => $v)
+        {
+            if (preg_match('/unused/', $id))
+            {
+                $this->vm()->deleteConfig($id);
+            }
+        }
+        //create new disk
+        $bytes = $masterHdd->getBytes();
+        $size  = (int)$bytes / pow(1024, 3);
+        $masterHdd->setSize($size);
+        $masterHdd->create();
+        sleep(1);
+        //Boot disk
+        $this->vm()->updateConfig(['bootdisk' => $masterHdd->getId()]);
+        //set bootorder to disk, cdrom, network (if cdrom would be first, the installer will run on every boot -> bootloop)
+        $this->vm()->changeBootOrder('cdn');
+        //ipset
+        if ($this->configuration()->isIpsetIpFilter())
+        {
+            $this->ipSetIpFilterService->create();
+        }
+        //HA
+        if ($this->configuration()->getClusterState())
+        {
+            $this->highAvailabilityClusterService->create();
+        }
+        //start vps
+        $this->vm()->start();
+        //show message that installation is now processing. The login information will be available in the noVNC console after installation.
+        return (new HtmlDataJsonResponse())
+            ->setStatusSuccess()
+            ->setMessageAndTranslate('Installation is now processing. The login information will be available in the noVNC console.');
+
+    }
+
+}

+ 145 - 0
app/UI/Reinstall/Providers/TemplateInstallProvider.php

@@ -0,0 +1,145 @@
+<?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\ProxmoxVps\App\UI\Reinstall\Providers;
+
+
+use MGProvision\Proxmox\v2\models\Kvm;
+use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\MigrateVmJob;
+use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\Reinstall\BackupVmJob;
+use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\Reinstall\CreateVmJob;
+use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\Reinstall\DeleteVmJob;
+use ModulesGarden\ProxmoxAddon\App\Libs\Format;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\HostingService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\ProxmoxAddon\Core\Queue\Models\Job;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\ResponseTemplates\HtmlDataJsonResponse;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\DataProviders\BaseDataProvider;
+use function ModulesGarden\ProxmoxAddon\Core\Helper\queue;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+
+
+class TemplateInstallProvider extends BaseDataProvider implements ClientArea, AdminArea
+{
+    use ProductService;
+    use ApiService;
+    use HostingService;
+
+    public function read()
+    {
+        if ($this->actionElementId)
+        {
+            $this->data['id']       = $this->actionElementId;
+            $this->data['password'] = htmlspecialchars($this->getWhmcsParamByKey("password"));
+        }
+    }
+
+    public function update()
+    {
+
+    }
+
+    public function processLxc()
+    {
+        if($this->jobExist()){
+            return (new HtmlDataJsonResponse())
+                ->setStatusError()
+                ->setMessageAndTranslate("Task 'Reinstall' already exist");
+        }
+        $arguments = [
+            'hostingId'  => $this->getWhmcsParamByKey('serviceid'),
+            "osTemplate" => $this->formData['id'],
+            "password"   => encrypt(html_entity_decode($this->formData['password'],ENT_QUOTES)),
+        ];
+        if ($this->configuration()->isBackupVmBeforeReinstall())
+        {
+            $job = queue(BackupVmJob::class, $arguments, null, "hosting", $this->getWhmcsParamByKey("serviceid"));
+        }
+        $job = queue(DeleteVmJob::class, $arguments, $job->id, "hosting", $this->getWhmcsParamByKey("serviceid"));
+        $job = queue(CreateVmJob::class, $arguments, $job->id, "hosting", $this->getWhmcsParamByKey("serviceid"));
+        return (new HtmlDataJsonResponse())
+            ->setStatusSuccess()
+            ->setMessageAndTranslate('The virtual server is being reinstalled')
+            ->setCallBackFunction('mgLocationReload');
+
+    }
+
+    private function jobExist(){
+        return Job::where("job", CreateVmJob::class. '@handle')->whereIn("status", ['waiting', "running", ""])
+            ->where("rel_id", $this->getWhmcsParamByKey("serviceid"))
+            ->where("rel_type", "hosting")->count() > 0;
+    }
+
+    public function processQemu()
+    {
+        if($this->jobExist()){
+            return (new HtmlDataJsonResponse())
+                ->setStatusError()
+                ->setMessageAndTranslate("Task 'Reinstall' already exist");
+        }
+        list($node, $vmid) = explode("/", $this->formData['id']);
+        $vm = new Kvm($node, $vmid);
+        $vm->setApi($this->api());
+        $templateSize = $vm->getMasterHardDisk()->getBytes();
+        if ($templateSize > $this->vm()->getMasterHardDisk()->getBytes())
+        {
+            sl("lang")->addReplacementConstant("size", Format::convertBytes($templateSize));
+            return (new HtmlDataJsonResponse())
+                ->setStatusError()
+                ->setMessageAndTranslate('OS Template require disk size :size:');
+        }
+        //automaticaly configure administartor username for window
+        $this->setHostingId($this->getWhmcsParamByKey('serviceid'));
+        if( $this->configuration()->isAgent() &&
+            $this->configuration()->isAgentServicePassword() &&
+            !$this->configuration()->isAgentTemplateUser() &&
+            preg_match('/w/', $vm ->config()['ostype'])){
+            $ciuser =  $vm->config()['ciuser'];
+            $this->hosting()->update(['username' => $ciuser ?: 'Administrator' ]);
+        }
+        elseif($this->configuration()->isQemu() && $this->configuration()->getCiuser()){
+            $this->hosting()->update(['username' =>$this->configuration()->getCiuser() ]);
+        }
+        $arguments = [
+            'hostingId'  => $this->getWhmcsParamByKey('serviceid'),
+            "osTemplate" => $this->formData['id'],
+            "password"   => encrypt(html_entity_decode($this->formData['password'],ENT_QUOTES)),
+        ];
+        if ($this->configuration()->isBackupVmBeforeReinstall())
+        {
+            $job = queue(BackupVmJob::class, $arguments, null, "hosting", $this->getWhmcsParamByKey("serviceid"));
+        }
+        $job = queue(DeleteVmJob::class, $arguments, $job->id, "hosting", $this->getWhmcsParamByKey("serviceid"));
+        $job = queue(CreateVmJob::class, $arguments, $job->id, "hosting", $this->getWhmcsParamByKey("serviceid"));
+        return (new HtmlDataJsonResponse())
+            ->setStatusSuccess()
+            ->setMessageAndTranslate('The virtual server is being reinstalled')
+            ->setCallBackFunction('mgLocationReload');
+
+    }
+
+    public function iso()
+    {
+
+    }
+
+}

+ 36 - 0
app/UI/ServiceInformation/Buttons/SshPrivateKeyDownloadButton.php

@@ -0,0 +1,36 @@
+<?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\ProxmoxVps\App\UI\ServiceInformation\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\ServiceInformation\Modals\SshPublicKeyDownloadModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+
+class SshPrivateKeyDownloadButton extends ButtonDataTableModalAction implements ClientArea
+{
+    protected $id = 'sshPrivateKeyDownloadButton';
+    protected $icon = 'lu-zmdi lu-zmdi-shield-check';
+
+    public function initContent()
+    {
+        $this->initLoadModalAction(new  SshPublicKeyDownloadModal());
+    }
+
+}

+ 37 - 0
app/UI/ServiceInformation/Buttons/UpdateButton.php

@@ -0,0 +1,37 @@
+<?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\ProxmoxVps\App\UI\ServiceInformation\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\ServiceInformation\Modals\UpdateModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+
+class UpdateButton extends ButtonDataTableModalAction implements ClientArea, AdminArea
+{
+    protected $id = 'updateeButton';
+    protected $icon = 'lu-zmdi lu-zmdi-edit';
+
+    public function initContent()
+    {
+        $this->initLoadModalAction(new UpdateModal());
+    }
+
+}

+ 33 - 0
app/UI/ServiceInformation/Forms/SshPublicKeyDownloadForm.php

@@ -0,0 +1,33 @@
+<?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\ProxmoxVps\App\UI\ServiceInformation\Forms;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+
+class SshPublicKeyDownloadForm extends BaseForm implements ClientArea
+{
+    public function initContent()
+    {
+        $this->initIds('sshPublicKeyDownloadForm');
+        $this->setConfirmMessage('SSH Key you can download only once.');
+    }
+
+}

+ 89 - 0
app/UI/ServiceInformation/Forms/UpdateForm.php

@@ -0,0 +1,89 @@
+<?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\ProxmoxVps\App\UI\ServiceInformation\Forms;
+
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\ServiceInformation\Providers\UpdateProvider;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Validators\HostnameValidator;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Validators\ShhPublicKeyValidator;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\isAdmin;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Text;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Textarea;
+
+class UpdateForm extends BaseForm implements ClientArea
+{
+    use ProductService;
+    use ApiService;
+
+    public function initContent()
+    {
+        $this->initIds('updateForm');
+        $this->setFormType('update');
+        $this->setProvider(new UpdateProvider());
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['update'];
+    }
+
+    private function initFields()
+    {
+        //Hostname
+        $field = new Text("hostname");
+        $field->addValidator(new HostnameValidator());
+        $this->addField($field);
+        if ($this->configuration()->isLxc())
+        {
+            return;
+        }
+        //ISO
+        if(isAdmin() || $this->configuration()->isPermissionIsoImage() && $this->vm()->getCdRom()->count()){
+            $field = new Select("iso");
+            $field->notEmpty();
+            $this->addField($field);
+        }
+        //boot device 1
+        $field = new Select("bootOrder0");
+        $field->notEmpty();
+        $this->addField($field);
+        //boot device 2
+        $field = new Select("bootOrder1");
+        $field->notEmpty();
+        $this->addField($field);
+        //boot device 3
+        $field = new Select("bootOrder2");
+        $field->notEmpty();
+        $this->addField($field);
+        //sshkeys for kvm only
+        if($this->configuration()->isPermissionSshkeys()){
+            $field = new Textarea("sshkeys");
+            $field->addValidator(new ShhPublicKeyValidator(false));
+            $this->addField($field);
+        }
+
+    }
+}

+ 68 - 0
app/UI/ServiceInformation/Modals/SshPublicKeyDownloadModal.php

@@ -0,0 +1,68 @@
+<?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\ProxmoxVps\App\UI\ServiceInformation\Modals;
+
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\UrlService;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Home\Buttons\RedirectButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\ServiceInformation\Forms\SshPublicKeyDownloadForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Traits\WhmcsParams;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ModalActionButtons\BaseCancelButton;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\BaseModal;
+
+class SshPublicKeyDownloadModal extends BaseModal implements ClientArea
+{
+
+    use WhmcsParams;
+    use ProductService;
+
+    public function initContent()
+    {
+        $this->initIds('sshPublicKeyDownloadModal');
+        $this->addForm(new SshPublicKeyDownloadForm());
+    }
+
+    protected function initActionButtons()
+    {
+        if (!empty($this->actionButtons))
+        {
+            return $this;
+        }
+        //URL
+        $urlService = new UrlService();
+        $rd         = new RedirectButton("sshPrivateKeyDownloadButton");
+        $rd->replaceClasses(['lu-btn lu-btn--success closeModal']);
+        $rd->setHref($urlService->getUrl("home", "sshPrivateKeyDownload"));
+        $rd->setIcon(null);
+        $rd->setShowTitle();
+        if($this->configuration()->isSshDeletePrivateKey()){
+            $rd->addClass("sshPrivateKeyDownloadButton");
+        }
+        $rd->deleteHtmlAttribute('data-toggle');
+        $rd->addHtmlAttribute('@click', 'closeModal($event)');
+        $this->addActionButton($rd);
+
+        $this->addActionButton(new BaseCancelButton());
+        return $this;
+    }
+
+
+}

+ 37 - 0
app/UI/ServiceInformation/Modals/UpdateModal.php

@@ -0,0 +1,37 @@
+<?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\ProxmoxVps\App\UI\ServiceInformation\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\ServiceInformation\Forms\UpdateForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\BaseEditModal;
+
+
+class UpdateModal extends BaseEditModal implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('updateModal');
+        $this->setModalSizeLarge();
+        $this->addForm(new UpdateForm());
+    }
+
+}

+ 206 - 0
app/UI/ServiceInformation/Pages/ServiceInformation.php

@@ -0,0 +1,206 @@
+<?php
+/* * ********************************************************************
+*  ProxmoxVPS Product developed. (26.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\ProxmoxVps\App\UI\ServiceInformation\Pages;
+
+use MGProvision\Proxmox\v2\models\Kvm;
+use MGProvision\Proxmox\v2\models\Lxc;
+use MGProvision\Proxmox\v2\models\NetworkDeviceKvm;
+use MGProvision\Proxmox\v2\models\NetworkDeviceLxc;
+use ModulesGarden\ProxmoxAddon\App\Libs\Format;
+use ModulesGarden\ProxmoxAddon\App\Models\KeyPair;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Utility;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\UrlService;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Home\Buttons\RedirectButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\ServiceInformation\Buttons\SshPrivateKeyDownloadButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\ServiceInformation\Buttons\UpdateButton;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Builder\BaseContainer;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AjaxElementInterface;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\ResponseTemplates\RawDataJsonResponse;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\isAdmin;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+use ModulesGarden\Servers\ProxmoxVps\App\Enum\ConfigurableOption;
+
+class ServiceInformation extends BaseContainer implements ClientArea, AdminArea, AjaxElementInterface
+{
+
+    use ProductService;
+    use ApiService;
+
+    protected $id = 'serviceInformationDataTable';
+    protected $title = 'serviceInformationDataTable';
+    protected $vueComponent = true;
+    protected $defaultVueComponentName = 'mg-serviceInformationDataTable';
+
+    public function initContent()
+    {
+        $this->addClass('lu-text-left');
+
+        //Update
+        $this->addButton(new UpdateButton());
+        if ($this->configuration()->isLxc() && KeyPair::ofHostingId($this->getWhmcsParamByKey('serviceid'))->count())
+        {
+            $keyPairs = KeyPair::ofHostingId($this->getWhmcsParamByKey('serviceid'))->first();
+            //URL
+            $urlService = new UrlService();
+            //Public Key
+            $rd = new RedirectButton("sshPublicKeyDownloadButton");
+            $rd->replaceClasses(['lu-btn lu-btn--sm lu-btn lu-btn--link lu-btn--icon lu-btn--plain lu-btn--default']);
+            $rd->setIcon('lu-zmdi lu-zmdi-shield-security');
+            $rd->setHref($urlService->getUrl("home", "sshPublicKeyDownload"));
+            $this->addButton($rd);
+            //Private Key
+            $deletePrivateKey = $this->configuration()->isSshDeletePrivateKey();
+            if (!$deletePrivateKey && $keyPairs->isPrivate())
+            {
+                $rd = new RedirectButton("sshPrivateKeyDownloadButton");
+                $rd->replaceClasses(['lu-btn lu-btn--sm lu-btn lu-btn--link lu-btn--icon lu-btn--plain lu-btn--default']);
+                $rd->setIcon('lu-zmdi lu-zmdi-shield-check');
+                $rd->setHref($urlService->getUrl("home", "sshPrivateKeyDownload"));
+                $this->addButton($rd);
+            }
+            else
+            {
+                if ($deletePrivateKey && $keyPairs->isPrivate())
+                {
+                    $this->addButton(new SshPrivateKeyDownloadButton());
+                }
+            }
+        }
+    }
+
+    public function returnAjaxData()
+    {
+        $vars                = [];
+        //Status
+        $status         = $this->vm()->status();
+        $vars['status'] = [
+            "uptime" => Utility::uptime($status['uptime']),
+            'cpu'    => Utility::cpuUsage($status['cpu']),
+            'cpus' => (int) $status['cpus']
+        ];
+        switch ($status['status'])
+        {
+            case 'running':
+                $vars['status']['status'] = '<span class="lu-label lu-label--success lu-label--status">' . sl('lang')->tr($status['status']) . '</span>';
+                break;
+            case 'stoped':
+                $vars['status']['status'] = '<span class="lu-label lu-label--danger lu-label--status">' . sl('lang')->tr($status['status']) . '</span>';
+            default:
+                $vars['status']['status'] = '<span class="lu-label lu-label--danger lu-label--status">' . sl('lang')->tr($status['status']) . '</span>';
+        }
+        //Memory
+        $vars['status']['memPercent'] = (int) round($status['mem'] / $status['maxmem'] * 100);
+        $vars['status']['maxmem']     = Format::convertBytes($status['maxmem']);
+        $vars['status']['mem']        = Format::convertBytes($status['mem']);
+        if ($this->vm() instanceof Lxc)
+        {
+            //SWAP
+            $vars['status']['swapPercent'] = (int) round($status['swap'] / $status['maxswap'] * 100);
+            $vars['status']['swap']        = Format::convertBytes($status['swap']);
+            $vars['status']['maxswap']     = Format::convertBytes($status['maxswap']);
+            //Disk
+            $vars['status']['diskPercent'] = (int) round($status['disk'] / $status['maxdisk'] * 100);
+            $vars['status']['disk']        = Format::convertBytes($status['disk']);
+            $vars['status']['maxdisk']     = Format::convertBytes($status['maxdisk']);
+            $vars['status']['diskwrite']   = Format::convertBytes($status['diskwrite']);
+            //Key Pairs
+            if (KeyPair::ofHostingId($this->getWhmcsParamByKey('serviceid'))->count())
+            {
+                $keyPairs                    = KeyPair::ofHostingId($this->getWhmcsParamByKey('serviceid'))->first();
+                $vars['keyPairs']['public']  = $keyPairs->isPrivate();
+                $vars['keyPairs']['private'] = $keyPairs->isPrivate();
+            }
+        }
+        if ($status['balloon_min'])
+        {
+            $vars['status']['balloon_min'] = Format::convertBytes($status['balloon_min']);
+        }
+        //Config
+        $vars['config'] = [
+            "name" => $this->vm()->config()['name'] ? $this->vm()->config()['name'] : $this->vm()->config()['hostname']
+        ];
+        if (isAdmin())
+        {
+            $vars['node'] = $this->vm()->getNode();
+        }
+        $vars['virtualization'] = $this->vm()->getVirtualization();
+        // Default configuration option
+        if (!$this->isWhmcsConfigOption(ConfigurableOption::IPV4) && $this->configuration()->getIpv4())
+        {
+            $vars['ipAddresses'] = $this->configuration()->getIpv4();
+        }
+        //BackupMaxFiles
+        if (!$this->isWhmcsConfigOption(ConfigurableOption::BACKUPS_FILES) && $this->configuration()->getBackupMaxFiles())
+        {
+            $vars['backupsFilesLimit'] = $this->configuration()->getBackupMaxFiles();
+            if($this->configuration()->getBackupMaxFiles() =="-1"){
+                $vars['backupsFilesLimit'] = sl('lang')->abtr("Unlimited");
+            }
+        }
+        //NetworkRate
+        /** @var NetworkDeviceKvm|NetworkDeviceLxc $networkDevice */
+        $networkDevice = $this->vm()->getNetworkDevices($this->configuration()->getBridge())[0];
+        if ($networkDevice && $networkDevice->getRate())
+        {
+            $vars['networkRate'] = "{$networkDevice->getRate()} MB/s ({$networkDevice->getRateMbps()} Mbps)";
+        }
+        //KVM
+        if ($this->vm() instanceof Kvm)
+        {
+            //CD-ROM
+            $vars['cdrom'] = $this->vm()->getIso();
+            //Boot order
+            $vars['bootOrder'] = [];
+            foreach ($this->vm()->getBootOrder() as $device)
+            {
+                $vars['bootOrder'][] = sl("lang")->tr("bootOrder", $device);
+            }
+            $vars['bootOrder'] = implode(", ", $vars['bootOrder']);
+            //SSH Public Key
+            $vars['sshkeysName'] = $this->vm()->sshkeysName();
+        }
+        //OS Info
+        if (isAdmin() && $this->vm()->config()['agent'] == 1)
+        {
+            try
+            {
+                $vars['osinfo']                  = $this->vm()->agent()->getOsinfo()['result'];
+                $vars['osinfo']['kernelrelease'] = $vars['osinfo']['kernel-release'];
+                $vars['hostname']                = $this->vm()->agent()->getHostname()['result']['host-name'];
+            }
+            catch (\Exception $ex)
+            {
+                $vars['quemuAgent'] = $ex->getMessage();
+            }
+        }
+        if (isAdmin() && $this->vm() instanceof  Lxc)
+        {
+            $features =  $this->vm()->config()['features'];
+            $vars['features'] = $features ? $features : "-";
+        }
+        return (new RawDataJsonResponse(['data' => $vars]));
+    }
+
+
+}

+ 167 - 0
app/UI/ServiceInformation/Providers/UpdateProvider.php

@@ -0,0 +1,167 @@
+<?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\ProxmoxVps\App\UI\ServiceInformation\Providers;
+
+use MGProvision\Proxmox\v2\models\Kvm;
+use MGProvision\Proxmox\v2\models\Lxc;
+use MGProvision\Proxmox\v2\models\NetworkDeviceKvm;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\HostingService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\isAdmin;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\ResponseTemplates\HtmlDataJsonResponse;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\DataProviders\BaseDataProvider;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+
+
+class UpdateProvider extends BaseDataProvider implements ClientArea
+{
+    use ApiService;
+    use ProductService;
+    use HostingService;
+
+    public function read()
+    {
+        if ($this->vm() instanceof Kvm)
+        {
+            //hostname
+            $this->data['hostname'] = $this->vm()->config()['name'];
+            //ISO
+            if(isAdmin() || $this->configuration()->isPermissionIsoImage()){
+                $this->data['iso']            = $this->vm()->cdrom()['isoRaw'];
+                $this->availableValues['iso'] = ["none" => sl("lang")->abtr("template", "None")];
+
+                foreach ($this->isoRepository()->fetch() as $file)
+                {
+                    if ($this->configuration()->isPermissionIsoImages() && !in_array($file->getVolid(), $this->configuration()->getPermissionIsoImages()))
+                    {
+                        continue;
+                    }
+                    $this->availableValues['iso'][$file->getVolid()] = sl("lang")->abtr("template", $file->getFriendlyName());
+                }
+            }
+            //Boot order
+            $bootOrder                           = $this->vm()->getBootOrder();
+            $this->data['bootOrder0']            = $bootOrder[0];
+            $this->data['bootOrder1']            = $bootOrder[1];
+            $this->data['bootOrder2']            = $bootOrder[2];
+            $options                             = [
+                0   => sl("lang")->tr("None"),
+                "c" => sl("lang")->tr("Disk"),
+                "d" => sl("lang")->tr("CD-ROM"),
+                "n" => sl("lang")->tr("Network"),
+            ];
+            if(version_compare($this->api()->getVersion(), "6.3", '>=')){
+                $cdrom = $this->vm()->cdrom();
+                $nd = $this->vm()->getNetworkDevices($this->configuration()->getBridge());
+                $options                             = [
+                    0   => sl("lang")->tr("None"),
+                    $this->vm()->getMasterHardDisk()->getId() => sl("lang")->tr("Disk"),
+                ];
+                if($cdrom['bus']){
+                    $options[$cdrom['bus']] = sl("lang")->tr("CD-ROM");
+                }
+                if($nd[0] instanceof  NetworkDeviceKvm){
+                    $options[$nd[0]->getId()] = sl("lang")->tr("Network");
+                }
+            }
+            $this->availableValues['bootOrder0'] = $options;
+            $this->availableValues['bootOrder1'] = $options;
+            $this->availableValues['bootOrder2'] = $options;
+            //sshkeys
+            $this->data['sshkeys'] = rawurldecode($this->vm()->config()['sshkeys']);
+        }
+        else
+        {
+            if ($this->vm() instanceof Lxc)
+            {
+                //hostname
+                $this->data['hostname'] = $this->vm()->config()['hostname'];
+            }
+        }
+
+    }
+
+    public function update()
+    {
+        if ($this->vm() instanceof Kvm)
+        {
+            //Hostname
+            $this->vm()->updateConfig(["name" => $this->formData['hostname']]);
+            //iso
+            if ($this->vm()->cdrom())
+            {
+                $this->vm()->updateCdrom($this->formData['iso']);
+            }
+            //Boot order
+            $bootOrder = null;
+            $order = [];
+            for ($i = 0; $i <= 2; $i++)
+            {
+                if ($this->formData['bootOrder' . $i])
+                {
+                    $bootOrder .= $this->formData['bootOrder' . $i];
+                    $order[] = $this->formData['bootOrder' . $i];
+                }
+            }
+            if(version_compare($this->api()->getVersion(), "6.3", '>=') && !empty($order)){
+
+                //order=scsi0;ide0;ide1;net0
+                $this->vm()->updateConfig(['boot' => "order=".implode(";", $order)]);
+            }else{
+                $this->vm()->changeBootOrder($bootOrder);
+            }
+
+            //sshkeys
+            if($this->configuration()->isPermissionSshkeys()){
+                if ($this->formData['sshkeys'])
+                {
+                    $this->vm()->updateConfig(["sshkeys" => rawurlencode($this->formData['sshkeys'])]);
+                } else if($this->vm()->config()['sshkeys'])
+                {
+                    $this->vm()->deleteConfig('sshkeys');
+                }
+                if (isset($this->getWhmcsParamByKey("customfields")['sshkeys']))
+                {
+                    $this->customFieldUpdate('sshkeys', $this->formData['sshkeys']);
+                }
+            }
+        }
+        else
+        {
+            if ($this->vm() instanceof Lxc)
+            {
+                //Hostname
+                $this->vm()->updateConfig(["hostname" => $this->formData['hostname']]);
+            }
+        }
+        if( $this->hosting()->domain != $this->formData['hostname'] ){
+            $this->hosting()->update(['domain' => $this->formData['hostname'] ]);
+        }
+
+        return (new HtmlDataJsonResponse())
+            ->setStatusSuccess()
+            ->setMessageAndTranslate('Service information has been changed')
+            ->addRefreshTargetId('serviceInformationDataTable');
+
+    }
+
+}

+ 5 - 0
app/UI/ServiceInformation/Templates/pages/serviceInformation.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}>

+ 54 - 0
app/UI/ServiceInformation/Templates/pages/serviceInformation_components.js

@@ -0,0 +1,54 @@
+mgJsComponentHandler.addDefaultComponent('mg-serviceInformationDataTable', {
+    template: '#t-mg-serviceInformationDataTable',
+    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();
+            }
+        }
+    }
+});

+ 172 - 0
app/UI/ServiceInformation/Templates/pages/serviceInformation_components.tpl

@@ -0,0 +1,172 @@
+<script type="text/x-template" id="t-mg-serviceInformationDataTable-{$elementId|strtolower}"
+        :component_id="component_id"
+        :component_namespace="component_namespace"
+        :component_index="component_index"
+>
+    <div class="lu-row lu-row--eq-height {$rawObject->getClasses()}" id="{$rawObject->getId()}" namespace="{$namespace}"
+         index="{$rawObject->getIndex()}" actionid="{$rawObject->getIndex()}">
+        <div class="lu-col-lg-12">
+            <div class="lu-widget">
+                <div class="lu-widget__header" style="border-bottom: none;">
+                    <div class="lu-widget__top lu-top">
+                        <div class="lu-top__title">
+                            {$MGLANG->absoluteT($title)}
+                        </div>
+                        <div class="lu-top__toolbar">
+                            {$rawObject->insertButton('updateeButton')}
+                        </div>
+                    </div>
+                </div>
+                <div class="lu-widget__body">
+                    <div class="no-footer">
+                        <div>
+                            <table role="grid" class="lu-table lu-table--mob-collapsible no-footer dtr-column"
+                                   width="100%" v-if="data.status">
+                                <tbody>
+                                <tr>
+                                    <td>{$MGLANG->tr('Status')}</td>
+                                    <td v-html="data.status.status"></td>
+                                </tr>
+                                <tr v-if="data.node">
+                                    <td>{$MGLANG->tr('Node')}</td>
+                                    <td>{literal}{{ data.node  }}{/literal}</td>
+                                </tr>
+                                <tr>
+                                    <td>{$MGLANG->tr('Hostname')}</td>
+                                    <td>
+                                        <span>{literal}{{ data.config.name  }} {/literal} </span>
+                                    </td>
+                                </tr>
+                                <tr v-if="data.status.uptime">
+                                    <td>{$MGLANG->tr('Uptime')}</td>
+                                    <td>
+                                        {literal} {{ data.status.uptime }} {/literal}
+                                    </td>
+                                </tr>
+                                <tr>
+                                    <td>{$MGLANG->tr('CPU Usage')}</td>
+                                    <td>
+                                        {literal}  {{ data.status.cpu }} {/literal} % {$MGLANG->tr('of')} {literal} {{ data.status.cpus }} {/literal}
+                                         {$MGLANG->tr('Cores')}
+                                        <span v-if="data.status.cpuunit"> {$MGLANG->tr('CPU Units')}  {literal} {{ data.status.cpuunit }}{/literal}</span>
+                                    </td>
+                                </tr>
+                                <tr>
+                                    <td>{$MGLANG->tr('Memory')}</td>
+                                    <td v-if="data.virtualization == 'qemu' && data.status.balloon_min">
+                                        {$MGLANG->tr('Total')}: {literal}{{ data.status.maxmem }}{/literal}
+                                        {$MGLANG->tr('Usage')}: {literal}{{ data.status.mem }}{/literal}
+                                    </td>
+                                    <td v-else>
+                                        {literal}  {{ data.status.mem  }} / {{ data.status.maxmem }} {/literal}
+                                    </td>
+                                </tr>
+                                <tr v-if="data.virtualization == 'lxc'">
+                                    <td>{$MGLANG->tr('SWAP')}</td>
+                                    <td>
+                                        {literal}   {{ data.status.swap  }} / {{ data.status.maxswap }} {/literal}
+                                    </td>
+                                </tr>
+                                <tr v-if="data.virtualization == 'lxc'">
+                                    <td>{$MGLANG->tr('Boot Disk')}</td>
+                                    <td>
+                                        {literal}    {{ data.status.disk  }} / {{ data.status.maxdisk }} {/literal}
+                                    </td>
+                                </tr>
+                                <tr v-if="data.backupsFilesLimit">
+                                    <td>{$MGLANG->tr('Backups Files Limit')}</td>
+                                    <td>
+                                        {literal}      {{ data.backupsFilesLimit }} {/literal}
+                                    </td>
+                                </tr>
+                                <tr v-if="data.networkRate">
+                                    <td>{$MGLANG->tr('Network Rate')}</td>
+                                    <td v-if="data.networkRate">
+                                        {literal}        {{ data.networkRate }} {/literal}
+                                    </td>
+                                    <td v-else>
+                                        {$MGLANG->tr('Unlimited')}
+                                    </td>
+                                </tr>
+                                <tr v-if="data.ipAddresses">
+                                    <td>{$MGLANG->tr('IP Addresses')}</td>
+                                    <td>
+                                        {literal}    {{ data.ipAddresses }} {/literal}
+                                    </td>
+                                </tr>
+                                <tr v-if="data.cdrom">
+                                    <td>{$MGLANG->tr('CD/DVD Disc Image File')}</td>
+                                    <td>
+                                        <span>{literal} {{ data.cdrom.iso }}  {/literal} </span>
+                                    </td>
+                                </tr>
+                                <tr v-if="data.bootOrder">
+                                    <td>{$MGLANG->tr('Boot Order')}</td>
+                                    <td>
+                                        <span>{literal} {{ data.bootOrder }}  {/literal} </span>
+                                    </td>
+                                </tr>
+                                <tr v-if="data.sshkeysName">
+                                    <td>{$MGLANG->tr('SSH Public Key')}</td>
+                                    <td>
+                                        <span>{literal} {{ data.sshkeysName }}  {/literal} </span>
+                                    </td>
+                                </tr>
+                                <tr v-if="data.keyPairs && data.keyPairs.public">
+                                    <td>{$MGLANG->tr('SSH Public Key')}</td>
+                                    <td>
+                                        {$rawObject->insertButton('sshPublicKeyDownloadButton')}
+                                    </td>
+                                </tr>
+                                <tr v-if="data.keyPairs && data.keyPairs.private">
+                                    <td>{$MGLANG->tr('SSH Private Key')}</td>
+                                    <td>
+                                        {$rawObject->insertButton('sshPrivateKeyDownloadButton')}
+                                    </td>
+                                </tr>
+                                <tr v-if="data.osinfo">
+                                    <td>{$MGLANG->tr('OS Info')}</td>
+                                    <td>
+                                        {literal}     {{ data.osinfo.name }} {{ data.osinfo.version }} {{ data.osinfo.machine }} {/literal}
+                                    </td>
+                                </tr>
+                                <tr v-if="data.quemuAgent">
+                                    <td>{$MGLANG->tr('Quemu Agent')}</td>
+                                    <td style="color: red">
+                                        {literal}  {{ data.quemuAgent }} {/literal}
+                                    </td>
+                                </tr>
+                                <tr v-if="data.osinfo">
+                                    <td>{$MGLANG->tr('Kernel Release')}</td>
+                                    <td>
+                                        {literal}    {{ data.osinfo.kernelrelease }} {/literal}
+                                    </td>
+                                </tr>
+                                <tr v-if="data.hostname">
+                                    <td>{$MGLANG->tr('Hostname')}</td>
+                                    <td>
+                                        {literal}   {{ data.hostname }} {/literal}
+                                    </td>
+                                </tr>
+                                <tr v-if="data.features">
+                                    <td>{$MGLANG->tr('Features')}</td>
+                                    <td>
+                                        {{ data.features }}
+                                    </td>
+                                </tr>
+                                </tbody>
+                            </table>
+                            <div v-else style="padding: 15px; text-align: center; border-top: 1px solid #e9ebf0;">
+                                {$MGLANG->absoluteT('noDataAvalible')}
+                            </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>

+ 35 - 0
app/UI/Snapshot/Buttons/CreateButton.php

@@ -0,0 +1,35 @@
+<?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\ProxmoxVps\App\UI\Snapshot\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Modals\CreateModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonCreate;
+
+class CreateButton extends ButtonCreate implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('createButton');
+        $this->initLoadModalAction(new CreateModal());
+    }
+
+}

+ 35 - 0
app/UI/Snapshot/Buttons/CreateJobButton.php

@@ -0,0 +1,35 @@
+<?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\ProxmoxVps\App\UI\Snapshot\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Modals\CreateJobModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonCreate;
+
+class CreateJobButton extends ButtonCreate implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('createJobButton');
+        $this->initLoadModalAction(new CreateJobModal());
+    }
+
+}

+ 36 - 0
app/UI/Snapshot/Buttons/DeleteButton.php

@@ -0,0 +1,36 @@
+<?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\ProxmoxVps\App\UI\Snapshot\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Modals\DeleteModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+
+class DeleteButton extends ButtonDataTableModalAction implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('deleteButton');
+        $this->switchToRemoveBtn();
+        $this->initLoadModalAction(new DeleteModal());
+    }
+
+}

+ 36 - 0
app/UI/Snapshot/Buttons/DeleteJobButton.php

@@ -0,0 +1,36 @@
+<?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\ProxmoxVps\App\UI\Snapshot\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Modals\DeleteJobModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+
+class DeleteJobButton extends ButtonDataTableModalAction implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('deleteJobButton');
+        $this->switchToRemoveBtn();
+        $this->initLoadModalAction(new DeleteJobModal());
+    }
+
+}

+ 36 - 0
app/UI/Snapshot/Buttons/DeleteJobMassButton.php

@@ -0,0 +1,36 @@
+<?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\ProxmoxVps\App\UI\Snapshot\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Modals\DeleteJobMassModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonMassAction;
+
+class DeleteJobMassButton extends ButtonMassAction implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('deleteJobMassButton');
+        $this->switchToRemoveBtn();
+        $this->initLoadModalAction(new DeleteJobMassModal());
+    }
+
+}

+ 36 - 0
app/UI/Snapshot/Buttons/DeleteMassButton.php

@@ -0,0 +1,36 @@
+<?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\ProxmoxVps\App\UI\Snapshot\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Modals\DeleteMassModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonMassAction;
+
+class DeleteMassButton extends ButtonMassAction implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('deleteMassButton');
+        $this->switchToRemoveBtn();
+        $this->initLoadModalAction(new DeleteMassModal());
+    }
+
+}

+ 36 - 0
app/UI/Snapshot/Buttons/RollbackButton.php

@@ -0,0 +1,36 @@
+<?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\ProxmoxVps\App\UI\Snapshot\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Modals\RollbackModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+
+class RollbackButton extends ButtonDataTableModalAction implements ClientArea
+{
+    protected $icon = 'lu-zmdi lu-zmdi-time-restore-setting';
+
+    public function initContent()
+    {
+        $this->initIds('rollbackButton ');
+        $this->initLoadModalAction(new RollbackModal());
+    }
+
+}

+ 35 - 0
app/UI/Snapshot/Buttons/UpdateButton.php

@@ -0,0 +1,35 @@
+<?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\ProxmoxVps\App\UI\Snapshot\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Modals\UpdateModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+
+class UpdateButton extends ButtonDataTableModalAction implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('updateButton');
+        $this->initLoadModalAction(new UpdateModal());
+    }
+
+}

+ 35 - 0
app/UI/Snapshot/Buttons/UpdateJobButton.php

@@ -0,0 +1,35 @@
+<?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\ProxmoxVps\App\UI\Snapshot\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Modals\UpdateJobModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+
+class UpdateJobButton extends ButtonDataTableModalAction implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('updateJobButton');
+        $this->initLoadModalAction(new UpdateJobModal());
+    }
+
+}

+ 73 - 0
app/UI/Snapshot/Forms/CreateForm.php

@@ -0,0 +1,73 @@
+<?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\ProxmoxVps\App\UI\Snapshot\Forms;
+
+use MGProvision\Proxmox\v2\models\Kvm;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Providers\SnapshotProvider;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Validators\SnapshotValidator;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Helpers\AlertTypesConstants;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Text;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Textarea;
+
+
+class CreateForm extends BaseForm implements ClientArea
+{
+    use ApiService;
+    use ProductService;
+
+    public function initContent()
+    {
+        $this->initIds('createForm');
+        $this->setFormType('create');
+        $this->setProvider(new SnapshotProvider());
+        $this->setInternalAlertMessage('confirmCreate');
+        $this->setInternalAlertMessageType(AlertTypesConstants::INFO);
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['create'];
+    }
+
+    private function initFields()
+    {
+        //name
+        $field = new Text('name');
+        $field->notEmpty();
+        $field->addValidator(new SnapshotValidator(true));
+        $this->addField($field);
+        if ($this->vm() instanceof Kvm)
+        {
+            //vmstate
+            $field = new Switcher("vmstate");
+            $this->addField($field);
+        }
+        //description
+        $field = new Textarea("description");
+        $this->addField($field);
+    }
+}

+ 59 - 0
app/UI/Snapshot/Forms/CreateJobForm.php

@@ -0,0 +1,59 @@
+<?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\ProxmoxVps\App\UI\Snapshot\Forms;
+
+use MGProvision\Proxmox\v2\models\Kvm;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\Enum\ConfigurableOption;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Providers\JobProvider;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Providers\SnapshotProvider;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Validators\SnapshotValidator;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Helpers\AlertTypesConstants;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Text;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Textarea;
+
+
+class CreateJobForm extends BaseForm implements ClientArea
+{
+    use ApiService;
+    use ProductService;
+    use JobForm;
+
+    public function initContent()
+    {
+        $this->initIds('createJobForm');
+        $this->setFormType('create');
+        $this->setProvider(new JobProvider());
+        $this->setJobConfirmMessage();
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['create'];
+    }
+
+}

+ 50 - 0
app/UI/Snapshot/Forms/DeleteForm.php

@@ -0,0 +1,50 @@
+<?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\ProxmoxVps\App\UI\Snapshot\Forms;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Providers\SnapshotProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Hidden;
+
+
+class DeleteForm extends BaseForm implements ClientArea
+{
+    public function initContent()
+    {
+        $this->initIds('deleteForm');
+        $this->setFormType('delete');
+        $this->setProvider(new SnapshotProvider());
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['delete'];
+    }
+
+    private function initFields()
+    {
+        $this->setConfirmMessage('conforimDelete');
+        $this->addField(new Hidden("name"));
+    }
+
+}

+ 52 - 0
app/UI/Snapshot/Forms/DeleteJobForm.php

@@ -0,0 +1,52 @@
+<?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\ProxmoxVps\App\UI\Snapshot\Forms;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Providers\JobProvider;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Providers\SnapshotProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Hidden;
+
+
+class DeleteJobForm extends BaseForm implements ClientArea
+{
+    public function initContent()
+    {
+        $this->initIds('deleteJobForm');
+        $this->setFormType('delete');
+        $this->setProvider(new JobProvider());
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['delete'];
+    }
+
+    private function initFields()
+    {
+        $this->setConfirmMessage('conforimJobDelete',["name"=> null]);
+        $this->addField(new Hidden("id"));
+        $this->addField(new Hidden("name"));
+    }
+
+}

+ 50 - 0
app/UI/Snapshot/Forms/DeleteJobMassForm.php

@@ -0,0 +1,50 @@
+<?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\ProxmoxVps\App\UI\Snapshot\Forms;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Providers\BackupProvider;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Providers\JobProvider;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Providers\SnapshotProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+
+
+class DeleteJobMassForm extends BaseForm implements ClientArea
+{
+    public function initContent()
+    {
+        $this->initIds('deleteJobMassForm');
+        $this->setFormType('deleteMass');
+        $this->setProvider(new JobProvider());
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['deleteMass'];
+    }
+
+    private function initFields()
+    {
+        $this->setConfirmMessage('conforimDeleteJobMass');
+    }
+
+}

+ 49 - 0
app/UI/Snapshot/Forms/DeleteMassForm.php

@@ -0,0 +1,49 @@
+<?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\ProxmoxVps\App\UI\Snapshot\Forms;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Providers\BackupProvider;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Providers\SnapshotProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+
+
+class DeleteMassForm extends BaseForm implements ClientArea
+{
+    public function initContent()
+    {
+        $this->initIds('deleteMassForm');
+        $this->setFormType('deleteMass');
+        $this->setProvider(new SnapshotProvider());
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['deleteMass'];
+    }
+
+    private function initFields()
+    {
+        $this->setConfirmMessage('conforimDeleteMass');
+    }
+
+}

+ 102 - 0
app/UI/Snapshot/Forms/JobForm.php

@@ -0,0 +1,102 @@
+<?php
+
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Forms;
+
+use MGProvision\Proxmox\v2\models\Kvm;
+use ModulesGarden\Servers\ProxmoxVps\App\Enum\ConfigurableOption;
+use ModulesGarden\Servers\ProxmoxVps\App\Enum\JobPeriod;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Validators\SnapshotValidator;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Validators\StartTimeValidator;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Hidden;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Number;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Text;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Textarea;
+
+trait JobForm
+{
+
+    public function setJobConfirmMessage(){
+        $limit = $this->getWhmcsConfigOption(ConfigurableOption::SNAPSHOTS, $this->configuration()->getSnapshotMaxFiles());
+        if ($limit && $limit != "-1")
+        {
+            sl("lang")->addReplacementConstant("snapshotFilesLimit" , $limit);
+            $this->setInternalAlertMessage( sl("lang")->tr('Your snapshot limit is :snapshotFilesLimit:. When you exceed this limit, the last snapshot will be replaced with a new one.'));
+            $this->setInternalAlertMessageRaw(true);
+        }
+    }
+
+    protected function initFields()
+    {
+        $formData = $this->getRequestValue("formData");
+        //id
+        $id = false;
+        if(is_numeric($this->getRequestValue("actionElementId"))){
+            $id = $this->getRequestValue("actionElementId");
+        }
+        if ($formData && $formData['id']){
+            $id =  $formData['id'];
+        }
+        //hourly
+        $isHourly = true;
+        if($formData &&  $formData['period'] ){
+            $isHourly = $formData['period'] == JobPeriod::HOURLY;
+        } elseif (!$formData && $id){
+            $this->loadProvider();
+            $this->dataProvider->read();
+            $isHourly = $this->dataProvider->getValueById('period') == JobPeriod::HOURLY ;
+        }elseif (!$formData && !$id){
+            $period = $this->configuration()->getPermissionSnapshotJobPeriod();
+            if($period && in_array(JobPeriod::HOURLY, $period)){
+                $isHourly = true;
+            }elseif ($period ){
+                $isHourly = false;
+            }
+        }
+        //id
+        if(is_numeric($this->getRequestValue("actionElementId"))){
+            $this->addField(new Hidden("id"));
+        }
+        //period
+        $field = new Select('period');
+        $field->addHtmlAttribute('bi-event-change', "reloadVueModal");
+        $this->addField($field);
+        //run_every
+        if($isHourly){
+            $field = new Number('run_every',1,48);
+            $field->setPlaceholder("1");
+            $this->addField($field);
+        }
+        //days
+        if(!$isHourly){
+            $field = new Select('days');
+            $field->enableMultiple();
+            $this->addField($field);
+        }
+        //start_time
+        if(!$isHourly){
+            $field = new Text('start_time');
+            $field->setPlaceholder("00:00");
+            $field->addValidator(new StartTimeValidator(false));
+            $this->addField($field);
+        }
+        //name
+        $field = new Text('name');
+        $field->notEmpty();
+        $field->addValidator(new SnapshotValidator(true));
+        $this->addField($field);
+        //vmstate
+        if ($this->vm() instanceof Kvm)
+        {
+            $field = new Switcher("vmstate");
+            $this->addField($field);
+        }
+        //description
+        $field = new Textarea("description");
+        $this->addField($field);
+
+    }
+}

+ 49 - 0
app/UI/Snapshot/Forms/RollbackForm.php

@@ -0,0 +1,49 @@
+<?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\ProxmoxVps\App\UI\Snapshot\Forms;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Providers\SnapshotProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Hidden;
+
+
+class RollbackForm extends BaseForm implements ClientArea
+{
+    public function initContent()
+    {
+        $this->initIds('rollbackForm');
+        $this->setFormType('rollback');
+        $this->setProvider(new SnapshotProvider());
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['rollback'];
+    }
+
+    private function initFields()
+    {
+        $this->setConfirmMessage('confirmRestore');
+        $this->addField(new Hidden("name"));
+    }
+}

+ 54 - 0
app/UI/Snapshot/Forms/UpdateForm.php

@@ -0,0 +1,54 @@
+<?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\ProxmoxVps\App\UI\Snapshot\Forms;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Providers\SnapshotProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Hidden;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Textarea;
+
+
+class UpdateForm extends BaseForm implements ClientArea
+{
+    public function initContent()
+    {
+        $this->initIds('updateForm');
+        $this->setFormType('update');
+        $this->setProvider(new SnapshotProvider());
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['update'];
+    }
+
+    private function initFields()
+    {
+        //name
+        $field = new Hidden('name');
+        $this->addField($field);
+        //description
+        $field = new Textarea("description");
+        $this->addField($field);
+    }
+}

+ 53 - 0
app/UI/Snapshot/Forms/UpdateJobForm.php

@@ -0,0 +1,53 @@
+<?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\ProxmoxVps\App\UI\Snapshot\Forms;
+
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Providers\JobProvider;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Providers\SnapshotProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Hidden;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Textarea;
+
+
+class UpdateJobForm extends BaseForm implements ClientArea
+{
+    use ApiService;
+    use ProductService;
+    use JobForm;
+
+    public function initContent()
+    {
+        $this->initIds('updateJobForm');
+        $this->setFormType('update');
+        $this->setProvider(new JobProvider());
+        $this->setJobConfirmMessage();
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['update'];
+    }
+
+}

+ 37 - 0
app/UI/Snapshot/Modals/CreateJobModal.php

@@ -0,0 +1,37 @@
+<?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\ProxmoxVps\App\UI\Snapshot\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Forms\CreateForm;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Forms\CreateJobForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\BaseEditModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmSuccess;
+
+class CreateJobModal extends BaseEditModal implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('createJobModal');
+        $this->addForm(new CreateJobForm());
+    }
+
+}

+ 36 - 0
app/UI/Snapshot/Modals/CreateModal.php

@@ -0,0 +1,36 @@
+<?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\ProxmoxVps\App\UI\Snapshot\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Forms\CreateForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\BaseEditModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmSuccess;
+
+class CreateModal extends BaseEditModal implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('createModal');
+        $this->addForm(new CreateForm());
+    }
+
+}

+ 36 - 0
app/UI/Snapshot/Modals/DeleteJobMassModal.php

@@ -0,0 +1,36 @@
+<?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\ProxmoxVps\App\UI\Snapshot\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Forms\DeleteJobMassForm;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Forms\DeleteMassForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmDanger;
+
+class DeleteJobMassModal extends ModalConfirmDanger implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('deleteJobMassModal');
+        $this->addForm(new DeleteJobMassForm());
+    }
+
+}

+ 36 - 0
app/UI/Snapshot/Modals/DeleteJobModal.php

@@ -0,0 +1,36 @@
+<?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\ProxmoxVps\App\UI\Snapshot\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Forms\DeleteForm;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Forms\DeleteJobForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmDanger;
+
+class DeleteJobModal extends ModalConfirmDanger implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('deleteJobModal');
+        $this->addForm(new DeleteJobForm());
+    }
+
+}

+ 35 - 0
app/UI/Snapshot/Modals/DeleteMassModal.php

@@ -0,0 +1,35 @@
+<?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\ProxmoxVps\App\UI\Snapshot\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Forms\DeleteMassForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmDanger;
+
+class DeleteMassModal extends ModalConfirmDanger implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('deleteMassModal');
+        $this->addForm(new DeleteMassForm());
+    }
+
+}

+ 35 - 0
app/UI/Snapshot/Modals/DeleteModal.php

@@ -0,0 +1,35 @@
+<?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\ProxmoxVps\App\UI\Snapshot\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Forms\DeleteForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmDanger;
+
+class DeleteModal extends ModalConfirmDanger implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('deleteModal');
+        $this->addForm(new DeleteForm());
+    }
+
+}

+ 36 - 0
app/UI/Snapshot/Modals/RollbackModal.php

@@ -0,0 +1,36 @@
+<?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\ProxmoxVps\App\UI\Snapshot\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Forms\RollbackForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmDanger;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmSuccess;
+
+class RollbackModal extends ModalConfirmDanger implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('rollbackModal');
+        $this->addForm(new RollbackForm());
+    }
+
+}

+ 37 - 0
app/UI/Snapshot/Modals/UpdateJobModal.php

@@ -0,0 +1,37 @@
+<?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\ProxmoxVps\App\UI\Snapshot\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Forms\UpdateForm;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Forms\UpdateJobForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\BaseEditModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmSuccess;
+
+class UpdateJobModal extends BaseEditModal implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('updateJobModal');
+        $this->addForm(new UpdateJobForm());
+    }
+
+}

+ 36 - 0
app/UI/Snapshot/Modals/UpdateModal.php

@@ -0,0 +1,36 @@
+<?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\ProxmoxVps\App\UI\Snapshot\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Forms\UpdateForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\BaseEditModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmSuccess;
+
+class UpdateModal extends BaseEditModal implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('updateModal');
+        $this->addForm(new UpdateForm());
+    }
+
+}

+ 134 - 0
app/UI/Snapshot/Pages/JobRawDataTable.php

@@ -0,0 +1,134 @@
+<?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\ProxmoxVps\App\UI\Snapshot\Pages;
+use MGProvision\Proxmox\v2\models\Kvm;
+use MGProvision\Proxmox\v2\repository\SnapshotRepository;
+use ModulesGarden\ProxmoxAddon\App\Models\SnapshotJob;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\Enum\JobPeriod;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Buttons\CreateButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Buttons\CreateJobButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Buttons\DeleteButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Buttons\DeleteJobButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Buttons\DeleteJobMassButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Buttons\DeleteMassButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Buttons\RollbackButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Buttons\UpdateButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Buttons\UpdateJobButton;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\Column;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\DataProviders\Providers\ArrayDataProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\DataProviders\Providers\QueryDataProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\RawDataTable\RawDataTable;
+
+class JobRawDataTable extends RawDataTable implements ClientArea, AdminArea
+{
+    use ApiService;
+    use ProductService;
+
+    protected $id = 'jobDataTable';
+    protected $title = 'jobDataTable';
+
+    public function initContent()
+    {
+        //Create
+        $createButton = new CreateJobButton();
+        $createButton->addClass("pmCreateJobButton");
+        if (!$this->resourceGuard()->hasSnapshotJobLimit())
+        {
+            $createButton->addClass("hidden");
+        }
+        $this->addButton($createButton);
+        //Update
+        $this->addActionButton(new UpdateJobButton());
+        //Delete
+        $this->addActionButton(new DeleteJobButton());
+        //Mass delete
+        $this->addMassActionButton(new DeleteJobMassButton());
+    }
+
+    protected function loadHtml()
+    {
+        $this->addColumn((new Column('name'))->setSearchable(true, "string")->setOrderable());
+        if ($this->vm() instanceof Kvm)
+        {
+            $this->addColumn((new Column('vmstate'))->setSearchable(true)->setOrderable());
+        }
+        $this->addColumn((new Column('description'))->setSearchable(true)->setOrderable());
+        $this->addColumn((new Column('days'))->setSearchable(true))
+             ->addColumn((new Column('created_at'))->setSearchable(true, "date")->setOrderable('DESC'));
+
+    }
+
+
+    public function replaceFieldVmstate($key, $row)
+    {
+        if ($row->vmstate == "1")
+        {
+            return '<span class="lu-label lu-label--success lu-label--status">' . sl('lang')->tr("Yes") . '</span>';
+        }
+        return '<span class="lu-label lu-label--danger lu-label--status">' . sl('lang')->tr("No") . '</span>';
+    }
+
+    public function replaceFieldDescription($key, $row)
+    {
+        if ($row->description)
+        {
+            return $row->description;
+        }
+        return '-';
+    }
+
+    public function replaceFieldDays($key, $row)
+    {
+
+        if($row->period == JobPeriod::DAILY && $row->days){
+            $row = json_decode($row->days, true);
+            foreach ($row as &$day){
+                $day = sl("lang")->tr($day);
+            }
+            return implode(", ", $row);
+        }elseif ($row->period == JobPeriod::HOURLY && $row->run_every &&  $row->run_every == 1){
+            sl('lang')->addReplacementConstant('run_every', $row->run_every);
+            return sl("lang")->tr("Every :run_every: hour");
+        }elseif ($row->period == JobPeriod::HOURLY && $row->run_every &&  $row->run_every > 1){
+            sl('lang')->addReplacementConstant('run_every', $row->run_every);
+            return sl("lang")->tr("Every :run_every: hours");
+        }
+        return '-';
+    }
+
+    protected function loadData()
+    {
+        $query    = (new SnapshotJob())
+            ->query()
+            ->getQuery()
+            ->select('id','name','description','vmstate','period', 'run_every','days','start_time','updated_at','created_at')
+            ->where("hosting_id", $this->getWhmcsParamByKey('serviceid'));
+        $dataProv = new QueryDataProvider();
+        $dataProv->setData($query);
+        $dataProv->setDefaultSorting("created_at", 'DESC');
+        $this->setDataProvider($dataProv);
+    }
+
+}

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

@@ -0,0 +1,46 @@
+<?php
+/* * ********************************************************************
+*  ProxmoxVPS Product developed. (26.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\ProxmoxVps\App\UI\Snapshot\Pages;
+
+use MGProvision\Proxmox\v2\models\Kvm;
+use MGProvision\Proxmox\v2\repository\SnapshotRepository;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Buttons\CreateButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Buttons\DeleteButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Buttons\DeleteMassButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Buttons\MailtoSwitchButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Buttons\RollbackButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Buttons\UpdateButton;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\Column;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\DataProviders\Providers\ArrayDataProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\DataTable;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+
+class SnapshotDataTable extends DataTable implements ClientArea
+{
+    use SnapshotTrait;
+
+    protected $id = 'snapshotDataTable';
+    protected $title = 'snapshotDataTable';
+
+
+}

+ 19 - 0
app/UI/Snapshot/Pages/SnapshotRawDataTable.php

@@ -0,0 +1,19 @@
+<?php
+
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Pages;
+
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\RawDataTable\RawDataTable;
+
+class SnapshotRawDataTable extends RawDataTable implements ClientArea, AdminArea
+{
+    use SnapshotTrait;
+
+    protected $id = 'snapshotDataTable';
+    protected $title = 'snapshotDataTable';
+
+
+}

+ 39 - 0
app/UI/Snapshot/Pages/SnapshotTab.php

@@ -0,0 +1,39 @@
+<?php
+/* * ********************************************************************
+*  ProxmoxVPS Product developed. (26.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\ProxmoxVps\App\UI\Snapshot\Pages;
+
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\TabsWidget\TabsWidget;
+
+class SnapshotTab extends TabsWidget implements ClientArea, AdminArea
+{
+    protected $id = 'snapshotTab';
+    protected $name = 'snapshotTab';
+    protected $vueComponent = true;
+
+    public function initContent()
+    {
+        $this->addElement(new SnapshotRawDataTable());
+        $this->addElement(new JobRawDataTable());
+
+    }
+}

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

@@ -0,0 +1,116 @@
+<?php
+
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Pages;
+
+
+use MGProvision\Proxmox\v2\models\Kvm;
+use MGProvision\Proxmox\v2\repository\SnapshotRepository;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Buttons\CreateButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Buttons\DeleteButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Buttons\DeleteMassButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Buttons\RollbackButton;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Buttons\UpdateButton;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\Column;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\DataProviders\Providers\ArrayDataProvider;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+
+trait SnapshotTrait
+{
+    use ApiService;
+    use ProductService;
+
+    /**
+     * @var SnapshotRepository
+     */
+    private $snapshotRepository;
+
+    public function initContent()
+    {
+        //Create
+        $createButton = new CreateButton();
+        $createButton->addClass("pmCreateButton");
+        if (!$this->resourceGuard()->hasSnapshotLimit())
+        {
+            $createButton->addClass("hidden");
+        }
+        $this->addButton($createButton);
+        //rollback
+        $this->addActionButton(new RollbackButton());
+        //Update
+        $this->addActionButton(new UpdateButton());
+        //Delete
+        $this->addActionButton(new DeleteButton());
+        //Mass delete
+        $this->addMassActionButton(new DeleteMassButton());
+        $this->snapshotRepository = new SnapshotRepository();
+    }
+
+    protected function loadHtml()
+    {
+        $this->addColumn((new Column('name'))->setSearchable(true, "string")->setOrderable())
+            ->addColumn((new Column('status'))->setSearchable(true, "string")->setOrderable());
+        if ($this->vm() instanceof Kvm)
+        {
+            $this->addColumn((new Column('vmstate'))->setSearchable(true)->setOrderable());
+        }
+        $this->addColumn((new Column('snaptime'))->setSearchable(true, "date")->setOrderable('DESC'))
+            ->addColumn((new Column('description'))->setSearchable(true)->setOrderable());
+    }
+
+
+    public function replaceFieldStatus($key, $row)
+    {
+        //current
+        if ($this->snapshotRepository->getCurrent()->getParent() == $row['name'])
+        {
+            return '<span class="lu-label lu-label--success lu-label--status">' . sl('lang')->tr("Active") . '</span>';
+        }
+        return '<span class="lu-label lu-label--danger lu-label--status">' . sl('lang')->tr("Disabled") . '</span>';
+
+
+    }
+
+    public function replaceFieldVmstate($key, $row)
+    {
+        if ($row['vmstate'] == "1")
+        {
+            return '<span class="lu-label lu-label--success lu-label--status">' . sl('lang')->tr("Yes") . '</span>';
+        }
+        return '<span class="lu-label lu-label--danger lu-label--status">' . sl('lang')->tr("No") . '</span>';
+    }
+
+    public function replaceFieldSnaptime($key, $row)
+    {
+        return date('Y-m-d H:i:s', $row[$key]);
+    }
+
+    public function replaceFieldDescription($key, $row)
+    {
+        if ($row['description'])
+        {
+            return $row['description'];
+        }
+        return '-';
+    }
+
+    protected function loadData()
+    {
+        $this->snapshotRepository->setApi($this->api());
+        $this->snapshotRepository->findByVm($this->vm());
+        $this->snapshotRepository->ignoreCurrent(true);
+        $data = [];
+        foreach ($this->snapshotRepository->fetch() as $entity)
+        {
+            $row    = $entity->getAttributes();
+            $data[] = array_merge(['id' => base64_encode(json_encode($row))], $row);
+        }
+        $dataProv = new ArrayDataProvider();
+        $dataProv->setDefaultSorting("snaptime", 'DESC');
+        $dataProv->setData($data);
+        $this->setDataProvider($dataProv);
+    }
+
+}

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

@@ -0,0 +1,121 @@
+<?php
+
+
+namespace ModulesGarden\Servers\ProxmoxVps\App\UI\Snapshot\Providers;
+
+
+use ModulesGarden\ProxmoxAddon\App\Models\SnapshotJob;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\Enum\JobPeriod;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\ResponseTemplates\HtmlDataJsonResponse;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\DataProviders\BaseModelDataProvider;
+
+class JobProvider  extends BaseModelDataProvider implements ClientArea
+{
+    use ProductService;
+
+    public function __construct()
+    {
+        parent::__construct(SnapshotJob::class);
+    }
+
+    protected function isModelProper($model)
+    {
+        if (in_array(get_parent_class($model), [
+            'ModulesGarden\Servers\ProxmoxVps\Core\Models\ExtendedEloquentModel',
+            'ModulesGarden\ProxmoxAddon\Core\Models\ExtendedEloquentModel',
+            'Illuminate\Database\Eloquent\Model'
+        ]))
+        {
+            return true;
+        }
+
+        return false;
+    }
+
+    public function read()
+    {
+        //period
+        $period = $this->configuration()->getPermissionSnapshotJobPeriod();
+        if($period && in_array(JobPeriod::HOURLY, $period)){
+            $this->availableValues['period'][JobPeriod::HOURLY] = sl("lang")->tr(JobPeriod::HOURLY );
+        }
+        if($period && in_array(JobPeriod::DAILY, $period)){
+            $this->availableValues['period'][JobPeriod::DAILY] = sl("lang")->tr(JobPeriod::DAILY);
+        }
+        if(!$period){
+            $this->availableValues['period'] = [
+                JobPeriod::HOURLY => sl("lang")->tr(JobPeriod::HOURLY ),
+                JobPeriod::DAILY => sl("lang")->tr(JobPeriod::DAILY )
+            ];
+        }
+         //days
+        $this->availableValues['days'] = [];
+        foreach (JobPeriod::DAYS_OF_WEEK as $day){
+            $this->availableValues['days'][$day] =  sl("lang")->tr($day);
+        }
+        if($this->formData){
+            $this->data = $this->formData;
+            return;
+        }
+        parent::read();
+        $vmstate = $this->data['vmstate']==1 ? "on":"off" ;
+        $this->data['vmstate']= $vmstate;
+        //start_time
+        if($this->data['start_time']){
+            $this->data['start_time'] = substr($this->data['start_time'], 0,-3);
+        }
+    }
+
+    public function create()
+    {
+        //vmstate
+        if(isset($this->formData['vmstate'])){
+            $vmstate = $this->formData['vmstate']=="on" ? 1:0;
+            $this->formData['vmstate']= $vmstate ;
+        }
+        //hosting_id
+        $this->formData['hosting_id']= $this->getWhmcsParamByKey('serviceid');
+        //fill from data
+        $this->model->fill($this->formData)->save();
+        sl('lang')->addReplacementConstant('name', $this->formData['name']);
+        return (new HtmlDataJsonResponse())->setMessageAndTranslate('Snapshot Job :name: has been created successfully')
+            ->addData('createJobButtonStatus', $this->resourceGuard()->hasSnapshotJobLimit())
+            ->setCallBackFunction('pmToggleCreateJobButton');
+    }
+
+    public function update(){
+
+        //vmstate
+        if(isset($this->formData['vmstate'])){
+            $vmstate = $this->formData['vmstate']=="on" ? 1:0;
+            $this->formData['vmstate']= $vmstate ;
+        }
+        parent::update();
+        sl('lang')->addReplacementConstant('name', $this->formData['name']);
+        return (new HtmlDataJsonResponse())->setMessageAndTranslate('Snapshot Job :name: has updated successfully');
+    }
+
+    public function deleteMass()
+    {
+        foreach ($this->getRequestValue('massActions') as $id)
+        {
+            $this->model->where('id', $id)->delete();
+        }
+        return (new HtmlDataJsonResponse())->setMessageAndTranslate('The selected snapshot jobs have been deleted successfully')
+            ->addData('createJobButtonStatus', $this->resourceGuard()->hasSnapshotJobLimit())
+            ->setCallBackFunction('pmToggleCreateJobButton');
+    }
+
+
+    public function delete()
+    {
+        parent::delete();
+        sl('lang')->addReplacementConstant('name', $this->formData['name']);
+        return (new HtmlDataJsonResponse())->setMessageAndTranslate('Snapshot Job :name: has been deleted successfully')
+            ->addData('createJobButtonStatus', $this->resourceGuard()->hasSnapshotJobLimit())
+            ->setCallBackFunction('pmToggleCreateJobButton');
+    }
+}

+ 138 - 0
app/UI/Snapshot/Providers/SnapshotProvider.php

@@ -0,0 +1,138 @@
+<?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\ProxmoxVps\App\UI\Snapshot\Providers;
+
+use MGProvision\Proxmox\v2\models\Snapshot;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\ResponseTemplates\HtmlDataJsonResponse;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\DataProviders\BaseDataProvider;
+
+
+class SnapshotProvider extends BaseDataProvider implements ClientArea
+{
+    use ProductService;
+    use ApiService;
+
+    public function read()
+    {
+        if ($this->actionElementId)
+        {
+            $this->data = json_decode(base64_decode($this->actionElementId), true);
+        }
+    }
+
+    public function create()
+    {
+
+        $this->acl()->snapshot();
+        $this->resourceGuard()->snapshotLimit();
+
+        $snapshot = new Snapshot();
+        $snapshot->setApi($this->api());
+        $snapshot->setPath($this->vm()->getPath() . "/snapshot");
+        $snapshot->setAttributes([
+            "name"        => $this->formData['name'],
+            "description" => $this->formData['description'],
+        ]);
+        if ($this->formData['vmstate'])
+        {
+            $snapshot->setVmstate($this->formData['vmstate'] == "on" ? 1 : 0);
+        }
+        $taskId =  $snapshot->create();
+        sleep(1);
+        $task = $this->vm()->node()->task($taskId);
+         if($task->isFalied()){
+             return (new HtmlDataJsonResponse())
+                 ->setStatusError()
+                 ->setMessageAndTranslate($task->getExitstatus());
+         }
+        return (new HtmlDataJsonResponse())
+            ->setStatusSuccess()
+            ->setMessageAndTranslate('The snapshot has been created successfully')
+            ->addData('createButtonStatus', $this->resourceGuard()->hasSnapshotLimit())
+            ->setCallBackFunction('pmToggleButton');
+    }
+
+    public function update()
+    {
+        $this->acl()->snapshot();
+        $snapshot = new Snapshot();
+        $snapshot->setApi($this->api());
+        $snapshot->setPath($this->vm()->getPath() . "/snapshot/" . $this->formData['name']);
+        $snapshot->setAttributes([
+            "name"        => $this->formData['name'],
+            "description" => $this->formData['description'],
+        ]);
+        $snapshot->update();
+        return (new HtmlDataJsonResponse())
+            ->setStatusSuccess()
+            ->setMessageAndTranslate('The snapshot has been updated successfully');
+    }
+
+    public function delete()
+    {
+        $this->acl()->snapshot();
+        $snapshot = new Snapshot();
+        $snapshot->setApi($this->api());
+        $snapshot->setPath($this->vm()->getPath() . "/snapshot/" . $this->formData['name']);
+        $snapshot->delete();
+        sleep(1);
+        return (new HtmlDataJsonResponse())
+            ->setStatusSuccess()
+            ->setMessageAndTranslate('The snapshot has been deleted successfully')
+            ->addData('createButtonStatus', $this->resourceGuard()->hasSnapshotLimit())
+            ->setCallBackFunction('pmToggleButton');
+    }
+
+    public function deleteMass()
+    {
+        $this->acl()->snapshot();
+        $snapshot = new Snapshot();
+        $snapshot->setApi($this->api());
+        foreach ($this->request->get('massActions') as $id)
+        {
+            $data = json_decode(base64_decode($id), true);
+            $name = $data['name'];
+            $snapshot->setPath($this->vm()->getPath() . "/snapshot/" . $name);
+            $snapshot->delete();
+            sleep(1);
+        }
+        return (new HtmlDataJsonResponse())
+            ->setStatusSuccess()
+            ->setMessageAndTranslate('The snapshots have been deleted successfully')
+            ->addData('createButtonStatus', $this->resourceGuard()->hasSnapshotLimit())
+            ->setCallBackFunction('pmToggleButton');
+    }
+
+    public function rollback()
+    {
+        $this->acl()->snapshot();
+        $snapshot = new Snapshot();
+        $snapshot->setApi($this->api());
+        $snapshot->setPath($this->vm()->getPath() . "/snapshot/" . $this->formData['name']);
+        $snapshot->rollback();
+        return (new HtmlDataJsonResponse())
+            ->setStatusSuccess()
+            ->setMessageAndTranslate('The snapshot has been rolled back successfully');
+    }
+
+}

+ 37 - 0
app/UI/TaskHistory/Buttons/InfoButton.php

@@ -0,0 +1,37 @@
+<?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\ProxmoxVps\App\UI\TaskHistory\Buttons;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\TaskHistory\Modals\InfoModal;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+
+class InfoButton extends ButtonDataTableModalAction implements ClientArea
+{
+    protected $icon = 'lu-zmdi lu-zmdi-info-outline';
+
+    public function initContent()
+    {
+        $this->initIds('infoButton ');
+        $this->initLoadModalAction(new InfoModal());
+        $this->setDisableByColumnValue("satusRaw", "OK");
+    }
+
+}

+ 50 - 0
app/UI/TaskHistory/Forms/InfoForm.php

@@ -0,0 +1,50 @@
+<?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\ProxmoxVps\App\UI\TaskHistory\Forms;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\TaskHistory\Providers\TaskHistoryProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Fields\Hidden;
+
+
+class InfoForm extends BaseForm implements ClientArea
+{
+    public function initContent()
+    {
+        $this->initIds('infoForm');
+        $this->setFormType('info');
+        $this->setProvider(new TaskHistoryProvider());
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function getAllowedActions()
+    {
+        return ['info'];
+    }
+
+    private function initFields()
+    {
+        $this->setConfirmMessage("error: :status:");
+        $this->addField(new Hidden("status"));
+        $this->addLocalLangReplacements(["status" => null]);
+    }
+}

+ 46 - 0
app/UI/TaskHistory/Modals/InfoModal.php

@@ -0,0 +1,46 @@
+<?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\ProxmoxVps\App\UI\TaskHistory\Modals;
+
+use ModulesGarden\Servers\ProxmoxVps\App\UI\TaskHistory\Forms\InfoForm;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ModalActionButtons\BaseCancelButton;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Modals\ModalConfirmDanger;
+
+class InfoModal extends ModalConfirmDanger implements ClientArea
+{
+
+    public function initContent()
+    {
+        $this->initIds('infoModal');
+        $this->setConfirmTitle("test");
+        $this->addForm(new InfoForm());
+    }
+
+    protected function initActionButtons()
+    {
+        if (!empty($this->actionButtons))
+        {
+            return $this;
+        }
+        $this->addActionButton(new BaseCancelButton());
+        return $this;
+    }
+}

+ 115 - 0
app/UI/TaskHistory/Pages/TaskHistoryDataTable.php

@@ -0,0 +1,115 @@
+<?php
+/* * ********************************************************************
+*  ProxmoxVPS Product developed. (26.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\ProxmoxVps\App\UI\TaskHistory\Pages;
+
+use MGProvision\Proxmox\v2\repository\TaskRepository;
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
+use ModulesGarden\Servers\ProxmoxVps\App\UI\TaskHistory\Buttons\InfoButton;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\Column;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\DataProviders\Providers\ArrayDataProvider;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\DataTable\DataTable;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl;
+
+class TaskHistoryDataTable extends DataTable implements ClientArea
+{
+    use ProductService;
+    use ApiService;
+    protected $id = 'taskHistoryDataTable';
+    protected $title = 'taskHistoryDataTable';
+
+    public function initContent()
+    {
+        //Info
+        $this->addActionButton(new InfoButton());
+    }
+
+    protected function loadHtml()
+    {
+        $this->addColumn((new Column('starttime'))->setSearchable(true, Column::TYPE_DATE)->setOrderable('DESC'))
+            ->addColumn((new Column('endtime'))->setSearchable(true, Column::TYPE_DATE)->setOrderable())
+            ->addColumn((new Column('type'))->setSearchable(true))
+            ->addColumn((new Column('status'))->setSearchable(true));
+    }
+
+    public function formatRowStarttime($key, $row)
+    {
+        return date('Y-m-d H:i:s', $row[$key]);
+    }
+
+    public function formatRowEndtime($key, $row)
+    {
+        return date('Y-m-d H:i:s', $row[$key]);
+    }
+
+    public function formatRowStatus($key,$row)
+    {
+        if ($row['status'] == "OK")
+        {
+            return '<span class="lu-label lu-label--success lu-label--status">' . sl('lang')->tr("OK") . '</span>';
+        }
+        return '<span class="lu-label lu-label--danger lu-label--status">' . sl('lang')->tr("Error") . '</span>';
+    }
+
+    public function formatRowSnaptime($key, $row)
+    {
+        return date('Y-m-d H:i:s', $row['snaptime']);
+    }
+
+    public function formatRowType($key,$row)
+    {
+        if ($row['type'])
+        {
+            return sl('lang')->tr($row['type']);
+        }
+        return '-';
+    }
+
+    protected function loadData()
+    {
+        $repository = new TaskRepository();
+        $repository->setApi($this->api());
+        $repository->findByVm($this->vm())
+            ->fromStartTime($this->getWhmcsParamByKey('model')->registrationDate->getTimestamp());
+        $repository->limit(3000);
+        $data = [];
+        foreach ($repository->fetch() as $entity)
+        {
+            $row             = $entity->getAttributes();
+            $row['entityId'] = $row['id'];
+            $row['satusRaw'] = $row['status'];
+            $row['id'] =  base64_encode(json_encode($row));
+            foreach($row as  $k => &$entery){
+                $method = 'formatRow'.ucfirst($k) ;
+                if(method_exists($this, $method)){
+                    $entery = $this->$method($k,$row);
+                }
+            }
+            $data[] = $row;
+        }
+        $dataProv = new ArrayDataProvider();
+        $dataProv->setDefaultSorting("snaptime", 'DESC');
+        $dataProv->setData($data);
+        $this->setDataProvider($dataProv);
+    }
+
+
+}

+ 45 - 0
app/UI/TaskHistory/Providers/TaskHistoryProvider.php

@@ -0,0 +1,45 @@
+<?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\ProxmoxVps\App\UI\TaskHistory\Providers;
+
+use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\DataProviders\BaseDataProvider;
+
+
+class TaskHistoryProvider extends BaseDataProvider implements ClientArea
+{
+    use ApiService;
+
+    public function read()
+    {
+        if ($this->actionElementId)
+        {
+            $this->data = json_decode(base64_decode($this->actionElementId), true);
+        }
+    }
+
+    public function update()
+    {
+
+    }
+
+
+}

+ 76 - 0
app/UI/Validators/CidrValidator.php

@@ -0,0 +1,76 @@
+<?php
+
+/* * ********************************************************************
+ * ProxmoxAddon product developed. (Aug 23, 2018)
+ * *
+ *
+ *  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\ProxmoxVps\App\UI\Validators;
+
+
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Validators\BaseValidator;
+
+/**
+ * Description of NumberValidator
+ *
+ * @author Pawel Kopec <pawelk@modulesgardne.com>
+ */
+class CidrValidator extends BaseValidator
+{
+    protected $required = false;
+
+    public function __construct($required = true)
+    {
+        $this->required = $required;
+    }
+
+    protected function validate($data, $additionalData = null)
+    {
+        if (!$this->required && empty($data))
+        {
+            return true;
+        }
+        else
+        {
+            if ($this->required && empty($data))
+            {
+                $this->addValidationError('PleaseProvideANumericValue');
+                return false;
+            }
+        }
+        $min = 1;
+        $max = 32;
+        //ipv6 range
+        if ($additionalData && $additionalData->get('formData')['ip'] && preg_match('/\:/', $additionalData->get('formData')['ip']))
+        {
+            $max = 128;
+        }
+        else
+        {
+            if ($additionalData && $additionalData->get('formData')['ipPool'] && preg_match('/\:/', $additionalData->get('formData')['ipPool']))
+            {
+                $max = 128;
+            }
+        }
+        if (!is_numeric($data) || (int)$data < $min || (int)$data > $max)
+        {
+            $this->addValidationError('PleaseProvideANumericValueBetween', false, ['minValue' => $min, 'maxValue' => $max]);
+            return false;
+        }
+        return true;
+    }
+}

+ 57 - 0
app/UI/Validators/HostnameValidator.php

@@ -0,0 +1,57 @@
+<?php
+
+/* * ********************************************************************
+ * ProxmoxAddon product developed. (Aug 23, 2018)
+ * *
+ *
+ *  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\ProxmoxVps\App\UI\Validators;
+
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Validators\BaseValidator;
+
+/**
+ * Description of NumberValidator
+ *
+ * @author Pawel Kopec <pawelk@modulesgardne.com>
+ */
+class HostnameValidator extends BaseValidator
+{
+    protected $required = false;
+
+    public function __construct($required = true)
+    {
+        $this->required = $required;
+    }
+
+    protected function validate($data, $additionalData = null)
+    {
+        if (!$this->required && empty($data))
+        {
+            return true;
+        }
+        else
+        {
+            if (!preg_match('/^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/', $data))
+            {
+                $this->addValidationError('PleaseProvideAhostname');
+                return false;
+            }
+        }
+
+        return true;
+    }
+}

+ 59 - 0
app/UI/Validators/IpAddressValidator.php

@@ -0,0 +1,59 @@
+<?php
+
+/* * ********************************************************************
+ * ProxmoxAddon product developed. (Aug 23, 2018)
+ * *
+ *
+ *  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\ProxmoxVps\App\UI\Validators;
+
+use ModulesGarden\ProxmoxAddon\App\Models\VmIpAddress;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Validators\BaseValidator;
+
+/**
+ * Description of NumberValidator
+ *
+ * @author Pawel Kopec <pawelk@modulesgardne.com>
+ */
+class IpAddressValidator extends BaseValidator
+{
+    protected $required = false;
+
+    public function __construct($required = false)
+    {
+        $this->required = $required;
+    }
+
+    protected function validate($data, $additionalData = null)
+    {
+
+        if (!$this->required && empty($data))
+        {
+            return true;
+        }
+        if (!filter_var($data, FILTER_VALIDATE_IP))
+        {
+            $this->addValidationError('IP Address is not valid', false);
+            return false;
+        }
+        if ($this->required && VmIpAddress::ofIp($data)->count())
+        {
+            $this->addValidationError('IP Address already exist', false);
+            return false;
+        }
+        return true;
+    }
+}

+ 94 - 0
app/UI/Validators/NumberValidator.php

@@ -0,0 +1,94 @@
+<?php
+
+/* * ********************************************************************
+ * ProxmoxAddon product developed. (Aug 23, 2018)
+ * *
+ *
+ *  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\ProxmoxVps\App\UI\Validators;
+
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Validators\BaseValidator;
+
+/**
+ * Description of NumberValidator
+ *
+ * @author Pawel Kopec <pawelk@modulesgardne.com>
+ */
+class NumberValidator extends BaseValidator
+{
+    protected $minValue = 0;
+    protected $maxValue = 0;
+    protected $required = false;
+
+    public function __construct($min = 0, $max = 0, $required = false)
+    {
+        $this->minValue = (int)$min;
+        $this->maxValue = $max;
+        $this->required = $required;
+    }
+
+    protected function validate($data, $additionalData = null)
+    {
+        if (!$this->required && empty($data))
+        {
+            return true;
+        }
+        if(preg_match("/\./", $data)){
+            $this->addValidationError('PleaseProvideANumericValueBetween', false, ['minValue' => $this->minValue, 'maxValue' => $this->maxValue]);
+            return false;
+        }
+        if (is_numeric($data) && $this->minValue === 0 && $this->maxValue === 0)
+        {
+            return true;
+        }
+        //Min & Max
+        if (is_numeric($data) && $this->minValue <= ((int)$data) && ((int)$data) <= $this->maxValue)
+        {
+            return true;
+        }
+        //Min
+        else
+        {
+            if (is_numeric($data) && !is_numeric($this->maxValue) && $this->minValue <= ((int)$data))
+            {
+                return true;
+            }
+        }
+
+        if ($this->minValue === $this->maxValue)
+        {
+            $this->addValidationError('PleaseProvideANumericValue');
+
+            return false;
+        }
+
+        if (is_numeric($this->minValue) && is_numeric($this->maxValue))
+        {
+            $this->addValidationError('PleaseProvideANumericValueBetween', false, ['minValue' => $this->minValue, 'maxValue' => $this->maxValue]);
+        }
+        else
+        {
+            if (is_numeric($this->minValue) && !is_numeric($this->maxValue))
+            {
+                $this->addValidationError('PleaseProvideANumericValueFrom', false, ['minValue' => $this->minValue]);
+            }
+        }
+
+
+        return false;
+    }
+}

+ 59 - 0
app/UI/Validators/PasswordValidator.php

@@ -0,0 +1,59 @@
+<?php
+
+/* * ********************************************************************
+ * ProxmoxAddon product developed. (Aug 23, 2018)
+ * *
+ *
+ *  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\ProxmoxVps\App\UI\Validators;
+
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Validators\BaseValidator;
+
+/**
+ * Description of NumberValidator
+ *
+ * @author Pawel Kopec <pawelk@modulesgardne.com>
+ */
+class PasswordValidator extends BaseValidator
+{
+    protected $required = false;
+    protected $length;
+
+    public function __construct($required = true, $length = false)
+    {
+        $this->required = $required;
+        $this->length   = $length;
+    }
+
+    protected function validate($data, $additionalData = null)
+    {
+        if (!$this->required && empty($data))
+        {
+            return true;
+        }
+        else
+        {
+            if (is_numeric($this->length) && strlen($data) < $this->length)
+            {
+                $this->addValidationError('The password is too short');
+                return false;
+            }
+        }
+
+        return true;
+    }
+}

+ 90 - 0
app/UI/Validators/PortValidator.php

@@ -0,0 +1,90 @@
+<?php
+
+/* * ********************************************************************
+ * ProxmoxAddon product developed. (Aug 23, 2018)
+ * *
+ *
+ *  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\ProxmoxVps\App\UI\Validators;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Validators\BaseValidator;
+
+/**
+ * Description of NumberValidator
+ *
+ * @author Pawel Kopec <pawelk@modulesgardne.com>
+ */
+class PortValidator extends BaseValidator
+{
+    protected $minValue = 1;
+    protected $maxValue = 65535;
+    protected $required = false;
+
+    public function __construct($required = false)
+    {
+        $this->required = $required;
+    }
+
+    protected function validate($data, $additionalData = null)
+    {
+        if (!$this->required && empty($data))
+        {
+            return true;
+        }
+        if (is_numeric($data) && $this->minValue === 0 && $this->maxValue === 0)
+        {
+            return true;
+        }
+        if($data && preg_match("/\:/",$data)){
+            return  true;
+        }
+        //Min & Max
+        if (is_numeric($data) && $this->minValue <= ((int)$data) && ((int)$data) <= $this->maxValue)
+        {
+            return true;
+        }
+        //Min
+        else
+        {
+            if (is_numeric($data) && !is_numeric($this->maxValue) && $this->minValue <= ((int)$data))
+            {
+                return true;
+            }
+        }
+
+        if ($this->minValue === $this->maxValue)
+        {
+            $this->addValidationError('PleaseProvideANumericValue');
+
+            return false;
+        }
+
+        if (is_numeric($this->minValue) && is_numeric($this->maxValue))
+        {
+            $this->addValidationError('PleaseProvideANumericValueBetween', false, ['minValue' => $this->minValue, 'maxValue' => $this->maxValue]);
+        }
+        else
+        {
+            if (is_numeric($this->minValue) && !is_numeric($this->maxValue))
+            {
+                $this->addValidationError('PleaseProvideANumericValueFrom', false, ['minValue' => $this->minValue]);
+            }
+        }
+
+
+        return false;
+    }
+}

+ 57 - 0
app/UI/Validators/ShhPublicKeyValidator.php

@@ -0,0 +1,57 @@
+<?php
+
+/* * ********************************************************************
+ * ProxmoxAddon product developed. (Aug 23, 2018)
+ * *
+ *
+ *  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\ProxmoxVps\App\UI\Validators;
+
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Validators\BaseValidator;
+
+/**
+ * Description of NumberValidator
+ *
+ * @author Pawel Kopec <pawelk@modulesgardne.com>
+ */
+class ShhPublicKeyValidator extends BaseValidator
+{
+    protected $required = false;
+
+    public function __construct($required = true)
+    {
+        $this->required = $required;
+    }
+
+    protected function validate($data, $additionalData = null)
+    {
+        if (!$this->required && empty($data))
+        {
+            return true;
+        }
+        else
+        {
+            if (!preg_match('/ssh\-/', $data))
+            {
+                $this->addValidationError('PleaseProvideASshPublicKey');
+                return false;
+            }
+        }
+
+        return true;
+    }
+}

+ 57 - 0
app/UI/Validators/SnapshotValidator.php

@@ -0,0 +1,57 @@
+<?php
+
+/* * ********************************************************************
+ * ProxmoxAddon product developed. (Aug 23, 2018)
+ * *
+ *
+ *  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\ProxmoxVps\App\UI\Validators;
+
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Validators\BaseValidator;
+
+/**
+ * Description of NumberValidator
+ *
+ * @author Pawel Kopec <pawelk@modulesgardne.com>
+ */
+class SnapshotValidator extends BaseValidator
+{
+    protected $required = false;
+
+    public function __construct($required = true)
+    {
+        $this->required = $required;
+    }
+
+    protected function validate($data, $additionalData = null)
+    {
+        if (!$this->required && empty($data))
+        {
+            return true;
+        }
+        else if (preg_match('/\s/', $data)) {
+            $this->addValidationError('PleaseProvideASnapshotValue');
+            return false;
+        }
+        else if (!preg_match('/^[A-Za-z]{1}[A-Za-z0-9_]{1}[A-Za-z0-9]/', $data)) {
+            $this->addValidationError('PleaseProvideASnapshotValue');
+            return false;
+        }
+
+        return true;
+    }
+}

+ 57 - 0
app/UI/Validators/StartTimeValidator.php

@@ -0,0 +1,57 @@
+<?php
+
+/* * ********************************************************************
+ * ProxmoxAddon product developed. (Aug 23, 2018)
+ * *
+ *
+ *  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\ProxmoxVps\App\UI\Validators;
+
+
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Forms\Validators\BaseValidator;
+
+/**
+ * Description of NumberValidator
+ *
+ * @author Pawel Kopec <pawelk@modulesgardne.com>
+ */
+class StartTimeValidator extends BaseValidator
+{
+    protected $required = false;
+
+    public function __construct($required = true)
+    {
+        $this->required = $required;
+    }
+
+    protected function validate($data, $additionalData = null)
+    {
+        if (!$this->required && empty($data))
+        {
+            return true;
+        }
+        else
+        {
+            if (!preg_match('/[0-9]{2}\:[0-9]{2}/', $data))
+            {
+                $this->addValidationError('PleaseProvideAStartTimeValue');
+                return false;
+            }
+        }
+
+        return true;
+    }
+}

+ 20 - 0
commands/commands.php

@@ -0,0 +1,20 @@
+<?php
+
+define('DS', DIRECTORY_SEPARATOR);
+$modulePath = dirname(__DIR__);
+$whmcsPath  = dirname(dirname(dirname($modulePath)));
+
+require_once $whmcsPath . DS . 'init.php';
+require_once $modulePath . DS . 'core' . DS . 'Bootstrap.php';
+
+//cause WHMCS
+ini_set('max_execution_time', 0);
+
+$argList = $argv ? $argv : $_SERVER['argv'];
+if (count($argList) === 0)
+{
+    $argList = [__FILE__];
+}
+
+(new \ModulesGarden\Servers\ProxmoxVps\Core\CommandLine\Application())
+    ->run();

+ 40 - 0
composer.json

@@ -0,0 +1,40 @@
+{
+    "name": "ModulesGarden/ProxmoxVps",
+    "description": "",
+    "version": "2.1.0",
+    "type": "project",
+    "license": "EULA",
+    "homepage": "http://www.modulesgarden.com",
+    "support":
+            {
+                "email": "contact@modulesgarden.com",
+                "issues": "http://www.modulesgarden.com/customers/support",
+                "forum": "http://www.forum.modulesgarden.com/"
+            },
+    "authors": [],
+    "require":
+            {
+                "php": ">=5.5.9",
+                "symfony/http-foundation": "^3.3",
+                "symfony/yaml": "^3.3",
+                "symfony/dependency-injection": "^3.3",
+                "piwik/ini": "^1.0",
+                "symfony/cache": "^3.3",
+                "mso/idna-convert" : "1.*",
+                "adbario/php-dot-notation" : "2.*",
+        "rappasoft/laravel-helpers": "^1.0"
+            },
+    "autoload": {
+        "psr-4": {
+            "ModulesGarden\\Servers\\ProxmoxVps\\Core\\": "./core",
+            "ModulesGarden\\Servers\\ProxmoxVps\\App\\": "./app",
+            "ModulesGarden\\Servers\\ProxmoxVps\\Packages\\": "./packages",
+            "MGProvision\\Proxmox\\": "../../../includes/Proxmox",
+            "ModulesGarden\\ProxmoxAddon\\Core\\": "../../addons/proxmoxAddon/core",
+            "ModulesGarden\\ProxmoxAddon\\App\\": "../../addons/proxmoxAddon/app"
+        },
+        "files": [
+            "./core/Helper/Functions.php"
+        ]
+    }
+}

+ 912 - 0
composer.lock

@@ -0,0 +1,912 @@
+{
+    "_readme": [
+        "This file locks the dependencies of your project to a known state",
+        "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
+        "This file is @generated automatically"
+    ],
+    "content-hash": "0e3dd310215440ef0553253fa7e6466b",
+    "packages": [
+        {
+            "name": "adbario/php-dot-notation",
+            "version": "2.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/adbario/php-dot-notation.git",
+                "reference": "895fe4bb153ac875c61a6fba658ded45405e73a4"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/adbario/php-dot-notation/zipball/895fe4bb153ac875c61a6fba658ded45405e73a4",
+                "reference": "895fe4bb153ac875c61a6fba658ded45405e73a4",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^4.0|^5.0|^6.0",
+                "squizlabs/php_codesniffer": "^3.0"
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "src/helpers.php"
+                ],
+                "psr-4": {
+                    "Adbar\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Riku Särkinen",
+                    "email": "riku@adbar.io"
+                }
+            ],
+            "description": "PHP dot notation access to arrays",
+            "homepage": "https://github.com/adbario/php-dot-notation",
+            "keywords": [
+                "ArrayAccess",
+                "dotnotation"
+            ],
+            "time": "2018-07-22T12:33:53+00:00"
+        },
+        {
+            "name": "mso/idna-convert",
+            "version": "v1.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/algo26-matthias/idna-convert.git",
+                "reference": "a6dfb6f87611e3a89d2eec4924a0f51db755c573"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/algo26-matthias/idna-convert/zipball/a6dfb6f87611e3a89d2eec4924a0f51db755c573",
+                "reference": "a6dfb6f87611e3a89d2eec4924a0f51db755c573",
+                "shasum": ""
+            },
+            "require": {
+                "ext-pcre": "*",
+                "php": ">=5.6.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Mso\\IdnaConvert\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "LGPL-2.1+"
+            ],
+            "authors": [
+                {
+                    "name": "Matthias Sommerfeld",
+                    "email": "mso@phlylabs.de",
+                    "role": "Developer"
+                }
+            ],
+            "description": "A library for encoding and decoding internationalized domain names",
+            "homepage": "http://idnaconv.net/",
+            "keywords": [
+                "idn",
+                "idna",
+                "php"
+            ],
+            "abandoned": "algo26-matthias/idna-convert",
+            "time": "2016-06-19T18:08:43+00:00"
+        },
+        {
+            "name": "paragonie/random_compat",
+            "version": "v9.99.99",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/paragonie/random_compat.git",
+                "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/paragonie/random_compat/zipball/84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95",
+                "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "4.*|5.*",
+                "vimeo/psalm": "^1"
+            },
+            "suggest": {
+                "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
+            },
+            "type": "library",
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Paragon Initiative Enterprises",
+                    "email": "security@paragonie.com",
+                    "homepage": "https://paragonie.com"
+                }
+            ],
+            "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
+            "keywords": [
+                "csprng",
+                "polyfill",
+                "pseudorandom",
+                "random"
+            ],
+            "time": "2018-07-02T15:55:56+00:00"
+        },
+        {
+            "name": "piwik/ini",
+            "version": "1.0.6",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/piwik/component-ini.git",
+                "reference": "bd2711ba4d5e20e4ca09b6829dc2831576b59dc3"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/piwik/component-ini/zipball/bd2711ba4d5e20e4ca09b6829dc2831576b59dc3",
+                "reference": "bd2711ba4d5e20e4ca09b6829dc2831576b59dc3",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "require-dev": {
+                "athletic/athletic": "0.1.*",
+                "phpunit/phpunit": "~4.0"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Piwik\\Ini\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "LGPL-3.0"
+            ],
+            "abandoned": "matomo/ini",
+            "time": "2016-01-14T21:13:33+00:00"
+        },
+        {
+            "name": "psr/cache",
+            "version": "1.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/cache.git",
+                "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8",
+                "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Psr\\Cache\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interface for caching libraries",
+            "keywords": [
+                "cache",
+                "psr",
+                "psr-6"
+            ],
+            "time": "2016-08-06T20:24:11+00:00"
+        },
+        {
+            "name": "psr/container",
+            "version": "1.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/container.git",
+                "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
+                "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Psr\\Container\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common Container Interface (PHP FIG PSR-11)",
+            "homepage": "https://github.com/php-fig/container",
+            "keywords": [
+                "PSR-11",
+                "container",
+                "container-interface",
+                "container-interop",
+                "psr"
+            ],
+            "time": "2017-02-14T16:28:37+00:00"
+        },
+        {
+            "name": "psr/log",
+            "version": "1.1.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/log.git",
+                "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc",
+                "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.1.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Psr\\Log\\": "Psr/Log/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interface for logging libraries",
+            "homepage": "https://github.com/php-fig/log",
+            "keywords": [
+                "log",
+                "psr",
+                "psr-3"
+            ],
+            "time": "2020-03-23T09:12:05+00:00"
+        },
+        {
+            "name": "psr/simple-cache",
+            "version": "1.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/simple-cache.git",
+                "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
+                "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Psr\\SimpleCache\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interfaces for simple caching",
+            "keywords": [
+                "cache",
+                "caching",
+                "psr",
+                "psr-16",
+                "simple-cache"
+            ],
+            "time": "2017-10-23T01:57:42+00:00"
+        },
+        {
+            "name": "rappasoft/laravel-helpers",
+            "version": "1.0.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/rappasoft/laravel-helpers.git",
+                "reference": "c8dfa1e979437528262725ebe99c2e6383b24c16"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/rappasoft/laravel-helpers/zipball/c8dfa1e979437528262725ebe99c2e6383b24c16",
+                "reference": "c8dfa1e979437528262725ebe99c2e6383b24c16",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.4.0"
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "src/helpers.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Anthony Rappa",
+                    "email": "rappa819@gmail.com"
+                }
+            ],
+            "description": "Laravel Helpers for Non-Laravel Projects",
+            "keywords": [
+                "helpers",
+                "laravel"
+            ],
+            "time": "2019-04-03T13:15:59+00:00"
+        },
+        {
+            "name": "symfony/cache",
+            "version": "v3.4.20",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/cache.git",
+                "reference": "d31c2a1b80029d885307db47405daeffafcda759"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/cache/zipball/d31c2a1b80029d885307db47405daeffafcda759",
+                "reference": "d31c2a1b80029d885307db47405daeffafcda759",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.5.9|>=7.0.8",
+                "psr/cache": "~1.0",
+                "psr/log": "~1.0",
+                "psr/simple-cache": "^1.0",
+                "symfony/polyfill-apcu": "~1.1"
+            },
+            "conflict": {
+                "symfony/var-dumper": "<3.3"
+            },
+            "provide": {
+                "psr/cache-implementation": "1.0",
+                "psr/simple-cache-implementation": "1.0"
+            },
+            "require-dev": {
+                "cache/integration-tests": "dev-master",
+                "doctrine/cache": "~1.6",
+                "doctrine/dbal": "~2.4",
+                "predis/predis": "~1.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.4-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Cache\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony Cache component with PSR-6, PSR-16, and tags",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "caching",
+                "psr6"
+            ],
+            "time": "2018-12-06T10:54:02+00:00"
+        },
+        {
+            "name": "symfony/dependency-injection",
+            "version": "v3.3.18",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/dependency-injection.git",
+                "reference": "54243abc4e1a1a15e274e391bd6f7090b44711f1"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/54243abc4e1a1a15e274e391bd6f7090b44711f1",
+                "reference": "54243abc4e1a1a15e274e391bd6f7090b44711f1",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.5.9|>=7.0.8",
+                "psr/container": "^1.0"
+            },
+            "conflict": {
+                "symfony/config": "<3.3.7",
+                "symfony/finder": "<3.3",
+                "symfony/yaml": "<3.3"
+            },
+            "provide": {
+                "psr/container-implementation": "1.0"
+            },
+            "require-dev": {
+                "symfony/config": "~3.3",
+                "symfony/expression-language": "~2.8|~3.0",
+                "symfony/yaml": "~3.3"
+            },
+            "suggest": {
+                "symfony/config": "",
+                "symfony/expression-language": "For using expressions in service container configuration",
+                "symfony/finder": "For using double-star glob patterns or when GLOB_BRACE portability is required",
+                "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them",
+                "symfony/yaml": ""
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.3-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\DependencyInjection\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony DependencyInjection Component",
+            "homepage": "https://symfony.com",
+            "time": "2018-01-29T09:02:23+00:00"
+        },
+        {
+            "name": "symfony/http-foundation",
+            "version": "v3.4.20",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/http-foundation.git",
+                "reference": "ea61dd57c4399b0b2a4162e1820cd9d0783acd38"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/http-foundation/zipball/ea61dd57c4399b0b2a4162e1820cd9d0783acd38",
+                "reference": "ea61dd57c4399b0b2a4162e1820cd9d0783acd38",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.5.9|>=7.0.8",
+                "symfony/polyfill-mbstring": "~1.1",
+                "symfony/polyfill-php70": "~1.6"
+            },
+            "require-dev": {
+                "symfony/expression-language": "~2.8|~3.0|~4.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.4-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\HttpFoundation\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony HttpFoundation Component",
+            "homepage": "https://symfony.com",
+            "time": "2018-11-26T10:17:44+00:00"
+        },
+        {
+            "name": "symfony/polyfill-apcu",
+            "version": "v1.10.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-apcu.git",
+                "reference": "19e1b73bf255265ad0b568f81766ae2a3266d8d2"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-apcu/zipball/19e1b73bf255265ad0b568f81766ae2a3266d8d2",
+                "reference": "19e1b73bf255265ad0b568f81766ae2a3266d8d2",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.9-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Polyfill\\Apcu\\": ""
+                },
+                "files": [
+                    "bootstrap.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill backporting apcu_* functions to lower PHP versions",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "apcu",
+                "compatibility",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "time": "2018-08-06T14:22:27+00:00"
+        },
+        {
+            "name": "symfony/polyfill-mbstring",
+            "version": "v1.10.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-mbstring.git",
+                "reference": "c79c051f5b3a46be09205c73b80b346e4153e494"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/c79c051f5b3a46be09205c73b80b346e4153e494",
+                "reference": "c79c051f5b3a46be09205c73b80b346e4153e494",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "suggest": {
+                "ext-mbstring": "For best performance"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.9-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Polyfill\\Mbstring\\": ""
+                },
+                "files": [
+                    "bootstrap.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill for the Mbstring extension",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "mbstring",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "time": "2018-09-21T13:07:52+00:00"
+        },
+        {
+            "name": "symfony/polyfill-php70",
+            "version": "v1.10.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-php70.git",
+                "reference": "6b88000cdd431cd2e940caa2cb569201f3f84224"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/6b88000cdd431cd2e940caa2cb569201f3f84224",
+                "reference": "6b88000cdd431cd2e940caa2cb569201f3f84224",
+                "shasum": ""
+            },
+            "require": {
+                "paragonie/random_compat": "~1.0|~2.0|~9.99",
+                "php": ">=5.3.3"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.9-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Polyfill\\Php70\\": ""
+                },
+                "files": [
+                    "bootstrap.php"
+                ],
+                "classmap": [
+                    "Resources/stubs"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "time": "2018-09-21T06:26:08+00:00"
+        },
+        {
+            "name": "symfony/yaml",
+            "version": "v3.3.18",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/yaml.git",
+                "reference": "af615970e265543a26ee712c958404eb9b7ac93d"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/yaml/zipball/af615970e265543a26ee712c958404eb9b7ac93d",
+                "reference": "af615970e265543a26ee712c958404eb9b7ac93d",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.5.9|>=7.0.8"
+            },
+            "require-dev": {
+                "symfony/console": "~2.8|~3.0"
+            },
+            "suggest": {
+                "symfony/console": "For validating YAML files using the lint command"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.3-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Yaml\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony Yaml Component",
+            "homepage": "https://symfony.com",
+            "time": "2018-01-20T15:04:53+00:00"
+        }
+    ],
+    "packages-dev": [
+        {
+            "name": "symfony/console",
+            "version": "v2.8.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/console.git",
+                "reference": "56cc5caf051189720b8de974e4746090aaa10d44"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/console/zipball/56cc5caf051189720b8de974e4746090aaa10d44",
+                "reference": "56cc5caf051189720b8de974e4746090aaa10d44",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.9",
+                "symfony/polyfill-mbstring": "~1.0"
+            },
+            "require-dev": {
+                "psr/log": "~1.0",
+                "symfony/event-dispatcher": "~2.1|~3.0.0",
+                "symfony/process": "~2.1|~3.0.0"
+            },
+            "suggest": {
+                "psr/log": "For using the console logger",
+                "symfony/event-dispatcher": "",
+                "symfony/process": ""
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.8-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Console\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony Console Component",
+            "homepage": "https://symfony.com",
+            "time": "2016-02-28T16:20:50+00:00"
+        }
+    ],
+    "aliases": [],
+    "minimum-stability": "stable",
+    "stability-flags": [],
+    "prefer-stable": false,
+    "prefer-lowest": false,
+    "platform": {
+        "php": ">=5.5.9"
+    },
+    "platform-dev": [],
+    "plugin-api-version": "1.1.0"
+}

+ 25 - 0
core/Api/AbstractApi.php

@@ -0,0 +1,25 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\Api;
+
+use \ModulesGarden\Servers\ProxmoxVps\Core\Api\AbstractApi\Curl\Request;
+use \ModulesGarden\Servers\ProxmoxVps\Core\DependencyInjection;
+
+/**
+ * Description of AbstractApi
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class AbstractApi
+{
+    protected $token;
+    protected $code;
+
+    /**
+     * @return Request
+     */
+    protected function getNewRequest()
+    {
+        return DependencyInjection::create(Request::class);
+    }
+}

+ 158 - 0
core/Api/AbstractApi/Curl.php

@@ -0,0 +1,158 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\Api\AbstractApi;
+
+use \ModulesGarden\Servers\ProxmoxVps\Core\Api\AbstractApi\Curl\Response;
+use \ModulesGarden\Servers\ProxmoxVps\Core\DependencyInjection;
+use \ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Exceptions\Exception;
+use \ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\ErrorCodes\ErrorCodesLib;
+
+/**
+ * Description of Curl
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+abstract class Curl
+{
+    private $curl;
+    private $options = [
+        CURLOPT_TIMEOUT        => 30,
+        CURLOPT_HEADER         => false,
+        CURLOPT_RETURNTRANSFER => true,
+        CURLINFO_HEADER_OUT    => true
+    ];
+    protected $curlParser;
+
+    public function setCurlParser($curlParser)
+    {
+        $this->curlParser = $curlParser;
+
+        return $this;
+    }
+
+    public function setOptions($options, $value)
+    {
+        $this->options[$options] = $value;
+        return $this;
+    }
+
+    protected function open()
+    {
+        $this->curl = curl_init();
+
+        return $this;
+    }
+
+    protected function close()
+    {
+        curl_close($this->curl);
+
+        return $this;
+    }
+
+    protected function unsetOptions($options)
+    {
+        if (is_array($options))
+        {
+            foreach ($options as $option)
+            {
+                if (isset($this->options[$option]))
+                {
+                    unset($this->options[$option]);
+                }
+            }
+        }
+        else
+        {
+            unset($this->options[$options]);
+        }
+
+        return $this;
+    }
+
+    /**
+     * @return Response
+     * @throws \ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Exceptions\Exception
+     */
+    protected function send()
+    {
+        $this->includeOptions();
+
+        if (($head = $this->execute()) === false)
+        {
+            throw new Exception(ErrorCodesLib::CORE_CURL_000001, ['lastCurlError' => $this->getLastErrorWithCurl()]);
+        }
+
+        if ($errno = $this->getLastErrorNumber())
+        {
+            throw new Exception(ErrorCodesLib::CORE_CURL_000002, ['curlError' => $this->getLastError($errno)]);
+        }
+
+        list($header, $body) = $this->curlParser->rebuild($head, $this->getHeaderSize());
+
+        return DependencyInjection::create(Response::class)
+                        ->setRequest($this->getHeaderOut())
+                        ->setHeader($header)
+                        ->setCode($this->getHttpCode())
+                        ->setBody($body);
+    }
+
+    private function execute()
+    {
+        return curl_exec($this->curl);
+    }
+
+    private function getLastErrorNumber()
+    {
+        return curl_errno($this->curl);
+    }
+
+    /**
+     * (PHP 5 &gt;= 5.5.0, PHP 7)<br/>
+     * Return string describing the given error code
+     * @link http://php.net/manual/en/function.curl-strerror.php
+     * @param int $errornum <p>
+     * One of the cURL error codes constants.
+     * </p>
+     * @return string error description or <b>NULL</b> for invalid error code.
+     */
+    private function getLastError($errmo)
+    {
+        return curl_strerror($errmo);
+    }
+
+    /**
+     * (PHP 4 &gt;= 4.0.3, PHP 5, PHP 7)<br/>
+     * Return a string containing the last error for the current session
+     * @link http://php.net/manual/en/function.curl-error.php
+     * @param resource $ch
+     * @return string the error message or '' (the empty string) if no
+     * error occurred.
+     */
+    private function getLastErrorWithCurl()
+    {
+        return curl_error($this->curl);
+    }
+
+    private function getHeaderSize()
+    {
+        return curl_getinfo($this->curl, CURLINFO_HEADER_SIZE);
+    }
+
+    private function getHeaderOut()
+    {
+        return curl_getinfo($this->curl, CURLINFO_HEADER_OUT);
+    }
+
+    private function getHttpCode()
+    {
+        return curl_getinfo($this->curl, CURLINFO_HTTP_CODE);
+    }
+
+    private function includeOptions()
+    {
+        curl_setopt_array($this->curl, $this->options);
+
+        return $this;
+    }
+}

+ 193 - 0
core/Api/AbstractApi/Curl/Request.php

@@ -0,0 +1,193 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\Api\AbstractApi\Curl;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\Api\AbstractApi\Curl;
+
+/**
+ * Description of Request
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Request extends Curl
+{
+    protected $url = '';
+    
+    protected $lastResponse = [];
+    
+    protected $headers = [
+        "Content-Type: application/x-www-form-urlencoded"
+    ];
+
+    public function getLastResponse()
+    {
+        return $this->lastResponse;
+    }
+
+    public function setUrl($url = "")
+    {
+        $this->url = $url;
+
+        return $this;
+    }
+
+    public function resetHeaders()
+    {
+        $this->headers = [];
+
+        return $this;
+    }
+
+    public function setHeaders(array $headers = [])
+    {
+        $this->headers = $headers;
+
+        return $this;
+    }
+
+    public function addHeaders($headers)
+    {
+        if (is_array($headers))
+        {
+            $this->headers = $headers;
+        }
+        else
+        {
+            $this->headers[] = $headers;
+        }
+
+        return $this;
+    }
+
+    protected function send()
+    {
+        $return               = parent::send();
+        $this->close();
+        $this->lastResponse[] = $return;
+
+        return $return;
+    }
+
+    /**
+     * @param array $data
+     * @return string
+     */
+    protected function httpBuildQuery(array $data = [])
+    {
+        return empty($data) ? "" : http_build_query($data);
+    }
+
+    /**
+     * @param array $data post field
+     * @return Response
+     */
+    public function post($data = [])
+    {
+
+        $postvars = is_array($data) ? $this->httpBuildQuery($data) : $data;
+
+        $this->open()
+            ->setOptions(CURLOPT_SSL_VERIFYPEER, false)
+            ->setOptions(CURLOPT_URL, $this->url)
+            ->setOptions(CURLOPT_POSTFIELDS, $postvars)
+            ->setOptions(CURLOPT_POST, true);
+        
+        if (!empty($this->headers))
+        {
+            $this->setOptions(CURLOPT_HTTPHEADER, $this->headers)
+                    ->setOptions(CURLOPT_HEADER, true);
+        }
+
+        return $this->send();
+    }
+
+    /**
+     * @param array $data post field
+     * @return Response
+     */
+    public function put($data = [])
+    {
+
+        $postvars = is_array($data)?$this->httpBuildQuery($data):$data;
+        
+        $this->open()
+            ->setOptions(CURLOPT_SSL_VERIFYPEER, false)
+            ->setOptions(CURLOPT_URL, $this->url)
+            ->setOptions(CURLOPT_POSTFIELDS, $postvars)
+            ->setOptions(CURLOPT_CUSTOMREQUEST, "PUT");
+        
+        if (!empty($this->headers))
+        {
+            $this->setOptions(CURLOPT_HTTPHEADER, $this->headers)
+                    ->setOptions(CURLOPT_HEADER, true);
+        }
+
+        return $this->send();
+    }
+
+    /**
+     * @param array $data post field
+     * @return Response
+     */
+    public function delete($data = [])
+    {
+
+        $deletevars = is_array($data)?$this->httpBuildQuery($data):$data;
+        
+        $this->open()
+            ->setOptions(CURLOPT_SSL_VERIFYPEER, false)
+            ->setOptions(CURLOPT_URL, $this->url . $deletevars)
+            ->setOptions(CURLOPT_CUSTOMREQUEST, "DELETE");
+        
+        if (!empty($this->headers))
+        {
+            $this->setOptions(CURLOPT_HTTPHEADER, $this->headers)
+                    ->setOptions(CURLOPT_HEADER, true);
+        }
+
+        return $this->send();
+
+    }
+    
+    /**
+     * @param array $data post field
+     * @return Response
+     */
+    public function get($data = [])
+    {
+        $getvars = is_array($data)?$this->httpBuildQuery($data):$data;
+        
+        $this->open()
+            ->setOptions(CURLOPT_URL, $this->url . $getvars);
+        
+        if (!empty($this->headers))
+        {
+            $this->setOptions(CURLOPT_HTTPHEADER, $this->headers)
+                    ->setOptions(CURLOPT_HEADER, true);
+        }
+        
+        return $this->send();
+    }  
+
+    /**
+     * @param array $data post field
+     * @return Response
+     */
+    public function options($data = [])
+    {
+        $deletevars = is_array($data)?$this->httpBuildQuery($data):$data;
+        
+        $this->open()
+            ->setOptions(CURLOPT_SSL_VERIFYPEER, false)
+            ->setOptions(CURLOPT_URL, $this->url)
+            ->setOptions(CURLOPT_CUSTOMREQUEST, "OPTIONS");
+        
+        if (!empty($this->headers))
+        {
+            $this->setOptions(CURLOPT_HTTPHEADER, $this->headers)
+                    ->setOptions(CURLOPT_HEADER, true);
+        }
+
+        return $this->send();
+    }
+}

+ 92 - 0
core/Api/AbstractApi/Curl/Response.php

@@ -0,0 +1,92 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\Api\AbstractApi\Curl;
+
+/**
+ * Description of Respons
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Response
+{
+    protected $body;
+    protected $request;
+    protected $header;
+    protected $code;
+
+    public function setRequest($request)
+    {
+        $this->request = $request;
+
+        return $this;
+    }
+
+    public function setHeader($header)
+    {
+        $this->header = $header;
+
+        return $this;
+    }
+
+    public function setBody($body)
+    {
+        $this->body = $body;
+
+        return $this;
+    }
+
+    public function setCode($code)
+    {
+        $this->code = $code;
+
+        return $this;
+    }
+
+    /**
+     * @param bool $isJson
+     * @return string|\stdClass
+     */
+    public function getBody($isJson = true)
+    {
+
+
+        if ($isJson)
+        {
+            return json_decode($this->body);
+        }
+
+        return $this->body;
+    }
+
+    /**
+     * @return string
+     */
+    public function getRequest()
+    {
+        return $this->request;
+    }
+
+    /**
+     * @return string
+     */
+    public function getHeader()
+    {
+        return $this->header;
+    }
+
+    /**
+     * @return int
+     */
+    public function getCode()
+    {
+        return $this->code;
+    }
+
+    /**
+     * @return bool
+     */
+    public function isSuccess()
+    {
+        return (bool) ($this->code >= 200 && $this->code < 300);
+    }
+}

+ 22 - 0
core/Api/AbstractApi/Parser.php

@@ -0,0 +1,22 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\Api\AbstractApi;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\Interfaces\CurlParser;
+
+/**
+ * Description of Parser
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Parser implements CurlParser
+{
+
+    public function rebuild($head, $size)
+    {
+        return [
+            substr($head, 0, $size),
+            substr($head, $size)
+        ];
+    }
+}

+ 186 - 0
core/Api/Http.php

@@ -0,0 +1,186 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\Api;
+
+use ModulesGarden\Servers\ProxmoxVps\App\Libs\Exceptions\WhmcsApiException;
+use ModulesGarden\Servers\ProxmoxVps\Core\ModuleConstants;
+use ModulesGarden\Servers\ProxmoxVps\Core\Traits\IsDebugOn;
+
+use ModulesGarden\Servers\ProxmoxVps\App\Libs\Exceptions\ApiException;
+
+
+/**
+ * Description of Http
+ *
+ * @author Paweł Złamaniec <pawel.zl@modulesgarden.com>
+ */
+class Http
+{
+    use IsDebugOn;
+
+    /**
+     * @var \AltoRouter;
+     */
+    protected $router;
+
+    public function __construct($basepath)
+    {
+        $this->loadRouter($basepath);
+        $this->router->addMatchTypes(["d" => "[^/]+"]);
+    }
+
+    /**
+     * Parse API request
+     */
+    public function run()
+    {
+        try
+        {
+            $logger = $this->getLoggerObject();
+            $match = $this->router->match();
+            if($match)
+            {
+                $auth = $this->getAuthObject();
+                $auth->run($match["name"]);
+
+                $validator = $this->getValidatorObject();
+                $validator->run($match["name"]);
+
+                $request = explode("#", $match['target']);
+                $action = [$this->getController($request[0]), $request[1]];
+                $result = call_user_func_array($action, $match['params']);
+
+                $logger->logInfo($match["name"], array_merge($match["params"], $_REQUEST), $result);
+
+                echo json_encode($result);
+            }
+            else
+            {
+                header( $_SERVER["SERVER_PROTOCOL"] . ' 404 Not Found');
+                echo json_encode(["error" => "Action not found"]);
+            }
+
+            exit;
+        }
+        catch (ApiException $mgex)
+        {
+            $code   = $mgex->getMgHttpCode();
+            $exdata = $mgex->getAdditionalData();
+
+            $message = "{$mgex->getMgMessage(false)}" . ($this->isDebugOn() ? " | " . print_r($exdata, true) : "");
+        }
+        catch (WhmcsApiException $whmcsex)
+        {
+            $exdata = $whmcsex->getAdditionalData();
+            $message = "{$exdata["data"]["result"]["message"]}: {$exdata["data"]["result"]["error"]}";
+        }
+        catch (\Exception $ex)
+        {
+            $exdata  = $this->isDebugOn() ? print_r($ex, true) : null;
+            $message = "Please contact administration (server side issue)" . ($exdata ? " | ". $exdata : "");
+        }
+
+        $logger->logError($match["name"], array_merge($match["params"], $_REQUEST), $exdata);
+
+        $response = $this->getResponseBuilderObject();
+        $message = $response->build($match["name"], $message);
+
+        http_response_code($code ?: 500);
+        echo json_encode(["error" => $message]);
+    }
+
+    /**
+     * Load router object
+     *
+     * @param $basePath
+     * @throws \Exception
+     */
+    protected function loadRouter($basePath)
+    {
+        $this->router = new \AltoRouter();
+        $this->router->setBasePath($basePath);
+
+        $routes = require ModuleConstants::getDevConfigDir().DS."api".DS."routes.php";
+        $this->router->addRoutes($routes);
+    }
+
+    /**
+     * Get controller object
+     *
+     * @return Object
+     */
+    protected function getController($classname)
+    {
+        $classname = "\\ModulesGarden\\Servers\\ProxmoxVps\\App\\Http\\Api\\{$classname}";
+        return new $classname;
+    }
+
+    /**
+     * Get Authorization class object
+     *
+     * @return Auth class object
+     */
+    protected function getAuthObject()
+    {
+        $config = $this->getConfigElement("auth");
+        $auth = new $config["class"];
+
+        return $auth;
+    }
+
+    /**
+     * @return mixed
+     */
+    protected function getValidatorObject()
+    {
+        $config = $this->getConfigElement("validator");
+        $validator = new $config["class"];
+
+        return $validator;
+    }
+
+
+    /**
+     * Get Logger class object
+     *
+     * @return Logger class object
+     */
+    protected function getLoggerObject()
+    {
+        $config = $this->getConfigElement("logger");
+        $auth = new $config["class"];
+
+        return $auth;
+    }
+
+    /**
+     * Get Logger class object
+     *
+     * @return Logger class object
+     */
+    protected function getResponseBuilderObject()
+    {
+        $config = $this->getConfigElement("responseBuilder");
+        $auth = new $config["class"];
+
+        return $auth;
+    }
+
+    /**
+     * Get configuration element by type
+     *
+     * @param $type
+     * @return mixed
+     */
+    protected function getConfigElement($type)
+    {
+        $config = require ModuleConstants::getDevConfigDir().DS."api".DS."config.php";
+        foreach($config as $element)
+        {
+            if($element["type"] == $type)
+            {
+                return $element;
+            }
+        }
+    }
+}

+ 90 - 0
core/Api/Whmcs.php

@@ -0,0 +1,90 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\Api;
+
+use \ModulesGarden\Servers\ProxmoxVps\Core\Models\Whmcs\Admins;
+use \ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Exceptions\Exception;
+use \ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\ErrorCodes\ErrorCodesLib;
+
+class Whmcs
+{
+    /**
+     * @var Admins
+     */
+    protected $admins;
+
+    /**
+     * @var string
+     */
+    protected $username;
+
+    /**
+     * @param Admins $admins
+     * @throws \ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Exceptions\Exception
+     */
+    public function __construct(Admins $admins)
+    {
+        $this->admins = $admins;
+        $this->getAdminUserName();
+
+        if (function_exists('localAPI') === false)
+        {
+            throw new Exception(ErrorCodesLib::CORE_WAPI_000001);
+        }
+    }
+
+    /**
+     * @return string
+     */
+    protected function getAdminUserName()
+    {
+        if (isset($this->username) === false)
+        {
+            $this->username = $this->admins->first()->toArray()['username'];
+        }
+
+        return $this->username;
+    }
+
+    public function call($command, $config = [])
+    {
+
+        $result = localAPI($command, $config, $this->getAdminUserName());
+
+        if ($result['result'] == 'error')
+        {
+            $exc = new Exception(ErrorCodesLib::CORE_WAPI_000002, ['command' => $command, 'data' => $config, 'result' => $result]);
+            $exc->setCustomMessage($result['message']);
+
+            throw $exc;
+        }
+        unset($result['result']);
+
+        return $result;
+    }
+
+    public function getAdminDetails($adminId)
+    {
+        $data = $this->admins->where("id", "LIKE", $adminId)->first();
+
+        if ($data === null)
+        {
+            throw new Exception(ErrorCodesLib::CORE_WAPI_000003, ['adminId' => $adminId], ['adminId' => $adminId]);
+        }
+
+        $result = localAPI("getadmindetails", [], $data->toArray()['username']);
+
+        if ($result['result'] == 'error')
+        {
+            $exc = new Exception(ErrorCodesLib::CORE_WAPI_000004, ['command' => "getadmindetails", 'data' => [], 'result' => $result]);
+            $exc->setCustomMessage($result['message']);
+
+            throw $exc;
+        }
+
+        $result['allowedpermissions'] = explode(",", $result['allowedpermissions']);
+        unset($result['result']);
+
+        return $result;
+    }
+}

+ 172 - 0
core/App/AppContext.php

@@ -0,0 +1,172 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\WhmcsErrorManagerWrapper;
+
+class AppContext
+{
+    protected $debugMode = true;
+
+    public function __construct()
+    {
+        require_once __DIR__ . DIRECTORY_SEPARATOR . 'ErrorHandler.php';
+
+        register_shutdown_function([$this, 'handleShutdown']);
+        set_error_handler([$this, 'handleError'], E_ALL);
+
+        $this->loadDebugState();
+
+        //require app bootstrap
+        require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . 'Bootstrap.php';
+
+        if ($this->debugMode)
+        {
+            spl_autoload_register(array('\ModulesGarden\Servers\ProxmoxVps\Core\App\AppContext', 'loadClassLoader'), true, false);
+        }
+    }
+
+    public function runApp($callerName = null, $params = [])
+    {
+        try
+        {
+            $app = new Application();
+            $result = $app->run($callerName, $params);
+
+            restore_error_handler();
+        }
+        catch (\Exception $exc)
+        {
+            restore_error_handler();
+
+            return [
+                'status' => 'error',
+                'message' => $exc->getMessage()
+            ];
+        }
+
+        return $result;
+    }
+
+    public function handleError($errno, $errstr, $errfile, $errline, $errcontext = null)
+    {
+        if ($this->debugMode || (!in_array($errno, ErrorHandler::WARNINGS) && !in_array($errno, ErrorHandler::NOTICES)))
+        {
+            $handler = new ErrorHandler();
+            $errorToken = md5(time());
+            $handler->logError($errorToken, $errno, $errstr, $errfile, $errline, $errcontext);
+        }
+
+        return true;
+    }
+
+    public function handleShutdown()
+    {
+        $errorInstance = null;
+        $errManager = WhmcsErrorManagerWrapper::getErrorManager();
+        if (is_object($errManager) && method_exists($errManager, 'getRunner'))
+        {
+            $runner = $errManager->getRunner();
+            if (is_object($runner) && method_exists($runner, 'getHandlers'))
+            {
+                $handlers = $runner->getHandlers();
+                foreach ($handlers as $handler)
+                {
+                    $rfHandler = new \ReflectionClass($handler);
+                    $method = $rfHandler->getMethod('getException');
+                    $method->setAccessible(true);
+                    $error = $method->invoke($handler);
+                    if (is_object($error))
+                    {
+                        $errorInstance = $error;
+                        break;
+                    }
+                }
+            }
+        }
+
+        if ($errorInstance === null)
+        {
+            $errorInstance = error_get_last();
+            if ($errorInstance === null)
+            {
+                return;
+            }
+
+            $this->handleError($errorInstance['type'], $errorInstance['message'], $errorInstance['file'], $errorInstance['line'], '');
+
+            return;
+        }
+
+        $handler = new ErrorHandler();
+        $errorToken = md5(time());
+        $handler->logError($errorToken, $errorInstance->getCode(), $errorInstance->getMessage(), $errorInstance->getFile(), $errorInstance->getLine(), $errorInstance->getTrace());
+        if ($errorToken)
+        {
+            echo '<input type="hidden" id="mg-sh-h-492318-64534" value="' . $errorToken . '" mg-sh-h-492318-64534-end >';
+        }
+    }
+
+    public function loadDebugState()
+    {
+        $path = dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR . '.debug';
+        if (file_exists($path))
+        {
+            $this->debugMode = true;
+
+            return;
+        }
+
+        $this->debugMode = false;
+    }
+
+    public static function loadClassLoader($class)
+    {
+        $rawClass = trim($class, '\\');
+        $pos = strpos($rawClass, 'ModulesGarden\Servers\ProxmoxVps');
+        if ($pos === 0)
+        {
+            if (!class_exists($class) && self::DEPRECATED[$rawClass])
+            {
+                echo 'This class no longer exists: ' . $class . '<br>';
+                echo 'Use: ' . self::DEPRECATED[$rawClass];
+                die();
+            }
+        }
+    }
+
+    const DEPRECATED = [
+        'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\BaseMassActionButton' => 'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonMassAction',
+        'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\AddIconModalButton' => 'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonCreate',
+        'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\BaseSubmitButton' => 'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonSubmitForm',
+        'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\BaseButton' => 'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonBase',
+        'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\BaseDatatableModalButton' => 'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonDatatableShowModal',
+        'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\BaseModalDataTableActionButton' => 'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonDataTableModalAction',
+        'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\RedirectButton' => 'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonRedirect',
+        'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\BaseModalButton' => 'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonModal',
+        'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\RedirectWithOutTooltipButton' => 'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonRedirect',
+        'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\OnOffAjaxSwitch' => 'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonSwitchAjax',
+        'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\CustomActionButton' => 'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonCustomAction',
+        'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\CustomAjaxActionButton' => 'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonAjaxCustomAction',
+        'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\DatatableModalButtonContextLang' => 'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonDatatableModalContextLang',
+        'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\DropdownButton' => 'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonDropdown',
+        'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\MassActionButtonContextLang' => 'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonMassActionContextLang',
+        'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\Submit' => 'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonSubmitForm',
+        'ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\WhmcsRegisterLoggin' => 'ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\WhmcsLogsHandler',
+        'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\ButtonDropdown' => 'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\DropdawnButtonWrappers\ButtonDropdown',
+        'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\Dropdowntems\DropdownItemButton' => 'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\DropdawnButtonWrappers\ButtonDropdownItem',
+        'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\Dropdowntems\DropdownItemCustonAjaxButton' => 'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\DropdawnButtonWrappers\ButtonDropdownItem',
+        'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\Dropdowntems\DropdownItemCustonButton' => 'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\DropdawnButtonWrappers\ButtonDropdownItem',
+        'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\Dropdowntems\DropdownItemDivider' => 'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\DropdawnButtonWrappers\ButtonDropdownItem',
+        'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\Dropdowntems\DropdownItemModalButton' => 'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\DropdawnButtonWrappers\ButtonDropdownItem',
+        'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\Dropdowntems\DropdownItemRedirectButton' => 'ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Buttons\DropdawnButtonWrappers\ButtonDropdownItem',
+        'ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Exceptions\ApiException' => 'ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Exceptions\Exception',
+        'ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Exceptions\ApiWhmcsException' => 'ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Exceptions\Exception',
+        'ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Exceptions\ControllerException' => 'ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Exceptions\Exception',
+        'ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Exceptions\DependencyInjectionException' => 'ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Exceptions\Exception',
+        'ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Exceptions\MGModuleException' => 'ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Exceptions\Exception',
+        'ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Exceptions\RegisterException' => 'ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Exceptions\Exception',
+        'ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Exceptions\ServiceLocatorException' => 'ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Exceptions\Exception',
+        'ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Exceptions\SmartyException' => 'ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Exceptions\Exception',
+    ];
+}

+ 53 - 0
core/App/AppParamsContainer.php

@@ -0,0 +1,53 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\Addon\Config;
+use function ModulesGarden\Servers\ProxmoxVps\Core\Helper\di;
+use ModulesGarden\Servers\ProxmoxVps\Core\ModuleConstants;
+use ModulesGarden\Servers\ProxmoxVps\Core\ServiceLocator;
+
+class AppParamsContainer
+{
+    /**
+     * @var array
+     * params container
+     */
+    protected $params = [];
+
+    public function __construct()
+    {
+        $addonConfig = ServiceLocator::call(Config::class);
+        $addonConfig->execute();
+        $params = $addonConfig->getConfig();
+
+        if (is_array($params))
+        {
+            $this->params = $params;
+        }
+
+        $this->params['moduleAppType'] = ModuleConstants::getModuleType();
+    }
+
+    public function getParams()
+    {
+        return $this->params;
+    }
+    
+    public function getParam($key, $default = null)
+    {
+        if (isset($this->params[$key]))
+        {
+            return $this->params[$key];
+        }
+        
+        return $default;
+    }
+    
+    public function setParam($key, $value = null)
+    {
+        $this->params[$key] = $value;
+        
+        return $this;
+    }
+}

+ 94 - 0
core/App/Application.php

@@ -0,0 +1,94 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\AppControllers\Http;
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\AppControllers\Addon;
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\AppControllers\Api;
+use ModulesGarden\Servers\ProxmoxVps\Core\Hook\InternalHooksWrapper;
+use ModulesGarden\Servers\ProxmoxVps\Core\ServiceLocator;
+
+use function \ModulesGarden\Servers\ProxmoxVps\Core\Helper\di;
+use ModulesGarden\Servers\ProxmoxVps\Core\Traits\AppParams;
+
+class Application
+{
+    use AppParams;
+
+    public function run($callerName = null, $params = null)
+    {
+        try
+        {
+            $params = $this->runPreAppHook($params);
+
+            $this->setWhmcsParams($params);
+
+            $controller = $this->getControllerClass($callerName);
+
+            $controllerInstance = ServiceLocator::call($controller);
+
+            $result = $controllerInstance->runController($callerName, $params);
+
+            return $result;
+        }
+        catch (\Exception $exc)
+        {
+            $errorPage = ServiceLocator::call(Controllers\Instances\Http\ErrorPage::class);
+
+            $params['mgErrorDetails'] = $exc;
+
+            $result = $errorPage->execute($params);
+
+            return $result;
+        }
+    }
+
+    /**
+     * Saves provided WHMCS params to WhmcsParams service
+     * @param type array
+     */
+    protected function setWhmcsParams($params)
+    {
+        $whmcsParams = di('whmcsParams');
+        $whmcsParams->setParams($params);
+    }
+
+    public function getControllerClass($callerName = null)
+    {
+        $functionName = str_replace($this->getModuleName() . '_', '', $callerName);
+        switch ($functionName)
+        {
+            //HTTP controllers
+            case 'output':
+                return Http::class;
+            case 'clientarea':
+                return Http::class;
+
+            //API controller
+            case 'api':
+                return Api::class;
+
+            //Addon controllers
+            default:
+                return Addon::class;
+        }
+    }
+
+    public function getModuleName ()
+    {
+        return $this->getAppParam('systemName');
+    }
+
+    public function runPreAppHook ($params = [])
+    {
+        //run hook before any app controllers runs
+        $hookWrapper = new InternalHooksWrapper();
+        $newParams = $hookWrapper->runInternalHook('PreAppRun', $params);
+        if ($newParams && $newParams !== false)
+        {
+            return $newParams;
+        }
+
+        return $params;
+    }
+}

+ 19 - 0
core/App/Controllers/AppController.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\ServiceLocator;
+
+abstract class AppController
+{
+    public function runController($callerName, $params)
+    {
+        $controller = $this->getControllerInstanceClass($callerName, $params);
+
+        $controllerInstance = ServiceLocator::call($controller);
+
+        $result = $controllerInstance->runExecuteProcess($params);
+
+        return $result;
+    }
+}

+ 36 - 0
core/App/Controllers/AppControllers/Addon.php

@@ -0,0 +1,36 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\AppControllers;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\AddonController;
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Interfaces\AppController;
+use ModulesGarden\Servers\ProxmoxVps\Core\Traits\AppParams;
+
+class Addon extends \ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\AppController implements AppController
+{
+    use AppParams;
+
+    public function getControllerInstanceClass ($callerName, $params)
+    {
+        $functionName = str_replace($this->getModuleName() . '_', '', $callerName);
+
+        $coreAddon = '\ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\Addon\\' . ucfirst($functionName);
+        if (class_exists($coreAddon) && is_subclass_of($coreAddon, AddonController::class))
+        {
+            return $coreAddon;
+        }
+
+        $appAddon = '\ModulesGarden\Servers\ProxmoxVps\App\Http\Actions\\' . ucfirst($functionName);
+        if (class_exists($appAddon) && is_subclass_of($appAddon, AddonController::class))
+        {
+            return $appAddon;
+        }
+
+        return null;
+    }
+
+    public function getModuleName ()
+    {
+        return $this->getAppParam('systemName');
+    }
+}

+ 13 - 0
core/App/Controllers/AppControllers/Api.php

@@ -0,0 +1,13 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\AppControllers;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Interfaces\AppController;
+
+class Api implements AppController
+{
+    public function getControllerInstanceClass ($callerName, $params)
+    {
+        // TODO: Implement getControllerInstanceClass() method.
+    }
+}

+ 13 - 0
core/App/Controllers/AppControllers/Cron.php

@@ -0,0 +1,13 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\AppControllers;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Interfaces\AppController;
+
+class Cron implements AppController
+{
+    public function getControllerInstanceClass ($callerName, $params)
+    {
+        // TODO: Implement runCalledController() method.
+    }
+}

+ 13 - 0
core/App/Controllers/AppControllers/Hooks.php

@@ -0,0 +1,13 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\AppControllers;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Interfaces\AppController;
+
+class Hooks implements AppController
+{
+    public function getControllerInstanceClass ($callerName, $params)
+    {
+        // TODO: Implement getControllerInstanceClass() method.
+    }
+}

+ 34 - 0
core/App/Controllers/AppControllers/Http.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\AppControllers;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Interfaces\AppController;
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\Http\AdminPageController;
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\Http\ClientPageController;
+use ModulesGarden\Servers\ProxmoxVps\Core\Traits\AppParams;
+
+class Http extends \ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\AppController implements AppController
+{
+    use AppParams;
+
+    public function getControllerInstanceClass ($callerName, $params)
+    {
+        //todo
+        $functionName = str_replace($this->getModuleName() . '_', '', $callerName);
+        switch ($functionName)
+        {
+            //HTTP controllers
+            case 'output':
+                return AdminPageController::class;
+            case 'clientarea':
+                return ClientPageController::class;
+        }
+
+        return null;
+    }
+
+    public function getModuleName ()
+    {
+        return $this->getAppParam('systemName');
+    }
+}

+ 71 - 0
core/App/Controllers/Instances/Addon/Activate.php

@@ -0,0 +1,71 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\Addon;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Interfaces\AddonController;
+use ModulesGarden\Servers\ProxmoxVps\Core\DependencyInjection;
+use ModulesGarden\Servers\ProxmoxVps\Core\Helper\DatabaseHelper;
+use ModulesGarden\Servers\ProxmoxVps\Core\ModuleConstants;
+use ModulesGarden\Servers\ProxmoxVps\Core\ServiceLocator;
+
+/**
+ * Activate module actions
+ */
+class Activate extends \ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\AddonController implements AddonController
+{
+    /**
+     * @var null|DatabaseHelper
+     */
+    protected $databaseHelper = null;
+
+    public function execute($params = [])
+    {
+        try
+        {
+            //Before module activation
+            $return = ServiceLocator::call(\ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Addon\Activate\Before::class)->execute($params);
+            if (!isset($return['status']))
+            {
+                $return['status'] = 'success';
+            }
+
+            //module activation process
+            $return = $this->activate($return);
+
+            //After module activation
+            $return = ServiceLocator::call(\ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Addon\Activate\After::class)->execute($return);
+
+            return $return;
+        }
+        catch (\Exception $exc)
+        {
+            ServiceLocator::call(\ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\ErrorManager::class)->addError(self::class, $exc->getMessage(), $return);
+            return [
+                'status' => 'error',
+                'description' => $exc->getMessage()
+            ];
+        }
+    }
+
+    protected function activate($params = [])
+    {
+        $this->databaseHelper = DependencyInjection::call(DatabaseHelper::class);
+
+        if ($params['status'] === 'error')
+        {
+            return $params;
+        }
+
+        $isErrorCore     = $this->databaseHelper->performQueryFromFile(ModuleConstants::getFullPath('core', 'Database', 'schema.sql'));
+        $isErrorApp     = $this->databaseHelper->performQueryFromFile(ModuleConstants::getFullPath('app', 'Database', 'schema.sql'));
+        $isErrorDataCore = $this->databaseHelper->performQueryFromFile(ModuleConstants::getFullPath('core', 'Database', 'data.sql'));
+        $isErrorDataApp = $this->databaseHelper->performQueryFromFile(ModuleConstants::getFullPath('app', 'Database', 'data.sql'));
+
+        if ($isErrorCore || $isErrorDataCore || $isErrorApp || $isErrorDataApp)
+        {
+            return ['status' => 'error', 'description' => ServiceLocator::call('errorManager')->getFirstError()->getMessage()];
+        }
+
+        return ['status' => 'success'];
+    }
+}

+ 149 - 0
core/App/Controllers/Instances/Addon/Config.php

@@ -0,0 +1,149 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\Addon;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Interfaces\AddonController;
+use ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Data;
+use ModulesGarden\Servers\ProxmoxVps\Core\DependencyInjection;
+use ModulesGarden\Servers\ProxmoxVps\Core\ServiceLocator;
+
+/**
+ * Module configuration wrapper
+ */
+class Config extends \ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\AddonController implements AddonController
+{
+    /**
+     * @var array
+     * list of params passed by WHMCS
+     */
+    private $params = [];
+
+    /**
+     * @var array
+     * module configuration list
+     */
+    protected $config = [];
+
+    /**
+     * @var null|\ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Data
+     *
+     */
+    protected $data = null;
+
+    /**
+     * @var array
+     * list of values to be returned as a part of
+     */
+    protected $configFields = [
+        'name',
+        'description',
+        'version',
+        'author',
+        'fields',
+        'systemName',
+        'debug',
+        'moduleIcon',
+        'clientareaName'
+    ];
+
+    /**
+     * @param array $params - WHMCS params for function _config
+     * @return array
+     */
+    public function execute($params = [])
+    {
+        if (!$this->config)
+        {
+            $this->setParams($params);
+            $this->loadConfig();
+
+            return $this->getConfig();
+        }
+
+        return $this->config;
+    }
+
+    /**
+     * @param array $params
+     */
+    protected function setParams($params = [])
+    {
+        if (is_array($params))
+        {
+            $this->params = $params;
+        }
+    }
+
+    /**
+     * loads module configuration from files yaml configs and moduleVersion.php
+     */
+    protected function loadConfig()
+    {
+        if (!$this->data)
+        {
+            $this->data = DependencyInjection::call(Data::class);
+        }
+    }
+
+    /**
+     * parses config data
+     */
+    public function getConfig()
+    {
+        if ($this->config)
+        {
+            return $this->config;
+        }
+
+        try
+        {
+            //Before loading the config
+            $params = [];
+            $return = ServiceLocator::call(\ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Addon\Config\Before::class)->execute($params);
+
+            foreach ($this->configFields as $field)
+            {
+                $value = $this->data->{$field};
+                if (isset($return[$field]) === false && $value !== null)
+                {
+                    if (is_numeric($value))
+                    {
+                        $return[$field] = (int)$value;
+                    }
+                    else
+                    {
+                        $return[$field] = $value;
+                    }
+                }
+            }
+
+            //After loading the config
+            $return = ServiceLocator::call(\ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Addon\Config\After::class)->execute($return);
+
+            $this->config = $return;
+
+            return $return;
+        }
+        catch (\Exception $ex)
+        {
+            ServiceLocator::call(\ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\ErrorManager::class)->addError(self::class, $ex->getMessage(), $return);
+
+            return $return ? : [];
+        }
+    }
+
+    public function getConfigValue($key, $defaultValue = null)
+    {
+        if (!$this->config)
+        {
+            $this->execute();
+        }
+
+        if (!isset($this->config[$key]))
+        {
+            return $defaultValue;
+        }
+
+        return $this->config[$key];
+    }
+}

+ 319 - 0
core/App/Controllers/Instances/Addon/ConfigOptions.php

@@ -0,0 +1,319 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\Addon;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\ResponseResolver;
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Installer\ModuleInstaller;
+use ModulesGarden\Servers\ProxmoxVps\Core\Http\JsonResponse;
+use ModulesGarden\Servers\ProxmoxVps\Core\Models\Whmcs\Product;
+use ModulesGarden\Servers\ProxmoxVps\Core\Models\Whmcs\Server;
+use ModulesGarden\Servers\ProxmoxVps\Core\ModuleConstants;
+use ModulesGarden\Servers\ProxmoxVps\Core\ServiceLocator;
+use ModulesGarden\Servers\ProxmoxVps\Core\Traits\AppParams;
+use ModulesGarden\Servers\ProxmoxVps\Core\Traits\OutputBuffer;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\Traits\RequestObjectHandler;
+
+/**
+ * ConfigOptions module actions
+ */
+class ConfigOptions extends \ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\AddonController
+{
+    use AppParams;
+    use RequestObjectHandler;
+    use OutputBuffer;
+
+    public function execute($params = null)
+    {
+        $productId = $this->getRequestValue('id');
+        if (($this->getRequestValue('action') === 'module-settings' || ($this->getRequestValue('loadData') && $this->getRequestValue('ajax') == '1')))
+        {
+            try
+            {
+                //check storage
+                $invalidStoragePermissions = $this->getInvalidStoragePermitions();
+                if ($invalidStoragePermissions)
+                {
+                    return $this->getInvalidStoragePermissionsError($invalidStoragePermissions);
+                }
+
+                //check server type
+                if (!$this->isCorrectServerType())
+                {
+                    return $this->getInvalidServerTypeError();
+                }
+
+                $requirementsHandler = new \ModulesGarden\Servers\ProxmoxVps\Core\App\Requirements\Checker();
+
+                if ($requirementsHandler->getUnfulfilledRequirements())
+                {
+                    $data = $this->buildErrorMessage(implode('<br>', $requirementsHandler->getUnfulfilledRequirements()));
+
+                    return $this->returnAjaxResponse($data);
+                }
+
+                $this->updateProductType();
+                $this->addRequiredCustomFields();
+
+                //run installer
+                $installer = new ModuleInstaller();
+
+                $installer->makeInstall();
+
+                if (!$installer->isInstallCorrect())
+                {
+                    return $this->buildFailedQueriesMessage($installer->getFailedQueries());
+                }
+            }
+            catch (\Excpetion $exc)
+            {
+                $data = $this->buildErrorMessage($exc->getMessage());
+
+                return $this->returnAjaxResponse($data);
+            }
+
+            try
+            {
+                $this->setAppParam('IntegrationControlerName', \ModulesGarden\Servers\ProxmoxVps\App\Http\Actions\ConfigOptions::class);
+                $this->setAppParam('IntegrationControlerMethod', 'runExecuteProcess');
+
+                $configOptionsController = new \ModulesGarden\Servers\ProxmoxVps\App\Http\Actions\ConfigOptions();
+
+                $result = $configOptionsController->execute();
+
+                return $result;
+            }
+            catch (\Exception $exc)
+            {
+                $data = $this->buildErrorMessage($exc->getMessage());
+                $response = new JsonResponse();
+                $response->setData($data);
+
+                $resolver = new ResponseResolver($response);
+
+                $resolver->resolve();
+            }
+
+        }
+        else if ($this->getRequestValue('action') === 'save')
+        {
+            if (!$this->isCorrectServerType())
+            {
+                return [];
+            }
+
+            return [\ModulesGarden\Servers\ProxmoxVps\App\Http\Actions\ConfigOptions::class, 'runExecuteProcess'];
+        }
+
+        return [];
+    }
+
+    /**
+     * Catch errors during form creation
+     * @param null $params
+     * @return \ModulesGarden\Servers\ProxmoxVps\Core\Helper\type
+     */
+    public function runExecuteProcess($params = null)
+    {
+        try
+        {
+            return parent::runExecuteProcess($params);;
+        }
+        catch(\Exception $exc)
+        {
+            $data = $this->buildErrorMessage($exc->getMessage());
+            $response = new JsonResponse();
+            $response->setData($data);
+
+            $resolver = new ResponseResolver($response);
+
+            $resolver->resolve();
+        }
+    }
+
+    public function getInvalidStoragePermitions()
+    {
+        $requiredPaths = [
+            ModuleConstants::getFullPath('storage'),
+            ModuleConstants::getFullPath('storage', 'app'),
+            ModuleConstants::getFullPath('storage', 'crons'),
+            ModuleConstants::getFullPath('storage', 'logs')
+        ];
+
+        $invalidPermissions = [];
+        $lang = ServiceLocator::call('lang');
+        foreach ($requiredPaths as $path)
+        {
+            if (!is_writable($path))
+            {
+                $invalidPermissions[] = $lang->addReplacementConstant('storage_path', $path)->absoluteT('permissionsStorage');
+            }
+            if (!is_readable($path))
+            {
+                $invalidPermissions[] = $lang->addReplacementConstant('storage_path', $path)->absoluteT('permissionsStorageReadable');
+            }
+        }
+
+        return $invalidPermissions;
+    }
+
+    public function buildFailedQueriesMessage($failedQueries = [])
+    {
+        $content = '';
+        foreach ($failedQueries as $query)
+        {
+            $content .= '<div class="panel panel-danger"><div class="panel-heading">Installation Error</div><div class="panel-body" style="padding:0px;"><ul class="list-group" style="margin-bottom: -5px;margin-top: -5px;">';
+            //$content .= '<li class="list-group-item ">Status: ' . $query['status'] . '</li>';
+            $content .= '<li class="list-group-item ">File: ' . $query['file'] . '</li>';
+            $content .= '<li class="list-group-item ">Error Message: ' . $query['errorMessage'] . '</li>';
+            $content .= '<li class="list-group-item ">Raw Query: ' . $query['rawQuery'] . '</li>';
+            $content .= '</ul></div></div>';
+        }
+
+        $data = [
+            'content' =>
+                '<tr><td class="fieldlabel" style="width:0%; display:none;"></td><td style="width=100%;" class="fieldarea">' . $content . '</td></tr>',
+            'mode' => 'advanced'
+        ];
+
+        return $this->returnAjaxResponse($data);
+    }
+
+    public function getInvalidStoragePermissionsError($permissions = [])
+    {
+        $data = $this->buildErrorMessage(implode('<br>', $permissions));
+
+        return $this->returnAjaxResponse($data);
+    }
+
+    public function isCorrectServerType()
+    {
+        try
+        {
+            if (class_exists('\ModulesGarden\Servers\ProxmoxVps\App\Http\Actions\MetaData'))
+            {
+                $metaDataController = new \ModulesGarden\Servers\ProxmoxVps\App\Http\Actions\MetaData();
+                $details = $metaDataController->execute(null);
+                if ($details['RequiresServer'] !== true)
+                {
+                    return true;
+                }
+
+                $serverGroupId = $this->getServerGroupId();
+
+                $sModel = new Server();
+                $server = $sModel
+                    ->select(['tblservers.type'])
+                    ->join('tblservergroupsrel', 'tblservergroupsrel.serverid', '=', 'tblservers.id')
+                    ->where('tblservergroupsrel.groupid', $serverGroupId)->first();
+
+                if (!$server)
+                {
+                    return false;
+                }
+
+                if ($server->type !== $this->getModuleName())
+                {
+                    return false;
+                }
+            }
+        }
+        catch (\Exception $exception)
+        {
+            //todo log me
+            return false;
+        }
+
+        return true;
+    }
+
+    public function getServerGroupId()
+    {
+        $gid = $this->getRequestValue('servergroup', false);
+        if (!$gid && $gid !== '0' && $gid !== 0)
+        {
+            $pid = $this->getRequestValue('id', 0);
+            $productModel = new Product();
+            $product = $productModel->where('id', $pid)->first();
+            if (!$product)
+            {
+                //can add first product here if needed
+                return 0;
+            }
+
+            return $product->servergroup;
+        }
+
+        return (int)$gid;
+    }
+
+    public function getInvalidServerTypeError()
+    {
+        $lang = ServiceLocator::call('lang');
+
+        $messaage = $lang->addReplacementConstant('provisioning_name', $this->getModuleDisplayName())->absoluteT('invalidServerType');
+        $data = $this->buildErrorMessage($messaage);
+
+        return $this->returnAjaxResponse($data);
+    }
+
+    public function buildErrorMessage($message)
+    {
+        $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>',
+            'mode' => 'advanced'
+        ];
+
+        return $data;
+    }
+
+    public function returnAjaxResponse($data = [])
+    {
+        $response = new JsonResponse();
+        $response->setData($data);
+
+        return $response;
+    }
+
+    public function updateProductType()
+    {
+        if ($this->getRequestValue('action') !== 'module-settings'
+            || $this->getAppParam('moduleAppType') !== 'server')
+        {
+            return false;
+        }
+
+        $moduleName = $this->getAppParam('systemName');
+        $pid = $this->getRequestValue('id', false);
+        $servergroup = $this->getRequestValue('servergroup', 0);
+
+        if ($pid && $servergroup > 0)
+        {
+            $product = new Product();
+            $product->where('id', $pid)->update(['servertype' => $moduleName, 'servergroup' => $servergroup]);
+        }
+    }
+
+    public function getModuleName()
+    {
+        return $this->getAppParam('systemName');
+    }
+
+    public function getModuleDisplayName()
+    {
+        return $this->getAppParam('name');
+    }
+
+    public function addRequiredCustomFields()
+    {
+        $pid = $this->getRequestValue('id', false);
+        if ($pid === false)
+        {
+            return;
+        }
+
+        $product = new \ModulesGarden\Servers\ProxmoxVps\Packages\WhmcsService\Product($pid);
+
+        $product->createCustomFieldsFromConfig();
+    }
+}

+ 44 - 0
core/App/Controllers/Instances/Addon/Deactivate.php

@@ -0,0 +1,44 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\Addon;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Interfaces\AddonController;
+use ModulesGarden\Servers\ProxmoxVps\Core\ServiceLocator;
+
+/**
+ * Deactivate module action
+ */
+class Deactivate extends \ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\AddonController implements AddonController
+{
+
+    /**
+     * @param array $params
+     * @return array
+     */
+    public function execute($params = [])
+    {
+        try
+        {
+            // before
+            $return = ServiceLocator::call(\ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Addon\Deactivate\Before::class)->execute($params);
+
+            if (!isset($return['status']))
+            {
+                $return['status'] = 'success';
+            }
+
+            // after
+            $return = ServiceLocator::call(\ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Addon\Deactivate\After::class)->execute($return);
+
+            return $return;
+        }
+        catch (\Exception $exc)
+        {
+            ServiceLocator::call(\ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\ErrorManager::class)->addError(self::class, $exc->getMessage(), $return);
+            return [
+                'status' => 'error',
+                'description' => $exc->getMessage()
+            ];
+        }
+    }
+}

+ 48 - 0
core/App/Controllers/Instances/Addon/Upgrade.php

@@ -0,0 +1,48 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\Addon;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Interfaces\AddonController;
+use ModulesGarden\Servers\ProxmoxVps\Core\Helper\DatabaseHelper;
+use ModulesGarden\Servers\ProxmoxVps\Core\ServiceLocator;
+
+/**
+ * module update process
+ */
+class Upgrade extends \ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\AddonController implements AddonController
+{
+    /**
+     * @var null|DatabaseHelper
+     */
+    protected $databaseHelper = null;
+
+    public function execute($params = [])
+    {
+        if ($version == '')
+        {
+            $version = isset($this->params['version']) ? $this->params['version'] : $params['version'];
+        }
+
+        try
+        {
+            // after
+            $return = ServiceLocator::call(\ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Addon\Update\After::class)->execute(['version' => $version]);
+
+            // update
+            if (!isset($return['version']))
+            {
+                $return['version'] = $version;
+            }
+            $patchManager = ServiceLocator::call("patchManager")->run(/*$this->getConfig("version")*/ '', $version);
+
+            // before
+            $return = ServiceLocator::call(\ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Addon\Update\Before::class)->execute($return);
+
+            return $return;
+        }
+        catch (\Exception $ex)
+        {
+            ServiceLocator::call(\ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\ErrorManager::class)->addError(self::class, $ex->getMessage(), $return);
+        }
+    }
+}

+ 119 - 0
core/App/Controllers/Instances/AddonController.php

@@ -0,0 +1,119 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Http\PageNotFound;
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Interfaces\DefaultController;
+use ModulesGarden\Servers\ProxmoxVps\Core\Helper;
+use ModulesGarden\Servers\ProxmoxVps\Core\Http\JsonResponse;
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\ResponseResolver;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\ViewAjax;
+use ModulesGarden\Servers\ProxmoxVps\Core\UI\ViewIntegrationAddon;
+
+abstract class AddonController implements DefaultController
+{
+    use \ModulesGarden\Servers\ProxmoxVps\Core\Traits\Lang;
+    use \ModulesGarden\Servers\ProxmoxVps\Core\Traits\OutputBuffer;
+    use \ModulesGarden\Servers\ProxmoxVps\Core\Traits\IsAdmin;
+    use \ModulesGarden\Servers\ProxmoxVps\Core\UI\Traits\RequestObjectHandler;
+    use \ModulesGarden\Servers\ProxmoxVps\Core\Traits\ErrorCodesLibrary;
+    use \ModulesGarden\Servers\ProxmoxVps\Core\Traits\AppParams;
+
+    public function runExecuteProcess($params = null)
+    {
+        $this->loadLangContext();
+
+        $resault = $this->execute($params);
+        if ($resault instanceof JsonResponse)
+        {
+            $resolver = new ResponseResolver($resault);
+
+            $resolver->resolve();
+        }
+
+        if ($this->isValidIntegrationCallback($resault))
+        {
+            $this->setAppParam('IntegrationControlerName', $resault[0]);
+            $this->setAppParam('IntegrationControlerMethod', $resault[1]);
+
+            //to do catch exceptions
+            $resault = Helper\di($resault[0], $resault[1]);
+        }
+
+        if ($resault instanceof ViewAjax)
+        {
+            $this->resolveAjax($resault);
+        }
+
+        if (!$resault instanceof ViewIntegrationAddon)
+        {
+            return $resault;
+        }
+
+        if ($resault instanceof JsonResponse)
+        {
+            $resolver = new ResponseResolver($resault);
+
+            $resolver->resolve();
+        }
+
+        $addonIntegration = $this->getIntegrationControler($params['action']);
+
+        return $addonIntegration->runExecuteProcess($resault);
+
+    }
+
+    public function isValidIntegrationCallback($callback = null)
+    {
+        if (is_callable($callback))
+        {
+            return true;
+        }
+
+        return false;
+    }
+
+    public function resolveAjax($resault)
+    {
+        $ajaxResponse = $resault->getResponse();
+
+        $resolver = new ResponseResolver($ajaxResponse);
+
+        $resolver->resolve();
+    }
+
+    protected function getIntegrationControler($action = null)
+    {
+        switch ($action)
+        {
+            case 'ConfigOptions':
+                return Helper\di(\ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\Http\ConfigOptionsIntegration::class);
+                break;
+            case 'AdminServicesTabFields':
+                return Helper\di(\ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\Http\AdminServicesTabFieldsIntegration::class);
+                break;
+            default:
+                return Helper\di(\ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\Http\AddonIntegration::class);
+        }
+    }
+
+    public function loadLangContext()
+    {
+        $this->loadLang();
+
+        if ($this->getAppParam('IntegrationControlerName'))
+        {
+            $parts = explode('\\', $this->getAppParam('IntegrationControlerName'));
+
+            $controller = end($parts);
+        }
+        else
+        {
+            $parts = explode('\\', get_class($this));
+
+            $controller = end($parts);
+        }
+
+        $this->lang->setContext(($this->getAppParam('moduleAppType') . ($this->isAdmin() ? 'AA' : 'CA')), lcfirst($controller));
+    }
+}

+ 11 - 0
core/App/Controllers/Instances/Api/ApiController.php

@@ -0,0 +1,11 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\Api;
+
+class ApiController implements DefaultController
+{
+    public function execute ()
+    {
+        // TODO: Implement execute() method.
+    }
+}

+ 40 - 0
core/App/Controllers/Instances/Http/AddonIntegration.php

@@ -0,0 +1,40 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\Http;
+
+use \ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Interfaces\AdminArea;
+use \ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Interfaces\ClientArea;
+use \ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\HttpController;
+
+class AddonIntegration extends HttpController implements AdminArea, ClientArea
+{
+    protected $templateName = 'addonIntegration';
+    protected $templateDir = null;
+
+    public function execute($response = null)
+    {
+        $this->loadLangContext();
+        $this->setControllerResult($response);
+        
+        if (!$this->controllerResult)
+        {
+            return '';
+        }
+
+        return $this->resolveResponse();
+    }
+
+    public function resolveResponse()
+    {
+        if ($this->controllerResult instanceof \ModulesGarden\Servers\ProxmoxVps\Core\Http\Response)
+        {
+            $this->controllerResult->setForceHtml();
+        }
+
+        return $this->responseResolver->setResponse($this->controllerResult)
+            ->setTemplateName($this->getTemplateName())
+            ->setTemplateDir($this->getTemplateDir())
+            ->setPageController($this)
+            ->resolve();
+    }
+}

+ 11 - 0
core/App/Controllers/Instances/Http/AdminPageController.php

@@ -0,0 +1,11 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\Http;
+
+use \ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Interfaces\AdminArea;
+use \ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\HttpController;
+
+class AdminPageController extends HttpController implements AdminArea
+{
+
+}

+ 39 - 0
core/App/Controllers/Instances/Http/AdminServicesTabFieldsIntegration.php

@@ -0,0 +1,39 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\Http;
+
+use \ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Interfaces\AdminArea;
+use \ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\HttpController;
+
+class AdminServicesTabFieldsIntegration extends HttpController implements AdminArea
+{
+    protected $templateName = 'adminServicesTabFieldsIntegration';
+    protected $templateDir = null;
+
+    public function execute($response = null)
+    {
+        $this->loadLangContext();
+        $this->setControllerResult($response);
+
+        if (!$this->controllerResult)
+        {
+            return '';
+        }
+
+        return ['' => $this->resolveResponse()];
+    }
+
+    public function resolveResponse()
+    {
+        if ($this->controllerResult instanceof \ModulesGarden\Servers\ProxmoxVps\Core\Http\Response)
+        {
+            $this->controllerResult->setForceHtml();
+        }
+
+        return $this->responseResolver->setResponse($this->controllerResult)
+            ->setTemplateName($this->getTemplateName())
+            ->setTemplateDir($this->getTemplateDir())
+            ->setPageController($this)
+            ->resolve();
+    }
+}

+ 23 - 0
core/App/Controllers/Instances/Http/ClientPageController.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\Http;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Interfaces\ClientArea;
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\HttpController;
+use ModulesGarden\Servers\ProxmoxVps\Core\Hook\InternalHooksWrapper;
+
+class ClientPageController extends HttpController implements ClientArea
+{
+    public function execute($params = null)
+    {
+        //run hook before client area page is loaded
+        $hookWrapper = new InternalHooksWrapper();
+        $newParams = $hookWrapper->runInternalHook('PreClientAreaPageLoad', $params);
+        if ($newParams && is_array($newParams))
+        {
+            $params = $newParams;
+        }
+
+        return parent::execute($params);
+    }
+}

+ 50 - 0
core/App/Controllers/Instances/Http/ConfigOptionsIntegration.php

@@ -0,0 +1,50 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\Http;
+
+use \ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Interfaces\AdminArea;
+use \ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\HttpController;
+
+class ConfigOptionsIntegration extends HttpController implements AdminArea
+{
+    protected $templateName = 'configOptionsIntegration';
+    protected $templateDir = null;
+
+    public function execute($response = null)
+    {
+        $this->loadLangContext();
+        $this->setControllerResult($response);
+
+        if (!$this->controllerResult)
+        {
+            return '';
+        }
+
+        $result = $this->resolveResponse();
+
+        $data = [
+            'content' => $result,
+            'mode' => 'advanced'
+        ];
+
+        $enc = json_encode($data);
+
+        $this->cleanOutputBuffer();
+        echo $enc;
+        exit;
+    }
+
+    public function resolveResponse()
+    {
+        if ($this->controllerResult instanceof \ModulesGarden\Servers\ProxmoxVps\Core\Http\Response)
+        {
+            $this->controllerResult->setForceHtml();
+        }
+
+        return $this->responseResolver->setResponse($this->controllerResult)
+            ->setTemplateName($this->getTemplateName())
+            ->setTemplateDir($this->getTemplateDir())
+            ->setPageController($this)
+            ->resolve();
+    }
+}

+ 82 - 0
core/App/Controllers/Instances/Http/ErrorPage.php

@@ -0,0 +1,82 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\Http;
+
+use \ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Interfaces\AdminArea;
+use \ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Interfaces\ClientArea;
+use \ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\HttpController;
+
+class ErrorPage extends HttpController implements AdminArea, ClientArea
+{
+    protected $templateName = 'errorPage';
+
+    public function execute ($params = null)
+    {
+        $this->setParams($params);
+        
+        $this->parseError();
+        
+        return $this->resolveResponse();
+    }
+
+    public function resolveResponse()
+    {
+        if ($this->getRequestValue('ajax') == '1')
+        {
+            return $this->resolveResponseAjax();
+        }
+
+        return $this->responseResolver->setResponse(\ModulesGarden\Servers\ProxmoxVps\Core\Helper\view())
+            ->setTemplateName($this->getTemplateName())
+            ->setTemplateDir($this->getTemplateDir())
+            ->setPageController($this)
+            ->resolve();
+    }
+    
+    public function parseError()
+    {
+        $err = $this->getParam('mgErrorDetails');
+        if (!$err)
+        {
+            return null;
+        }
+
+        if (!($err instanceof \ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Exceptions\Exception))
+        {
+            $nErr = new \ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Exceptions\Exception(null, null, null, $err);
+
+            $this->setParam('mgErrorDetails', $nErr);
+        }
+
+        $this->logError();
+    }
+
+    public function logError()
+    {
+        $err = $this->getParam('mgErrorDetails');
+
+        /**
+         * \ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\WhmcsLogsHandler
+         */
+        $logger = \ModulesGarden\Servers\ProxmoxVps\Core\ServiceLocator::call('whmcsLogger');
+
+        $logger->addModuleLogError($err);
+    }
+
+    public function resolveResponseAjax()
+    {
+        $err = $this->getParam('mgErrorDetails');
+        if (!$err)
+        {
+            return null;
+        }
+
+        $ajaxData = (new \ModulesGarden\Servers\ProxmoxVps\Core\UI\ResponseTemplates\DataJsonResponse($err->getDetailsToDisplay()))->setStatusError();
+
+        return $this->responseResolver->setResponse($ajaxData->getFormatedResponse())
+            ->setTemplateName($this->getTemplateName())
+            ->setTemplateDir($this->getTemplateDir())
+            ->setPageController($this)
+            ->resolve();
+    }
+}

+ 38 - 0
core/App/Controllers/Instances/Http/Integration.php

@@ -0,0 +1,38 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\Http;
+
+use \ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Interfaces\AdminArea;
+use \ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Interfaces\ClientArea;
+use \ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\HttpController;
+
+class Integration extends HttpController implements AdminArea, ClientArea
+{
+    protected $templateName = 'integration';
+
+    public function execute($params = null)
+    {
+        $this->setParams($params);
+        
+        if (!$this->controllerResult)
+        {
+            return '';
+        }
+
+        return $this->resolveResponse();
+    }
+
+    public function resolveResponse()
+    {
+        if ($this->controllerResult instanceof \ModulesGarden\Servers\ProxmoxVps\Core\Http\Response)
+        {
+            $this->controllerResult->setForceHtml();
+        }
+
+        return $this->responseResolver->setResponse($this->controllerResult)
+            ->setTemplateName($this->getTemplateName())
+            ->setTemplateDir($this->getTemplateDir())
+            ->setPageController($this)
+            ->resolve();
+    }
+}

+ 31 - 0
core/App/Controllers/Instances/Http/PageNotFound.php

@@ -0,0 +1,31 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\Http;
+
+use \ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Interfaces\AdminArea;
+use \ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Interfaces\ClientArea;
+use \ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\HttpController;
+
+class PageNotFound extends HttpController implements AdminArea, ClientArea
+{
+    protected $templateName = 'pageNotFound';
+
+    public function execute ($params = null)
+    {
+        $this->setParams($params);
+        
+        return $this->resolveResponse();
+    }
+
+    public function resolveResponse()
+    {
+        $view = \ModulesGarden\Servers\ProxmoxVps\Core\Helper\view();
+        $view->replaceBreadcrumbTitle('1', 'pageNotFound');
+
+        return $this->responseResolver->setResponse($view)
+            ->setTemplateName($this->getTemplateName())
+            ->setTemplateDir($this->getTemplateDir())
+            ->setPageController($this)
+            ->resolve();
+    }
+}

+ 189 - 0
core/App/Controllers/Instances/HttpController.php

@@ -0,0 +1,189 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances;
+
+use \ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Interfaces\AdminArea;
+use \ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Interfaces\ClientArea;
+use \ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Interfaces\DefaultController;
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\ResponseResolver;
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Router;
+use \ModulesGarden\Servers\ProxmoxVps\Core\DependencyInjection;
+use ModulesGarden\Servers\ProxmoxVps\Core\ModuleConstants;
+
+abstract class HttpController implements DefaultController
+{
+    use \ModulesGarden\Servers\ProxmoxVps\Core\Traits\Lang;
+    use \ModulesGarden\Servers\ProxmoxVps\Core\Traits\Smarty;
+    use \ModulesGarden\Servers\ProxmoxVps\Core\Traits\OutputBuffer;
+    use \ModulesGarden\Servers\ProxmoxVps\Core\Traits\IsAdmin;
+    use \ModulesGarden\Servers\ProxmoxVps\Core\UI\Traits\RequestObjectHandler;
+    use \ModulesGarden\Servers\ProxmoxVps\Core\Traits\ErrorCodesLibrary;
+    use \ModulesGarden\Servers\ProxmoxVps\Core\Traits\Params;
+    use \ModulesGarden\Servers\ProxmoxVps\Core\Traits\AppParams;
+
+    const ADMIN = 'admin';
+    const CLIENT = 'client';
+
+    protected $templateName = 'main';
+    protected $templateContext = 'default';
+    protected $templateDir = null;
+
+    protected $controllerResult = null;
+
+    /**
+     * @var Router|null
+     *
+     */
+    protected $router = null;
+    protected $responseResolver = null;
+
+    public function __construct()
+    {
+        $this->loadSmarty();
+        $this->isAdmin();
+
+        $this->router = new Router();
+        $this->responseResolver = new ResponseResolver();
+    }
+
+    public function execute($params = null)
+    {
+        $this->setParams($params);
+
+        if (!$this->router->isControllerCallable() || !$this->isAdminContextValid())
+        {
+            return $this->controllerResult = $this->getPageNotFound();
+        }
+        else
+        {
+            $this->setAppParam('HttpControlerName', $this->router->getControllerClass());
+            $this->setAppParam('HttpControlerMethod', $this->router->getControllerMethod());
+
+            $this->controllerResult = $this->getControllerResponse();
+        }
+
+        return $this->resolveResponse();
+    }
+
+    public function resolveResponse()
+    {
+        return $this->responseResolver->setResponse($this->controllerResult)
+            ->setTemplateName($this->getTemplateName())
+            ->setTemplateDir($this->getTemplateDir())
+            ->setPageController($this)
+            ->resolve();
+    }
+
+    public function isAdminContextValid()
+    {
+        if ($this->isAdmin() && !($this instanceof AdminArea))
+        {
+            return false;
+        }
+
+        if (!$this->isAdmin() && !($this instanceof ClientArea))
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+    public function getPageNotFound()
+    {
+        $notFound = new Http\PageNotFound();
+
+        return $notFound->execute();
+    }
+
+    protected function getControllerResponse()
+    {
+        $this->loadLang();
+        $this->lang->setContext(($this->getAppParam('moduleAppType') . ($this->isAdmin() ? 'AA' : 'CA')), lcfirst($this->getControllerClass(true)));
+
+        $result = DependencyInjection::create(
+            $this->router->getControllerClass(),
+            $this->router->getControllerMethod()
+        );
+
+        return $result;
+    }
+
+    public function getTemplateName()
+    {
+        return $this->templateName;
+    }
+
+    public function getTemplateDir()
+    {
+        if ($this->templateDir === null)
+        {
+            $this->templateDir = ModuleConstants::getTemplateDir() . DIRECTORY_SEPARATOR .
+                ($this->isAdmin() ? self::ADMIN : (self::CLIENT . DIRECTORY_SEPARATOR . $this->getTemplateContext()))
+               . DIRECTORY_SEPARATOR . 'controlers';
+        }
+
+        return $this->templateDir;
+    }
+
+    public function getTemplateContext()
+    {
+        return $this->templateContext;
+    }
+
+    public function getControllerClass($raw = false)
+    {
+        if ($raw)
+        {
+            $namespaceParts = explode('\\', $this->getControllerClass());
+
+            return end($namespaceParts);
+        }
+
+        return $this->router->getControllerClass();
+    }
+
+    public function getControllerMethod()
+    {
+        return $this->router->getControllerMethod();
+    }
+
+    /**
+     * @param null $controllerResult
+     */
+    public function setControllerResult ($controllerResult)
+    {
+        $this->controllerResult = $controllerResult;
+    }
+
+    /**
+     * @return null
+     */
+    public function getControllerResult ()
+    {
+        return $this->controllerResult;
+    }
+
+    public function runExecuteProcess($params = null)
+    {
+        return $this->execute($params);
+    }
+
+    public function loadLangContext()
+    {
+        $this->loadLang();
+
+        if ($this->getAppParam('IntegrationControlerName'))
+        {
+            $parts = explode('\\', $this->getAppParam('IntegrationControlerName'));
+
+            $controller = end($parts);
+        }
+        else
+        {
+            $controller = $this->getControllerClass(true);
+        }
+
+        $this->lang->setContext(($this->getAppParam('moduleAppType') . ($this->isAdmin() ? 'AA' : 'CA')), lcfirst($controller));
+    }
+}

+ 8 - 0
core/App/Controllers/Interfaces/AddonController.php

@@ -0,0 +1,8 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Interfaces;
+
+interface AddonController
+{
+    public function execute($params = []);
+}

+ 8 - 0
core/App/Controllers/Interfaces/AdminArea.php

@@ -0,0 +1,8 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Interfaces;
+
+interface AdminArea
+{
+
+}

+ 8 - 0
core/App/Controllers/Interfaces/AppController.php

@@ -0,0 +1,8 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Interfaces;
+
+interface AppController
+{
+    public function getControllerInstanceClass($callerName, $params);
+}

+ 8 - 0
core/App/Controllers/Interfaces/ClientArea.php

@@ -0,0 +1,8 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Interfaces;
+
+interface ClientArea
+{
+
+}

+ 10 - 0
core/App/Controllers/Interfaces/DefaultController.php

@@ -0,0 +1,10 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Interfaces;
+
+interface DefaultController
+{
+    public function execute($params = null);
+
+    public function runExecuteProcess($params = null);
+}

+ 137 - 0
core/App/Controllers/ResponseResolver.php

@@ -0,0 +1,137 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers;
+
+use \ModulesGarden\Servers\ProxmoxVps\Core\UI\View;
+use \ModulesGarden\Servers\ProxmoxVps\Core\Http\JsonResponse;
+use \ModulesGarden\Servers\ProxmoxVps\Core\Http\RedirectResponse;
+use \ModulesGarden\Servers\ProxmoxVps\Core\Http\Response;
+
+class ResponseResolver
+{
+    use \ModulesGarden\Servers\ProxmoxVps\Core\Traits\Lang;
+    use \ModulesGarden\Servers\ProxmoxVps\Core\Traits\Smarty;
+    use \ModulesGarden\Servers\ProxmoxVps\Core\Traits\OutputBuffer;
+    use \ModulesGarden\Servers\ProxmoxVps\Core\Traits\IsAdmin;
+    use \ModulesGarden\Servers\ProxmoxVps\Core\UI\Traits\RequestObjectHandler;
+    use \ModulesGarden\Servers\ProxmoxVps\Core\Traits\Template;
+
+    protected $response = null;
+
+    /**
+     * @var null|HttpController
+     */
+    protected $pageController = null;
+
+    public function __construct($response = null)
+    {
+        $this->setResponse($response);
+
+        $this->loadSmarty();
+    }
+
+    /**
+     * @param null $response
+     * @return $this
+     */
+    public function setResponse($response = null)
+    {
+        if ($response)
+        {
+            $this->response = $response;
+        }
+
+        return $this;
+    }
+
+    /**
+     * resolves the response
+     */
+    public function resolve()
+    {
+        if ($this->response instanceof View)
+        {
+            $this->resolveView();
+        }
+
+        if ($this->response instanceof JsonResponse)
+        {
+            $this->resolveJson();
+        }
+        elseif ($this->response instanceof RedirectResponse)
+        {
+            $this->resolveRedirect();
+        }
+        elseif ($this->response instanceof Response)
+        {
+            $this->prepareResponse();
+
+            return $this->resolveResponse();
+        }
+    }
+
+    /**
+     * resolve View object to the processable response
+     */
+    public function resolveView()
+    {
+        /**
+         * @var $this->response \ModulesGarden\Servers\ProxmoxVps\Core\UI\View
+         */
+        $this->response->validateAcl($this->isAdmin());
+
+        $this->response = $this->response->getResponse();
+    }
+
+    public function prepareResponse()
+    {
+        $this->response->setLang($this->lang);
+        $this->response->setTemplateName($this->getTemplateName());
+        $this->response->setTemplateDir($this->getTemplateDir());
+        //$this->smarty->setTemplateDir();
+    }
+
+    /**
+     * resolve \ModulesGarden\Servers\ProxmoxVps\Core\Http\JsonResponse
+     */
+    public function resolveJson()
+    {
+        $this->cleanOutputBuffer();
+        /**
+         * @var \ModulesGarden\Servers\ProxmoxVps\Core\Http\JsonResponse
+         */
+        $this->response->send();
+        die();
+    }
+
+    public function resolveRedirect()
+    {
+        /**
+         * @var \ModulesGarden\Servers\ProxmoxVps\Core\Http\RedirectResponse
+         */
+        die($this->response->send());
+    }
+
+    public function resolveResponse()
+    {
+        return $this->response->getHtmlResponse($this);
+    }
+
+    /**
+     * @param null|HttpController $pageController
+     */
+    public function setPageController($pageController)
+    {
+        $this->pageController = $pageController;
+
+        return $this;
+    }
+
+    /**
+     * @return HttpController|null
+     */
+    public function getPageController()
+    {
+        return $this->pageController;
+    }
+}

+ 103 - 0
core/App/Controllers/Router.php

@@ -0,0 +1,103 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers;
+
+class Router
+{
+    use \ModulesGarden\Servers\ProxmoxVps\Core\Traits\Lang;
+    use \ModulesGarden\Servers\ProxmoxVps\Core\Traits\Smarty;
+    use \ModulesGarden\Servers\ProxmoxVps\Core\Traits\OutputBuffer;
+    use \ModulesGarden\Servers\ProxmoxVps\Core\Traits\IsAdmin;
+    use \ModulesGarden\Servers\ProxmoxVps\Core\UI\Traits\RequestObjectHandler;
+
+    const ADMIN = 'admin';
+    const CLIENT = 'client';
+
+    protected $controllerClass = null;
+    protected $controllerMethod = null;
+
+    public function __construct()
+    {
+        $this->isAdmin();
+        $this->loadController();
+    }
+
+    /**
+     * load routing params
+     */
+    public function loadController()
+    {
+        $this->getControllerClass();
+        $this->getControllerMethod();
+    }
+
+    /**
+     * @return string
+     * class name of the controller
+     */
+    public function getControllerClass()
+    {
+        if ($this->controllerClass === null)
+        {
+            $this->controllerClass = '\ModulesGarden\Servers\ProxmoxVps\App\Http\\' . ucfirst($this->getControllerType()) . '\\' . ucfirst($this->getController());
+        }
+
+        return $this->controllerClass;
+    }
+
+    /**
+     * @return string
+     * admin/client context type
+     */
+    public function getControllerType()
+    {
+        return $this->isAdminStatus ? self::ADMIN : self::CLIENT;
+    }
+
+    /**
+     * @return string
+     * get controller name
+     */
+    public function getController()
+    {
+        return filter_var($this->getRequestValue('mg-page', 'Home'), FILTER_SANITIZE_SPECIAL_CHARS);
+    }
+
+    /**
+     * @return string
+     * controller method name
+     */
+    public function getControllerMethod()
+    {
+        if ($this->controllerMethod === null)
+        {
+            $this->controllerMethod = $this->request->get('mg-action', 'index');
+        }
+
+        return $this->controllerMethod;
+    }
+
+    /**
+     * @return bool
+     * determines if controller can be called
+     */
+    public function isControllerCallable()
+    {
+        if (!class_exists($this->controllerClass))
+        {
+            return false;
+        }
+
+        if (!method_exists($this->controllerClass, $this->controllerMethod))
+        {
+            return false;
+        }
+
+        if (!is_callable([$this->controllerClass, $this->controllerMethod]))
+        {
+            return false;
+        }
+
+        return true;
+    }
+}

+ 46 - 0
core/App/ErrorHandler.php

@@ -0,0 +1,46 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App;
+
+class ErrorHandler
+{
+    const ERRORS = [1, 4, 16, 64, 256, 4096];
+    const WARNINGS = [2, 32, 128, 512, 2048];
+    const NOTICES = [8, 1024, 8192, 16384];
+
+    public function __construct()
+    {
+        require_once __DIR__ . DIRECTORY_SEPARATOR . 'LowLevelLog.php';
+    }
+    
+    public function logError($errorToken, $errno, $errstr, $errfile, $errline, $errcontext = null)
+    {
+        $logType = $this->getLogType($errno);
+        $errorTime = date('d.m.Y H:i:s', time());
+        $errorDetails = [
+            'errno' => $errno,
+            'errstr' => $errstr,
+            'errfile' => $errfile,
+            'errline' => $errline,
+            'errcontext' => $logType === 'error' ? $errcontext : null
+        ];
+
+        $log = new LowLevelLog($logType, $errorToken, $errorTime);
+        $log->makeLogs($errorDetails);
+    }
+    
+    public function getLogType($errno = null)
+    {
+        if (in_array($errno, self::WARNINGS))
+        {
+            return 'warning';
+        }
+        
+        if (in_array($errno, self::NOTICES))
+        {
+            return 'notice';
+        }
+        
+        return 'error';
+    }
+}

+ 104 - 0
core/App/Installer/DatabaseInstaller.php

@@ -0,0 +1,104 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Installer;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\FileReader\Reader;
+use Illuminate\Database\Capsule\Manager;
+
+class DatabaseInstaller
+{
+    const STATUS = 'status';
+    const STATUS_SUCCESS = 'success';
+    const STATUS_ERROR = 'error';
+    const RAW_QUERY = 'rawQuery';
+    const ERROR_MESSAGE = 'errorMessage';
+    const FILE = 'file';
+
+    protected $queryResults = [];
+
+    public function performQueryFromFile($file = '')
+    {
+        $queries = $this->getQueries($file);
+
+        array_map(function($query) use ($file)
+        {
+            $this->execute($query, $file);
+        }, $queries);
+    }
+
+    protected function execute(&$query, $file)
+    {
+        try
+        {
+            $pdo = Manager::connection()->getPdo();
+            if (empty($query) === false)
+            {
+                $statement = $pdo->prepare($query);
+                $statement->execute();
+            }
+        }
+        catch (\PDOException $exc)
+        {
+            $this->queryResults[] = [
+                self::STATUS => self::STATUS_ERROR,
+                self::ERROR_MESSAGE => $exc->getMessage(),
+                self::FILE => $file,
+                self::RAW_QUERY => str_replace(PHP_EOL, '<br>', $query)
+            ];
+
+            return null;
+        }
+
+        $this->queryResults[] = [
+            self::STATUS => self::STATUS_SUCCESS,
+            self::FILE => $file,
+            self::RAW_QUERY => $query
+        ];
+    }
+
+    protected function getQueries($file)
+    {
+        return array_filter(explode(';', Reader::read($file)->get()), function ($element) {
+            $tElement = trim($element);
+            if ($element === '' || $tElement === '')
+            {
+                return false;
+            }
+
+            return true;
+        });
+    }
+
+    public function isInstallCorrect()
+    {
+        foreach ($this->queryResults as $result)
+        {
+            if ($result[self::STATUS] === self::STATUS_ERROR)
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    public function getFailedQueries()
+    {
+        $failedList = [];
+
+        foreach ($this->queryResults as $result)
+        {
+            if ($result[self::STATUS] === self::STATUS_ERROR)
+            {
+                $failedList[] = $result;
+            }
+        }
+
+        return $failedList;
+    }
+
+    public function getQueriesResults()
+    {
+        return $this->queryResults;
+    }
+}

+ 76 - 0
core/App/Installer/ModuleInstaller.php

@@ -0,0 +1,76 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Installer;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Packages\PackageManager;
+use ModulesGarden\Servers\ProxmoxVps\Core\DependencyInjection;
+use ModulesGarden\Servers\ProxmoxVps\Core\ModuleConstants;
+
+class ModuleInstaller
+{
+    protected $databaseInstaller = null;
+
+    public function __construct()
+    {
+        $this->databaseInstaller = DependencyInjection::get(DatabaseInstaller::class);
+    }
+
+    public function makeInstall()
+    {
+        $this->installModule();
+        $this->installPackages();
+    }
+
+    public function installModule()
+    {
+        array_map(function ($value){
+            $this->databaseInstaller->performQueryFromFile($value);
+        }, $this->getModuleQueriesPaths());
+    }
+
+    public function getModuleQueriesPaths()
+    {
+        return [
+            ModuleConstants::getFullPath('core', 'Database', 'schema.sql'),
+            ModuleConstants::getFullPath('app', 'Database', 'schema.sql'),
+            ModuleConstants::getFullPath('core', 'Database', 'data.sql'),
+            ModuleConstants::getFullPath('app', 'Database', 'data.sql')
+        ];
+    }
+
+    public function installPackages()
+    {
+        $packageManager = DependencyInjection::get(PackageManager::class);
+
+        array_map(function ($package){
+            $packageName = $package->getName();
+
+            $packageSchemaPath =  ModuleConstants::getFullPath('packages', $packageName, 'Database', 'schema.sql');
+            if (file_exists($packageSchemaPath) && is_readable($packageSchemaPath))
+            {
+                $this->databaseInstaller->performQueryFromFile($packageSchemaPath);
+            }
+
+            $packageDataPath =  ModuleConstants::getFullPath('packages', $packageName, 'Database', 'schema.sql');
+            if (file_exists($packageDataPath) && is_readable($packageDataPath))
+            {
+                $this->databaseInstaller->performQueryFromFile($packageDataPath);
+            }
+        }, $packageManager->getPackagesConfiguration());
+    }
+
+    public function isInstallCorrect()
+    {
+        return $this->databaseInstaller->isInstallCorrect();
+    }
+
+    public function getFailedQueries()
+    {
+        return $this->databaseInstaller->getFailedQueries();
+    }
+
+    public function getQueriesResults()
+    {
+        return $this->databaseInstaller->getQueriesResults();
+    }
+}

+ 91 - 0
core/App/LowLevelLog.php

@@ -0,0 +1,91 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App;
+
+class LowLevelLog
+{
+    protected $logType = null;
+    protected $logToken = null;
+    protected $logTime = null;
+    protected $moduleName = null;
+
+    public function __construct($logType, $logToken, $logTime)
+    {
+        $this->logType = $logType;
+        $this->logToken = $logToken;
+        $this->logTime = $logTime;
+    }
+
+    public function makeLogs($logDetails)
+    {
+        if ($this->logType === 'error')
+        {
+            $this->logToDb($logDetails);
+        }
+        
+        $this->logToFile($logDetails);
+        
+        if ($this->logType === 'error')
+        {
+            $this->logToPHPLog($logDetails);
+        }
+    }
+    
+    public function logToDb($logDetails = [])
+    {
+        \logModuleCall(
+            $this->getModuleName() . ' Error',
+            'Token: ' . $this->logToken,
+            ['time' => $this->logTime],
+            var_export($logDetails, true)
+        );
+    }
+
+    public function logToFile($logDetails)
+    {
+        return;
+        $logData = date('d.m.Y H:i:s', time()) . ' - Token: ' . $this->logToken . ' - ' . var_export($logDetails, true) . PHP_EOL;
+        $logFile = $this->getLogFile($this->logType);
+
+        file_put_contents($logFile, $logData, FILE_APPEND);
+    }
+
+    public function logToPHPLog($logDetails)
+    {
+        
+    }
+
+    public function getLogFile($logType = 'error')
+    {
+        $logDir = dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR . 'storage' . DIRECTORY_SEPARATOR . 'logs';
+        $logFile = $logDir . DIRECTORY_SEPARATOR . $logType . '.log';
+        if (!file_exists($logFile) && !is_writable($logDir))
+        {
+            //throw new \Exception('Insufficient permissions for directory: ' . $logDir);
+        }
+        if (file_exists($logFile) && !is_writable($logFile))
+        {
+            //throw new \Exception('Insufficient permissions for file: ' . $logFile);
+        }
+
+        return $logFile;
+    }
+
+    public function getModuleName()
+    {
+        if (!$this->moduleName)
+        {
+            $className = trim(self::class, '\\');
+            if (strpos($className, 'ModulesGarden') === 0)
+            {
+                $pt1 = str_replace('ModulesGarden\\', '', $className);
+                if (strpos($pt1, '\Core\App'))
+                {
+                    $this->moduleName = substr($pt1, 0, strpos($pt1, '\Core\App'));
+                }
+            }
+        }
+
+        return $this->moduleName;
+    }
+}

+ 39 - 0
core/App/Packages/AppPackageConfiguration.php

@@ -0,0 +1,39 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Packages;
+
+
+use ModulesGarden\Servers\ProxmoxVps\Packages\WhmcsService\Config\Enum;
+
+abstract class AppPackageConfiguration
+{
+    const PACKAGE_STATUS = 'packageStatus';
+    const PACKAGE_STATUS_ACTIVE = 'active';
+    const PACKAGE_STATUS_INACTIVE = 'inactive';
+
+    const APP_CONFIGURATION = [];
+
+    public function getSuboptionsByCallback($optName = null)
+    {
+
+        $optName = preg_replace('/\s+/', '', $optName);
+        $fullOptName = $optName . 'GetSubOptions';
+        if (method_exists($this, $fullOptName))
+        {
+            return $this->{$fullOptName}();
+        }
+
+        return false;
+    }
+
+    public function getConfigurableOptionsList()
+    {
+        if (method_exists($this, 'getConfigurableOptions'))
+        {
+            return $this->getConfigurableOptions();
+        }
+
+        return $this::APP_CONFIGURATION[Enum::CONFIGURABLE_OPTIONS];
+    }
+}
+

+ 88 - 0
core/App/Packages/BasePackageConfiguration.php

@@ -0,0 +1,88 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Packages;
+
+abstract class BasePackageConfiguration
+{
+    protected $configuration = null;
+    protected $appConfigFound = false;
+    protected $appConfigInstance = null;
+
+
+    static $protectedConfigOptions = [
+        PackageConfigurationConst::VERSION,
+        PackageConfigurationConst::PACKAGE_NAME
+    ];
+
+    public function __get($key)
+    {
+        $this->loadConfiguration();
+
+        if(isset($this->configuration[$key]))
+        {
+            return $this->configuration[$key];
+        }
+
+        return null;
+    }
+
+    public function getConfig()
+    {
+        $this->loadConfiguration();
+
+        return $this->configuration;
+    }
+
+    public function getName()
+    {
+        $this->loadConfiguration();
+
+        return $this->configuration[PackageConfigurationConst::PACKAGE_NAME];
+    }
+
+    public function loadConfiguration($forceReload = false)
+    {
+        if (!($this->configuration === null || $forceReload))
+        {
+            return;
+        }
+
+        $config = $this::CONFIGURATION;
+        $packageName = $config[PackageConfigurationConst::PACKAGE_NAME];
+
+        $appPackageConfig = $this->getAppPackageConfig($packageName);
+
+        $merged = array_merge($config, $appPackageConfig);
+        foreach (self::$protectedConfigOptions as $protectedOption)
+        {
+            $merged[$protectedOption] = $config[$protectedOption];
+        }
+
+        $this->configuration = $merged;
+    }
+
+    public function getAppPackageConfig($packageName = null)
+    {
+        $appConfigClassName = '\ModulesGarden\Servers\ProxmoxVps\App\Config\Packages\\' . $packageName;
+        if (!class_exists($appConfigClassName) || !is_subclass_of($appConfigClassName, AppPackageConfiguration::class)
+            || !defined($appConfigClassName . '::APP_CONFIGURATION'))
+        {
+
+            return [];
+        }
+
+        $this->appConfigFound = true;
+        $this->appConfigInstance = new $appConfigClassName();
+
+        return $appConfigClassName::APP_CONFIGURATION;
+    }
+
+    /**
+     * @return null
+     */
+    public function getAppConfigInstance()
+    {
+        return $this->appConfigInstance;
+    }
+
+}

+ 9 - 0
core/App/Packages/PackageConfigurationConst.php

@@ -0,0 +1,9 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Packages;
+
+class PackageConfigurationConst
+{
+    const VERSION = 'version';
+    const PACKAGE_NAME = 'packageName';
+}

+ 103 - 0
core/App/Packages/PackageManager.php

@@ -0,0 +1,103 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Packages;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\FileReader\Directory;
+use ModulesGarden\Servers\ProxmoxVps\Core\ModuleConstants;
+
+class PackageManager
+{
+    const STATUS_ACTIVE = 'active';
+    const STATUS_INACTIVE = 'inactive';
+
+    const STATUS_REASON_INACTIVE = 'Inactive in the configuration';
+    const STATUS_REASON_CONFIG_MISSING = 'Inactive because of lack of the configuration file';
+
+    protected $packageList = [];
+
+    public function __construct()
+    {
+        $this->loadPackages();
+    }
+
+    public function getPackageConfiguration($packageName)
+    {
+        if (isset($this->packageList[$packageName]))
+        {
+            return $this->packageList[$packageName];
+        }
+
+        return null;
+    }
+
+    public function getPackagesConfiguration()
+    {
+        return $this->packageList;
+    }
+
+    protected function loadPackages()
+    {
+        $packageList = $this->getPackageListByDirectory();
+        foreach ($packageList as $className)
+        {
+            $config = new $className();
+            $packageName = $config->getName();
+
+            if ($this->isNameValid($packageName) && $this->isVersionValid($config->{PackageConfigurationConst::VERSION}) && $this->isStatusValid($config->{AppPackageConfiguration::PACKAGE_STATUS}))
+            {
+                $this->packageList[$packageName] = $config;
+            }
+        }
+    }
+
+    public function getPackageListByDirectory()
+    {
+        $directoryHelper = new Directory();
+
+        $packagesDirectory = ModuleConstants::getModuleRootDir() . DIRECTORY_SEPARATOR . 'packages';
+
+        $packagesList = $directoryHelper->getFilesList($packagesDirectory);
+
+        $existing = [];
+        foreach ($packagesList as $packageName)
+        {
+            $className = '\ModulesGarden\Servers\ProxmoxVps\Packages\\' . $packageName . '\Config\PackageConfiguration';
+            if (class_exists($className) && is_subclass_of($className, BasePackageConfiguration::class))
+            {
+                $existing[] = $className;
+            }
+        }
+
+        return $existing;
+    }
+
+    public function isNameValid($name = null)
+    {
+        if(trim($name) === '' || !is_string($name))
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+    public function isVersionValid($version = null)
+    {
+        if(trim($version) === '' || !is_string($version))
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+    public function isStatusValid($status = null)
+    {
+        if(!in_array($status, [AppPackageConfiguration::PACKAGE_STATUS_ACTIVE, AppPackageConfiguration::PACKAGE_STATUS_INACTIVE]))
+        {
+            return false;
+        }
+
+        return true;
+    }
+}

+ 96 - 0
core/App/Requirements/Checker.php

@@ -0,0 +1,96 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Requirements;
+
+/**
+ * Description of Handler
+ *
+ * @author INBSX-37H
+ */
+class Checker
+{
+    /** 
+     * \ModulesGarden\Servers\ProxmoxVps\Core\FileReader\PathValidator
+     * @var type null|\ModulesGarden\Servers\ProxmoxVps\Core\FileReader\|\ModulesGarden\Servers\ProxmoxVps\Core\FileReader\Directory
+     */
+    protected $directoryHandler = null;
+    
+    protected $requirementsList = [];
+    
+    protected $checkResaults = [];
+    
+    /** 
+     * Paths for Requirements class to be placed in
+     * @var type array
+     */
+    const PATHS = [
+        'app' . DIRECTORY_SEPARATOR . 'Configuration' . DIRECTORY_SEPARATOR . 'Requirements',
+        'core' . DIRECTORY_SEPARATOR . 'Configuration' . DIRECTORY_SEPARATOR . 'Requirements'
+    ];
+ 
+    public function __construct()
+    {
+        $this->directoryHandler = new \ModulesGarden\Servers\ProxmoxVps\Core\FileReader\Directory();
+
+        $this->loadRequirements();
+        
+        $this->checkRequirements();
+    }
+    
+    protected function loadRequirements()
+    {
+        foreach (self::PATHS as $path)
+        {
+            $this->loadClassesByPath($path);
+        }
+    }
+    
+    protected function loadClassesByPath($path)
+    {
+        $fullPath = \ModulesGarden\Servers\ProxmoxVps\Core\ModuleConstants::getModuleRootDir() . DIRECTORY_SEPARATOR . $path;
+        $files = $this->directoryHandler->getFilesList($fullPath, '.php', true);
+        $classNamespace = $this->getClassNamespaceByPath($path);
+        foreach ($files as $file)
+        {
+            $className = $classNamespace . $file;
+            if (!class_exists($className) || !is_subclass_of($className, RequirementInterface::class))
+            {
+                continue;
+            }
+            
+            $this->requirementsList[] = $className;
+        }
+    }
+    
+    protected function getClassNamespaceByPath($path)
+    {
+        $contextParts = explode('\\', self::class);
+        $coreParts = explode(DIRECTORY_SEPARATOR, $path);
+
+        $mergeArray = in_array($contextParts[1], ['Servers', 'Registrars'])
+            ? [$contextParts[0], $contextParts[1], $contextParts[2]] : [$contextParts[0], $contextParts[1]];
+
+        $allParts = array_merge($mergeArray, $coreParts);
+        array_walk($allParts, function(&$item){
+            $item = ucfirst($item);
+        });
+        
+        return '\\' . implode('\\', $allParts) . '\\';
+    }
+    
+    protected function checkRequirements()
+    {
+        foreach ($this->requirementsList as $requirement)
+        {
+            $instance = \ModulesGarden\Servers\ProxmoxVps\Core\DependencyInjection\DependencyInjection::call($requirement);
+            $handler = $instance->getHandlerInstance();
+            
+            $this->checkResaults = array_merge($this->checkResaults, $handler->getUnfulfilledRequirements());
+        }
+    }
+    
+    public function getUnfulfilledRequirements()
+    {
+        return $this->checkResaults;
+    }
+}

+ 35 - 0
core/App/Requirements/Handler.php

@@ -0,0 +1,35 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Requirements;
+
+/**
+ * Description of Handler
+ *
+ * @author INBSX-37H
+ */
+abstract class Handler
+{
+    use \ModulesGarden\Servers\ProxmoxVps\Core\Traits\Lang;
+
+    protected $unfulfilledRequirements = [];
+
+    protected function addUnfulfilledRequirement($message = null, $params = [])
+    {
+        if ($message)
+        {
+            $this->loadLang();
+            $translated = $this->lang->absoluteTranslate('unfulfilledRequirement', $message);
+            foreach ($params as $searchKey => $searchValue)
+            {
+                $translated = str_replace(':' . (string)$searchKey . ':', (string)$searchValue, $translated);
+            }
+
+            $this->unfulfilledRequirements[] = $translated;
+        }
+    }
+
+    public function getUnfulfilledRequirements()
+    {
+        return $this->unfulfilledRequirements;
+    }
+}

+ 13 - 0
core/App/Requirements/HandlerInterface.php

@@ -0,0 +1,13 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Requirements;
+
+/**
+ * Description of RequirementInterface
+ *
+ * @author INBSX-37H
+ */
+interface HandlerInterface
+{
+    public function handleRequirements();
+}

+ 49 - 0
core/App/Requirements/Handlers/Classes.php

@@ -0,0 +1,49 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Requirements\Handlers;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Requirements\Handler;
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Requirements\Instances\Classes as ClassesInstance;
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Requirements\HandlerInterface;
+
+/**
+ * Description of Files
+ *
+ * @author INBSX-37H
+ */
+class Classes extends Handler implements HandlerInterface
+{
+    protected $classList = [];
+
+    public function __construct(array $classList = [])
+    {
+        $this->classList = $classList;
+        
+        $this->handleRequirements();
+    }
+
+    public function handleRequirements()
+    {
+        foreach ($this->classList as $record)
+        {
+            $this->handleRequirement($record);
+        }
+    }
+
+    protected function handleRequirement($record)
+    {
+        $className = $record[ClassesInstance::CLASS_NAME];
+        if ($className[0] !== '\\')
+        {
+            $className = '\\' . $className;
+        }
+
+        if (class_exists($className))
+        {
+            return null;
+        }
+
+        $this->addUnfulfilledRequirement('In order for the module to work correctly, it requires the :class_name: class.',
+            ['class_name' => $className]);
+    }
+}

+ 114 - 0
core/App/Requirements/Handlers/Files.php

@@ -0,0 +1,114 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Requirements\Handlers;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Requirements\Handler;
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Requirements\HandlerInterface;
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Requirements\Instances\Files as FilesInstance;
+
+/**
+ * Description of Files
+ *
+ * @author INBSX-37H
+ */
+class Files extends Handler implements HandlerInterface
+{
+    use \ModulesGarden\Servers\ProxmoxVps\Core\Traits\Lang;
+    
+    protected $fileList = [];
+
+    public function __construct(array $fileList = [])
+    {
+        $this->fileList = $fileList;
+        
+        $this->handleRequirements();
+    }
+
+    public function handleRequirements()
+    {
+        foreach ($this->fileList as $record)
+        {
+            if (!$this->isValidPath($record[FilesInstance::PATH]))
+            {
+                continue;
+            }
+
+            $this->handleRequirement($record);
+        }
+    }
+    
+    public function isValidPath($path)
+    {
+        if (stripos($path, FilesInstance::WHMCS_PATH) === 0
+            || stripos($path, FilesInstance::MODULE_PATH) === 0)
+        {
+            return true;
+        }
+        
+        return false;
+    }
+    
+    protected function handleRequirement($record)
+    {
+        $filePath = $this->getFullPath($record[FilesInstance::PATH]);
+
+        switch ($record[FilesInstance::TYPE])
+        {
+            case FilesInstance::REMOVE:
+                $this->removeFile($filePath);
+                break;
+            case FilesInstance::IS_WRITABLE:
+                $this->checkIfWritable($filePath);
+                break;
+        }
+        
+    }
+    
+    public function getFullPath($recordPath = null)
+    {
+        if (stripos($recordPath, FilesInstance::WHMCS_PATH) === 0)
+        {
+            return str_replace(FilesInstance::WHMCS_PATH, \ModulesGarden\Servers\ProxmoxVps\Core\ModuleConstants::getFullPathWhmcs(),
+                    str_replace('/', DIRECTORY_SEPARATOR, $recordPath));
+        }
+
+        if (stripos($recordPath, FilesInstance::MODULE_PATH) === 0)
+        {
+            return str_replace(FilesInstance::MODULE_PATH, \ModulesGarden\Servers\ProxmoxVps\Core\ModuleConstants::getModuleRootDir(),
+                    str_replace('/', DIRECTORY_SEPARATOR, $recordPath));
+        }
+
+        return null;
+    }
+    
+    protected function removeFile($filePath = null)
+    {
+        $fileValidator = new \ModulesGarden\Servers\ProxmoxVps\Core\FileReader\PathValidator();
+        if (!$fileValidator->pathExists($filePath))
+        {
+            return null;
+        }
+        
+        unlink($filePath);
+        
+        if (!$fileValidator->pathExists($filePath))
+        {
+            return null;
+        }
+
+        $this->addUnfulfilledRequirement('In order for the module to work correctly, please remove the following file: :remove_file_requirement:',
+                ['remove_file_requirement' => $filePath]);
+    }
+
+    protected function checkIfWritable($filePath = null)
+    {
+        $fileValidator = new \ModulesGarden\Servers\ProxmoxVps\Core\FileReader\PathValidator();
+        if ($fileValidator->isPathWritable($filePath))
+        {
+            return null;
+        }
+
+        $this->addUnfulfilledRequirement('In order for the module to work correctly, please set up permissions to the :writable_file_requirement: directory as writable.',
+            ['writable_file_requirement' => $filePath]);
+    }
+}

+ 47 - 0
core/App/Requirements/Handlers/PhpExtensions.php

@@ -0,0 +1,47 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Requirements\Handlers;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Requirements\Handler;
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Requirements\HandlerInterface;
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Requirements\Instances\PhpExtensions as PhpExtensionsInstance;
+
+/**
+ * Description of PhpExtensions
+ *
+ * @author INBSX-37H
+ */
+class PhpExtensions extends Handler implements HandlerInterface
+{
+    use \ModulesGarden\Servers\ProxmoxVps\Core\Traits\Lang;
+    
+    protected $extensionsList = [];
+
+    public function __construct(array $classList = [])
+    {
+        $this->extensionsList = $classList;
+        
+        $this->handleRequirements();
+    }
+
+    public function handleRequirements()
+    {
+        foreach ($this->extensionsList as $record)
+        {
+            $this->handleRequirement($record);
+        }
+    }
+
+    protected function handleRequirement($record)
+    {
+        $extension = $record[PhpExtensionsInstance::EXTENSION_NAME];
+
+        if (extension_loaded($extension))
+        {
+            return null;
+        }
+
+        $this->addUnfulfilledRequirement('In order for the module to work correctly, it requires the :extension_name: PHP extension to be installed.',
+            ['extension_name' => $extension]);
+    }
+}

+ 20 - 0
core/App/Requirements/Instances/Classes.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Requirements\Instances;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Requirements\RequirementsList;
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Requirements\RequirementInterface;
+/**
+ * Description of Classes
+ *
+ * @author INBSX-37H
+ */
+abstract class Classes extends RequirementsList implements RequirementInterface
+{
+    const CLASS_NAME = 'className';
+
+    final public function getHandler()
+    {
+        return \ModulesGarden\Servers\ProxmoxVps\Core\App\Requirements\Handlers\Classes::class;
+    }
+}

+ 30 - 0
core/App/Requirements/Instances/Files.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Requirements\Instances;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Requirements\RequirementsList;
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Requirements\RequirementInterface;
+
+/**
+ * Description of Files
+ *
+ * @author INBSX-37H
+ */
+abstract class Files extends RequirementsList implements RequirementInterface
+{
+    const WHMCS_PATH = ':WHMCS_PATH:';
+    const MODULE_PATH = ':MODULE_PATH:';    
+    
+    const PATH = 'path';
+    const TYPE = 'type';
+    
+    const REMOVE = 'remove';
+    const EXISTS = 'exists';
+    const IS_WRITABLE = 'isWritable';
+    const IS_READABLE = 'isReadable';
+
+    final public function getHandler()
+    {
+        return \ModulesGarden\Servers\ProxmoxVps\Core\App\Requirements\Handlers\Files::class;
+    }
+}

+ 21 - 0
core/App/Requirements/Instances/PhpExtensions.php

@@ -0,0 +1,21 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Requirements\Instances;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Requirements\RequirementsList;
+use ModulesGarden\Servers\ProxmoxVps\Core\App\Requirements\RequirementInterface;
+
+/**
+ * Description of PhpExtensions
+ *
+ * @author INBSX-37H
+ */
+abstract class PhpExtensions extends RequirementsList implements RequirementInterface
+{
+    const EXTENSION_NAME = 'extensionName';
+
+    final public function getHandler()
+    {
+        return \ModulesGarden\Servers\ProxmoxVps\Core\App\Requirements\Handlers\PhpExtensions::class;
+    }
+}

+ 13 - 0
core/App/Requirements/RequirementInterface.php

@@ -0,0 +1,13 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Requirements;
+
+/**
+ * Description of RequirementInterface
+ *
+ * @author INBSX-37H
+ */
+interface RequirementInterface
+{
+
+}

+ 26 - 0
core/App/Requirements/RequirementsList.php

@@ -0,0 +1,26 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App\Requirements;
+
+/**
+ * Description of Requirements
+ *
+ * @author INBSX-37H
+ */
+abstract class RequirementsList
+{
+    protected $requirementsList = [];
+
+    public function getHandlerInstance()
+    {
+        $handler = $this->getHandler();
+        if (!class_exists($handler))
+        {
+            return null;
+        }
+
+        return new $handler($this->requirementsList);
+    }
+
+    abstract function getHandler();
+}

+ 64 - 0
core/App/TemplateDisplayWrapper.php

@@ -0,0 +1,64 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\App;
+
+use \ModulesGarden\Servers\ProxmoxVps\Core\ServiceLocator;
+
+/**
+ * Template Display Wrapper
+ *
+ * @author slawomir@modulesgarden.com
+ */
+class TemplateDisplayWrapper
+{
+    use \ModulesGarden\Servers\ProxmoxVps\Core\Traits\Lang;
+    
+    protected $templateName = null;
+    protected $templateDir = null;
+    protected $vars = [];
+
+
+    public function __construct($templateName = null, $templateDir = null, $vars = [], $lang = null)
+    {
+        $this->setTemplate($templateName, $templateDir);
+        $this->setVars($vars);
+        $this->setLang($lang);
+    }
+    
+    public function toHtml()
+    {
+            $pageContent = ServiceLocator::call('smarty')
+                ->setLang($this->lang)
+                ->setTemplateDir($path)
+                ->view($fileName, $vars);
+
+            return $pageContent;        
+    }
+    
+    public function setTemplate($templateName = null, $templateDir = null)
+    {
+        if (file_exists($templateDir . DIRECTORY_SEPARATOR . $templateName . '.tpl'))
+        {
+            $this->templateName = $templateName;
+            $this->templateDir = $templateDir;
+        }
+    }
+    
+    public function setVars($vars = [])
+    {
+        if (is_array($vars))
+        {
+            $this->vars = $vars;
+        }
+    }
+    
+    public function setLang($lang = null)
+    {
+        if ($lang instanceof \ModulesGarden\Servers\ProxmoxVps\Core\Lang)
+        {
+            $this->lang = $lang;
+        }
+        
+        $this->loadLang();
+    }
+}

+ 56 - 0
core/Bootstrap.php

@@ -0,0 +1,56 @@
+<?php
+
+use \ModulesGarden\Servers\ProxmoxVps\Core\ModuleConstants;
+use \ModulesGarden\Servers\ProxmoxVps\Core\ServiceLocator;
+use \ModulesGarden\Servers\ProxmoxVps\Core\FileReader\PathValidator;
+use \ModulesGarden\Servers\ProxmoxVps\Core\FileReader\File;
+use \ModulesGarden\Servers\ProxmoxVps\Core\DependencyInjection\Builder;
+use \ModulesGarden\Servers\ProxmoxVps\Core\DependencyInjection\Services;
+
+if (!defined('DS')) define('DS', DIRECTORY_SEPARATOR);
+if (!defined('PS')) define('PS', PATH_SEPARATOR);
+if (!defined('CRLF')) define('CRLF', "\r\n");
+
+require_once dirname(__DIR__) . DS . "vendor" . DS . "autoload.php";
+
+/**
+ * Initialize base values
+ */
+ModuleConstants::initialize();
+
+/**
+ * Initailize DI builder
+ */
+new Builder();
+
+/**
+ * Initialize Services
+ */
+new Services();
+
+/**
+ * Check file permission
+ */
+if (is_dir(ModuleConstants::getFullPath('storage')) === false 
+        || is_writable(ModuleConstants::getFullPath('storage')) === false
+        || is_writable(ModuleConstants::getFullPath('storage', 'app')) === false
+        || is_writable(ModuleConstants::getFullPath('storage', 'crons')) === false
+        || is_writable(ModuleConstants::getFullPath('storage', 'logs')) === false)
+{
+    File::createPaths(
+            ['full' => ModuleConstants::getFullPath('storage'),              'permission' => 0777],
+            ['full' => ModuleConstants::getFullPath('storage', 'app'),       'permission' => 0777],
+            ['full' => ModuleConstants::getFullPath('storage', 'crons'),     'permission' => 0777],
+            ['full' => ModuleConstants::getFullPath('storage', 'logs'),      'permission' => 0777]
+    );
+}
+
+$pathValidator = new PathValidator();
+if (!$pathValidator->validatePath(ModuleConstants::getFullPath('storage', 'logs'), true, true, true))
+{
+    ServiceLocator::call('errorManager')->addError(
+        'Bootstrap',
+        PHP_EOL . ServiceLocator::call('lang')->absoluteT('permissionsStorage'),
+        ['path' => ModuleConstants::getFullPath('storage')]
+    );
+}

+ 209 - 0
core/Cache/CacheManager.php

@@ -0,0 +1,209 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\Cache;
+
+use Symfony\Component\Cache\Simple\FilesystemCache;
+use ModulesGarden\Servers\ProxmoxVps\Core\ModuleConstants;
+use ModulesGarden\Servers\ProxmoxVps\Core\Interfaces\CacheManagerInterface;
+
+/**
+ * Description of CacheManager
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class CacheManager implements CacheManagerInterface
+{
+    protected static $instance = null;
+
+    /**
+     * @var CacheManagerInterface
+     */
+    protected $manager;
+    
+    /**
+     * @var string
+     */
+    protected $dir = '';
+    
+    /**
+     * @var string
+     */
+    protected $namespace = '';
+    
+    /**
+     * @var string
+     */
+    protected $key;
+    
+    /**
+     * @var string|array|object
+     */
+    protected $data;
+
+    public function __construct()
+    {
+        $this->namespace = ModuleConstants::getRootNamespace();
+        $this->dir = ModuleConstants::getModuleRootDir() . DS . 'storage' . DS . 'framework';
+        $this->manager = new FilesystemCache('', 0, $this->dir);
+    }
+    
+    private function __clone()
+    {
+        
+    }
+
+
+    /**
+     * @param string $key
+     * @return $this
+     * @throws \ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Exceptions\MGModuleException
+     */
+    public function setKey($key = 'default')
+    {
+        try
+        {
+            $this->key = $key;
+            $this->setData($this->manager->get($this->key));
+        }
+        catch (\Exception $ex)
+        {
+            throw new \ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Exceptions\MGModuleException(self::class, $ex->getMessage(), $ex->getCode(), $ex);
+        }
+        
+        
+        return $this;
+    }
+    
+    /**
+     * @return string
+     */
+    public function getKey()
+    {
+        return $this->key;
+    }
+    
+    /**
+     * @param mixed $data
+     * @return $this
+     */
+    public function setData($data = null)
+    {
+        if ($data !== null)
+        {
+            $this->data = $data;
+        }
+        
+        return $this;
+    }
+    
+    /**
+     * @return mixed
+     * @throws \ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Exceptions\MGModuleException
+     */
+    public function getData()
+    {
+        try
+        {
+            if (isset($this->key))
+            {
+                $this->data = $this->manager->get($this->key);
+            }
+            return $this->data;
+        }
+        catch (\Exception $ex)
+        {
+            throw new \ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Exceptions\MGModuleException(self::class, $ex->getMessage(), $ex->getCode(), $ex);
+        }
+        
+    }
+    
+    /**
+     * @return $this
+     * @throws \ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Exceptions\MGModuleException
+     */
+    public function save()
+    {
+        try
+        {
+            $this->manager->set($this->key, $this->data);
+        }
+        catch (\Exception $ex)
+        {
+            throw new \ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Exceptions\MGModuleException(self::class, $ex->getMessage(), $ex->getCode(), $ex);
+        }
+        return $this;
+    }
+    
+    /**
+     * @return $this
+     * @throws \ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Exceptions\MGModuleException
+     */
+    public function remove()
+    {
+        try
+        {
+            $this->manager->delete($this->key);
+        }
+        catch (\Exception $ex)
+        {
+            throw new \ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Exceptions\MGModuleException(self::class, $ex->getMessage(), $ex->getCode(), $ex);
+        }
+        return $this;
+    }
+    
+    /**
+     * @return $this
+     * @throws \ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Exceptions\MGModuleException
+     */
+    public function clearAll()
+    {
+        try
+        {
+            $this->manager->clear();
+        }
+        catch (\Exception $ex)
+        {
+            throw new \ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Exceptions\MGModuleException(self::class, $ex->getMessage(), $ex->getCode(), $ex);
+        }
+        return $this;
+    }
+    
+    /**
+     * @return type
+     * @throws \ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Exceptions\MGModuleException
+     */
+    public function exist()
+    {
+        try
+        {
+            return $this->manager->has($this->key);
+        }
+        catch (\Exception $ex)
+        {
+            throw new \ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Exceptions\MGModuleException(self::class, $ex->getMessage(), $ex->getCode(), $ex);
+        }
+    }
+
+    /**
+     * @return CacheManager
+     */
+    public static function instance()
+    {
+        if (CacheManager::$instance === null)
+        {
+            CacheManager::$instance = new CacheManager();
+        }
+        return CacheManager::$instance;
+    }
+    
+    public static function cache($key = null)
+    {
+        $istance = self::instance();
+        if ($key)
+        {
+            $istance->setKey($key);
+        }
+
+        return $istance;
+    }
+}

+ 107 - 0
core/CommandLine/AbstractCommand.php

@@ -0,0 +1,107 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\CommandLine;
+
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
+
+/**
+ * Class Command
+ * @package ModulesGarden\Servers\ProxmoxVps\Core\CommandLine
+ */
+class AbstractCommand extends \Symfony\Component\Console\Command\Command
+{
+    /**
+     * Command name
+     * @var string
+     */
+    protected $name         = null;
+
+    /**
+     * Command description
+     * @var string
+     */
+    protected $description  = '';
+
+    /**
+     * Command help text. Use --help to show
+     * @var string
+     */
+    protected $help         = '';
+
+    /**
+     * minimal command configuration
+     */
+    protected function configure()
+    {
+        $this
+            ->setName($this->name)
+            ->setDescription($this->description)
+            ->setHelp($this->help)
+            ->addOption('force', 'f', InputOption::VALUE_OPTIONAL, 'Force script to run, without checking if another instance is running', false);
+
+        $this->setup();
+    }
+
+    /**
+     * Execute command
+     * @param InputInterface $input
+     * @param OutputInterface $output
+     */
+    protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        try
+        {
+            $this->beforeProcess($input, $output);
+
+            $this->process($input, $output, new SymfonyStyle($input, $output));
+
+            $this->afterProcess($input, $output);
+        }
+        catch(\Exception $ex)
+        {
+            (new SymfonyStyle($input, $output))->error($ex->getMessage());
+        }
+
+        return 0;
+    }
+
+    /**
+     * Add some custom actions here based on documentation  https://symfony.com/doc/current/console.html
+     */
+    protected function setup()
+    {
+
+    }
+
+    /**
+     * @param InputInterface $input
+     * @param OutputInterface $output
+     * @param SymfonyStyle $io
+     */
+    protected function process(InputInterface $input, OutputInterface $output, SymfonyStyle $io)
+    {
+
+    }
+
+    /**
+     * Function will be called before executing "process" function
+     * @throws \Exception
+     */
+    protected function beforeProcess(InputInterface $input, OutputInterface $output)
+    {
+
+    }
+
+    /**
+     * Function will be called after executing "process" function
+     * @param InputInterface $input
+     * @param OutputInterface $output
+     */
+    protected function afterProcess(InputInterface $input, OutputInterface $output)
+    {
+
+    }
+}

+ 43 - 0
core/CommandLine/AbstractCronController.php

@@ -0,0 +1,43 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\CommandLine;
+
+/**
+ * Description of AbstractCronController
+ *
+ * @author Rafał
+ */
+if (class_exists(\Thread::class))
+{
+    class AbstractCronController extends \Thread
+    {
+        protected $className;
+        protected $cronManager;
+
+        public function setCronManager($cronManager)
+        {
+            $this->cronManager = $cronManager;
+
+            return $this;
+        }
+
+        public function setClassName($className)
+        {
+            $this->className = $className;
+
+            return $this;
+        }
+
+        protected function updatePid()
+        {
+            CronManager::updatePids($this->className);
+        }
+    }
+}
+else
+{
+    class AbstractCronController
+    {
+        
+    }
+}

+ 218 - 0
core/CommandLine/AbstractCronControllerWithoutThread.php

@@ -0,0 +1,218 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\CommandLine;
+
+use \ModulesGarden\Servers\ProxmoxVps\Core\ModuleConstants;
+use \ModulesGarden\Servers\ProxmoxVps\Core\Models\CronTabs;
+
+/**
+ * Description of AbstractCronController
+ *
+ * @author Rafał
+ */
+abstract class AbstractCronControllerWithoutThread
+{
+    protected $exit = true;
+    protected $error = false;
+    protected $isChild = false;
+    protected $className;
+    protected $child = 0;
+    protected $childId;
+    protected $parentId;
+    protected $cronManager;   
+    protected $parentUserId;
+    protected $parentGroupId; 
+
+    public function setParentId($parentId)
+    {
+        $this->parentId = $parentId;
+
+        return $this;
+    }
+
+    public function setChildId($childId)
+    {
+        $this->childId = $childId;
+
+        return $this;
+    }
+
+    public function ischild($isChild)
+    {
+        $this->isChild = $isChild;
+
+        return $this;
+    }
+
+    public function setClassName($className)
+    {
+        $this->className = $className;
+
+        return $this;
+    }
+    
+    protected function canRunScript()
+    {
+        $run = true;
+        foreach (CronTabs::get() as $cronTab)
+        {
+            if ($cronTab->name == CronTabs::DEFAULT_CRON_MANAGER_NAME && $cronTab->status == 'stop')
+            {
+                $run = false;
+            }
+            elseif ($cronTab->name == $this->className && $cronTab->status == 'stop')
+            {
+                $run = false;
+            }
+        }
+        
+        return $run;
+    }
+
+    protected function updatePid()
+    {
+        if ($this->isChild)
+        {
+            CronManager::updatePids($this->className, $this->childId);
+            if ($this->parentGroupId === getmygid() && $this->parentUserId === getmyuid())
+            {
+                $this->removePid();
+            }
+        }
+
+        return $this;
+    }
+    
+    protected function isExistPid()
+    {
+        if ($this->isChild)
+        {
+            return CronManager::existPids($this->className, $this->childId);
+        }
+        
+        return $this->canRunScript();
+    }
+
+    protected function removePid()
+    {
+        if ($this->isChild)
+        {
+            CronManager::removePids($this->className, $this->childId);
+        }
+        
+        return $this;
+    }
+
+    abstract public function run();
+
+    public function isChildrenCreate()
+    {
+        return false;
+    }
+
+    public function getChildrenCount()
+    {
+        return $this->child;
+    }
+
+    public function setCronManager($cronManager)
+    {
+        $this->cronManager = $cronManager;
+
+        return $this;
+    }
+    
+    public function getIndexElements()
+    {
+        $childrenListIds = [];
+        
+        for ($key = 1; $key <= $this->getChildrenCount(); $key++)
+        {
+            $childrenListIds[] = $key;
+        }
+        
+        return $childrenListIds;
+    }
+
+    public function start()
+    {
+        try{
+            if ($this->isStart() === false)
+            {
+                if ($this->child > 0 && $this->isChild === false)
+                {
+                    while ($this->canRunScript())
+                    {
+                        if ($this->isChildrenCreate())
+                        {
+                            $parentId = getmypid();
+                            $parentUId = $this->parentUserId ? $this->parentUserId : getmyuid();
+                            $parentGId = $this->parentGroupId ? $this->parentGroupId : getmygid();
+                            foreach ($this->getIndexElements() as $key)
+                            {
+                                if ($this->cronManager->isChildRunning($this->className, $key))
+                                {
+                                    continue;
+                                }
+
+                                $phpInterpreter       = \PHP_BINARY ?: 'php';
+                                $internalCronDumpFile = ModuleConstants::getFullPath('storage', 'crons', 'cronLog');
+                                exec($phpInterpreter . " " . ModuleConstants::getModuleRootDir() . DS . 'cron' . DS . 'cron.php ' . $this->className
+                                        . " --parent {$parentId} --parentuid {$parentUId} --parentgid {$parentGId} --child {$key} >> {$internalCronDumpFile} &");
+                            }
+                        }
+                        $this->wait(4000000);
+                    }
+                }
+                elseif ($this->child === 0 && $this->isChild === false)
+                {
+                    $this->exit = false;
+                    $this->run();
+                }
+                elseif ($this->isChild === true)
+                {
+                    $this->exit = false;
+                    $this->run();
+                    $this->removePid();
+                    exit;
+                }
+            }
+        } 
+        catch (\Exception $ex) 
+        {
+            $this->error = $ex->getMessage();
+        }
+    }    
+    
+    public function setParentGroupId($parentGroupId)
+    {
+        $this->parentGroupId = $parentGroupId;
+        
+        return $this;
+    }
+    
+    public function setParentUserId($parentUserId)
+    {
+        $this->parentUserId = $parentUserId;
+        
+        return $this;
+    }
+
+    public function isStart()
+    {
+        return ($this->exit === false);
+    }
+
+    public function wait($seconds = 500000)
+    {
+        usleep($seconds);
+    }
+
+    function __destruct()
+    {
+        if ($this->error)
+        {
+            CronTabs::ifName($this->className)->addError($this->error);
+        }
+    }
+}

+ 54 - 0
core/CommandLine/Application.php

@@ -0,0 +1,54 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\CommandLine;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\ModuleConstants;
+
+class Application extends \Symfony\Component\Console\Application
+{
+    protected $dir          = '';
+
+    /**
+     * @override
+     */
+    public function run()
+    {
+        $this->loadCommandsControllers($this->getCommands());
+
+        parent::run();
+    }
+
+    /**
+     * Get all available files
+     * @return array
+     */
+    protected function getCommands()
+    {
+        $files      = glob(ModuleConstants::getFullPath('app', $this->dir).'/*.php');
+        $commands   = [];
+
+        foreach($files as $file)
+        {
+            $file   = substr($file, strrpos($file, DIRECTORY_SEPARATOR)+1);
+            $file   = substr($file, 0, strrpos($file, '.'));
+
+            $commands[] = $file;
+        }
+
+        return $commands;
+    }
+
+    /**
+     * Create new objects and add it
+     * @param $commands
+     */
+    protected function loadCommandsControllers($commands)
+    {
+        foreach($commands as $command)
+        {
+            $class  = ModuleConstants::getRootNamespace().'\App\\'.$this->dir.'\\'.$command;
+
+            $this->add(new $class);
+        }
+    }
+}

+ 53 - 0
core/CommandLine/Command.php

@@ -0,0 +1,53 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\CommandLine;
+
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
+
+/**
+ * Class Command
+ * @package ModulesGarden\Servers\ProxmoxVps\Core\CommandLine
+ */
+class Command extends AbstractCommand
+{
+    /**
+     *
+     */
+    final protected function configure()
+    {
+        parent::configure();
+    }
+
+    /**
+     * Execute command
+     * @param InputInterface $input
+     * @param OutputInterface $output
+     */
+    final protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        return parent::execute($input, $output, new SymfonyStyle($input, $output));
+    }
+
+    /**
+     * @param InputInterface $input
+     * @param OutputInterface $output
+     * @throws \Exception
+     */
+    protected function beforeProcess(InputInterface $input, OutputInterface $output)
+    {
+        (new Hypervisor($this->getName(), $input->getOptions()))
+            ->lock();
+    }
+
+    /**
+     * @param InputInterface $input
+     * @param OutputInterface $output
+     */
+    protected function afterProcess(InputInterface $input, OutputInterface $output)
+    {
+        (new Hypervisor($this->getName(), $input->getOptions()))
+            ->unlock();
+    }
+}

+ 86 - 0
core/CommandLine/CommandLoop.php

@@ -0,0 +1,86 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\CommandLine;
+
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class CommandLoop extends AbstractCommand
+{
+    /**
+     * Loop interval in seconds
+     * @var int
+     */
+    protected $loopInterval = 5;
+
+    /**
+     * Loop counter
+     * @var int
+     * @TODO remove me
+     */
+    private $loopCounter  = 0;
+
+    /**
+     *
+     */
+    final protected function configure()
+    {
+        parent::configure();
+    }
+
+    /**
+     * @param InputInterface $input
+     * @param OutputInterface $output
+     * @return int|null|void
+     * @throws \Exception
+     */
+    final protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        $hypervisor = new Hypervisor($this->getName(), $input->getOptions());
+
+        /**
+         * Lock command in database. We want to run only one command in the same time
+         */
+        $hypervisor->lock();
+
+        do
+        {
+            /**
+             * Let's do something funny!
+             */
+            parent::execute($input, $output);
+
+            /**
+             * Ping... Pong... Ping...
+             */
+            $hypervisor->ping();
+
+            /**
+             * Time to sleep!
+             */
+            $hypervisor->sleep($this->loopInterval);
+
+            /**
+             * @TODO remove me
+             */
+            $this->loopCounter++;
+        }
+        while(!$hypervisor->shouldBeStopped());
+
+        /**
+         * Unlock command in database
+         */
+        $hypervisor->unlock();
+    }
+
+    /**
+     * @return int
+     */
+    final protected function getLoopCounter()
+    {
+        return $this->loopCounter;
+    }
+}
+
+
+//

+ 8 - 0
core/CommandLine/CommandManager.php

@@ -0,0 +1,8 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\CommandLine;
+
+class CommandManager extends Application
+{
+
+}

+ 8 - 0
core/CommandLine/CronManager.php

@@ -0,0 +1,8 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\CommandLine;
+
+class CronManager extends Application
+{
+    protected $dir          = 'Cron';
+}

+ 348 - 0
core/CommandLine/CronManager.php_old

@@ -0,0 +1,348 @@
+<?php
+
+namespace ModulesGarden\ModuleFramework\Core\CommandLine;
+
+use ModulesGarden\ModuleFramework\Core\FileReader\Validator;
+use ModulesGarden\ModuleFramework\Core\ModuleConstants;
+use ModulesGarden\ModuleFramework\Core\DependencyInjection;
+use ModulesGarden\ModuleFramework\Core\FileReader\File;
+use ModulesGarden\ModuleFramework\Core\CommandLine\ReaderCronTask;
+use ModulesGarden\ModuleFramework\Core\Models\CronTabs;
+
+/**
+ * Description of CronManager
+ *
+ * @author Rafał
+ */
+class CronManager {
+    
+    const AVAILABLE_MODES = ['cli', 'cgi-fcgi'];
+    
+    protected $arguments = [];
+    
+    protected $appCronPath = '';
+    
+    protected $coreCronPath = '';
+    
+    protected $parentUId;
+    
+    protected $parentGId;
+    
+    protected $cronPids = '';
+    
+    protected $isParent = true;
+    
+    protected $parentId;
+    
+    protected $childId;
+
+    /**
+     * @var Validator
+     */
+    protected $fileValidator;
+    
+    public function __construct(Validator $fileValidator) {
+        $this->fileValidator = $fileValidator;
+        $this->appCronPath   = ModuleConstants::getModuleRootDir() . DS . 'app' . DS . 'Cron' . DS;
+        $this->coreCronPath  = ModuleConstants::getModuleRootDir() . DS . 'core' . DS . 'Cron' . DS;
+        $this->cronPidsPath  = ModuleConstants::getModuleRootDir() . DS . 'storage' . DS . 'crons' . DS;
+        
+        if($this->fileValidator->isExist($this->cronPidsPath) === false)
+        {
+            mkdir($this->cronPidsPath);
+            File::setPermission($this->cronPidsPath);
+        }
+
+        if (self::isThread())
+        {
+            $this->appCronPath  .= "Thread" . DS;
+            $this->coreCronPath .= "Thread" . DS;
+        }
+        else 
+        {
+            $this->appCronPath  .= "WithoutThread" . DS;
+            $this->coreCronPath .= "WithoutThread" . DS;
+        }
+        
+        $this->parentGId = getmygid();
+        $this->parentUId = getmyuid();
+    }
+    
+    public function setArgv($arguments)
+    {
+        $this->arguments = $arguments;
+        
+        return $this;
+    }
+    
+    public function execute()
+    {
+        $this->loadArguments();
+        
+        if($this->isInCliMode() === false)
+        {
+            return $this;
+        }
+        if (count($this->arguments) == 0)
+        {
+            $this->arguments = ReaderCronTask::get();
+        }
+        
+        $this->loadDefaultCronManager();
+        foreach ($this->arguments as $className)
+        {
+            $className = trim(trim($className, '--'), '-');
+            $class = ModuleConstants::getRootNamespace() . "\\";
+            if ($this->fileValidator->isExist($this->appCronPath . $className . ".php"))
+            {
+                $class .= "App\Cron\\" . $this->getType() . "\\" . $className;
+                $this->runTask($class, $className);
+            }
+            elseif ($this->fileValidator->isExist($this->coreCronPath . $className . ".php"))
+            {
+                $class .= "Core\Cron\\" . $this->getType() . "\\" . $className;
+                $this->runTask($class, $className);
+            }
+        }
+        
+        return $this;
+    }
+    
+    protected function runTask($class, $className)
+    {
+        if ($this->classExist($class) === true && $this->isCronRunning($className) === false)
+        {
+            if ($this->beforeRunTask($className) === false)
+            {
+                return;
+            }
+            
+            $instant = DependencyInjection::create($class, null, (class_exists(\Thread::class)?false:true));
+            $instant->setCronManager($this);
+            $instant->setClassName($className);
+            if (self::isThread() === false)
+            {
+                $instant->ischild(!$this->isParent)
+                        ->setChildId($this->childId)
+                        ->setParentId($this->parentId)
+                        ->setParentGroupId($this->parentGId)
+                        ->setParentUserId($this->parentUId);
+
+            }
+            $instant->start();
+            unset($instant);
+            $this->afterRunTask($className);
+        }
+    }
+    
+    protected function getType()
+    {
+        return (self::isThread()?'Thread':'WithoutThread');
+    }
+    
+    public static function isThread()
+    {
+        return class_exists(\Thread::class);
+    }
+    
+    protected function loadArguments()
+    {
+        $deleteClass = [];
+        foreach ($this->arguments as $key => $name) {
+            if (strpos($name, 'cron.php') !== false)
+            {
+                $deleteClass[] = $key; 
+            }
+            elseif ($name === '--parent')
+            {
+                $this->parentId = $this->arguments[$key + 1];
+                $this->isParent = false;
+                $deleteClass[] = $key; 
+                $deleteClass[] = $key + 1; 
+            }
+            elseif ($name === '--child')
+            {
+                $this->childId = $this->arguments[$key + 1];
+                $this->isParent = false;
+                $deleteClass[] = $key; 
+                $deleteClass[] = $key + 1; 
+            }
+            elseif ($name === '--parentuid')
+            {
+                $this->parentUId  = $this->arguments[$key + 1];
+                $deleteClass[]  = $key;
+                $deleteClass[]  = $key + 1;
+            }
+            elseif ($name === '--parentgid')
+            {
+                $this->parentGId  = $this->arguments[$key + 1];
+                $deleteClass[]  = $key;
+                $deleteClass[]  = $key + 1;
+            }
+        }
+        
+        foreach ($deleteClass as $clasKey)
+        {
+            unset($this->arguments[$clasKey]);
+        }
+        
+        return $this;
+    }
+    
+    protected function classExist($name)
+    {
+        return class_exists($name);
+    }
+    
+    public static function updatePids($name, $id = '')
+    {
+        touch(ModuleConstants::getModuleRootDir() . DS . 'storage' . DS . 'crons' . DS . $name. 'Pid' . $id . '.php');
+    }
+    
+    public static function removePids($name, $id = '')
+    {
+        unlink(ModuleConstants::getModuleRootDir() . DS . 'storage' . DS . 'crons' . DS . $name. 'Pid' . $id . '.php');
+    }
+    
+    public static function existPids($name, $id = '')
+    {
+        return file_exists(ModuleConstants::getModuleRootDir() . DS . 'storage' . DS . 'crons' . DS . $name. 'Pid' . $id . '.php');
+    }
+
+
+    public function createPids($file)
+    {
+        return file_put_contents($file, '<?php die(); '.getmypid());
+    }
+    
+    public function isChildRunning($name, $id)
+    {
+        $file = $this->cronPidsPath . $name. 'Pid' . $id . '.php';
+        
+        if($this->fileValidator->isExist($file) && filemtime($file) > time() - 7200)
+        {
+            return true;
+        }
+        return false;
+    }
+    
+    private function isCronRunning($name)
+    {
+        if ($this->isParent === false)
+        {
+            $file = $this->cronPidsPath . $name. 'Pid' . $this->childId . '.php';
+        
+            if($this->fileValidator->isExist($file) && filemtime($file) > time() - 7200)
+            {
+                return true;
+            }
+
+            if($this->createPids($file) === false)
+            {
+                return true;
+            }
+        }
+        
+        return false;
+        
+        /**
+        if(PHP_OS == "Linux")
+        {
+            $out = null;
+            exec("ps aux | grep 'php -q.*modules/addons/AdvancedBilling/cron/cron.php$' | grep -v 'grep'", $out);
+            if(count($out) > 1)
+            {
+                return true;
+            }
+        }
+        **/
+    }
+
+    
+    private function isInCliMode()
+    { 
+        if (in_array(php_sapi_name(), self::AVAILABLE_MODES)) 
+        {
+            return true;
+        } 
+        else 
+        {
+            return false;
+        }
+    }
+    
+    protected function loadDefaultCronManager()
+    {
+        $defaultCron = CronTabs::ifDefaultCronManager()->first();
+        if ($this->isParent && $defaultCron && $defaultCron->status != 'start')
+        {
+            CronTabs::ifDefaultCronManager()->updateStatus('start');
+            unset($defaultCron);
+        }
+        elseif ($this->isParent && !$defaultCron)
+        {
+            CronTabs::create([
+                'name'   => CronTabs::DEFAULT_CRON_MANAGER_NAME,
+                'status' => 'start',
+                'params' => [],
+                'errors' => []
+            ]);
+        }
+        
+        return $this;
+    }
+    
+    protected function beforeRunTask($className)
+    {
+        if ($this->isParent)
+        {
+            if (CronTabs::ifDefaultCronManager()->getQuery()->first()->status == 'stop')
+            {
+                exit;
+            }
+            $cronTask = CronTabs::ifName($className)->getQuery()->first();
+            if ($cronTask && $cronTask->status != 'stop')
+            {
+                return false;
+            }
+
+            $params = [
+                'parentId'  => getmypid(),
+                'parentUId' => $this->parentUId,
+                'parentGId' => $this->parentGId
+            ];
+            if ($cronTask)
+            {
+                CronTabs::ifName($className)->updateStatus('start', $params);
+            }
+            else
+            {
+                CronTabs::create([
+                    'name'   => $className,
+                    'status' => 'start',
+                    'params' => $params,
+                    'errors' => []
+                ]);
+            }
+
+            usleep(500000);
+            $cronTask = (new CronTabs())->ifName($className)->getQuery()->first();
+            if ($this->isParent && json_decode($cronTask->params)->parentId != getmypid())
+            {
+                return false;
+            }
+        }
+        
+        return true;
+    }
+    
+    protected function afterRunTask($className)
+    {
+        if ($this->isParent)
+        {
+            CronTabs::ifName($className)->updateStatus();
+        }
+        
+        return $this;
+    }
+}

+ 253 - 0
core/CommandLine/Hypervisor.php

@@ -0,0 +1,253 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\CommandLine;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\Models\Commands;
+
+/**
+ * We need that for calculating interval between operations and for killing process for PHP < 7.1
+ * Don't remove it!
+ */
+declare(ticks = 1);
+
+/**
+ * Class Hypervisor
+ * @package ModulesGarden\Servers\ProxmoxVps\Core\CommandLine
+ * @todo - clean up!
+ */
+class Hypervisor
+{
+    /**
+     * command name
+     * @var null
+     */
+    protected $name     = null;
+
+    /**
+     * command params
+     * @var null
+     */
+    protected $params   = null;
+
+    /**
+     * @var int
+     */
+    protected $counter  = 0;
+
+    /**
+     * @var \ModulesGarden\Servers\ProxmoxVps\Core\Models\Commands
+     */
+    protected $entity   = null;
+
+    protected $tickTime = 1;
+
+    /**
+     * @var int
+     */
+    protected $sleepInterval    =   5;
+
+    /**
+     * Hypervisor constructor.
+     * @param $name
+     * @param $params
+     */
+    public function __construct($name, $params)
+    {
+        $this->name     = $name;
+        $this->params   = $params;
+    }
+
+    /**
+     * Lock script
+     * @return $this
+     * @throws \Exception
+     */
+    public function lock()
+    {
+        if($this->isActive())
+        {
+            throw new \Exception('Cannot create lock. Command already running');
+        }
+
+        $this->registerTickHandler();
+        $this->registerSignalHandler();
+
+        $this->getEntity()->setRunning();
+
+        return $this;
+    }
+
+    /**
+     * Unlock script
+     * @return $this
+     */
+    public function unlock()
+    {
+        $this->getEntity()
+            ->setStopped()
+            ->clearAction();
+
+        return $this;
+    }
+
+    /**
+     * Update information about running command
+     * @return $this
+     */
+    public function ping()
+    {
+        $this->getEntity()
+            ->ping();
+
+        return $this;
+    }
+
+    /**
+     * @param $interval
+     * @return $this
+     */
+    public function sleep($interval)
+    {
+        $this->getEntity()
+            ->setSleeping();
+
+        /**
+         * We need run tick function during sleep, so we run many sleep function in loop
+         */
+        $counter    = 0;
+        while($counter < $interval)
+        {
+            if($interval <= $this->sleepInterval)
+            {
+                $time   = $interval;
+            }
+            else
+            {
+                $time   = $this->sleepInterval;
+            }
+
+
+            $counter    += $time;
+
+            sleep($time);
+        }
+
+
+        $this->getEntity()
+            ->setRunning();
+
+        return $this;
+    }
+
+    public function shouldBeStopped()
+    {
+        return $this->getEntity()
+                    ->shouldBeStopped();
+    }
+
+    /**
+     * @return bool
+     * @throws \Exception
+     */
+    public function checkIfRunning()
+    {
+        if(!$this->isRunning())
+        {
+            throw new \Exception('Script is not running');
+        }
+
+        return true;
+    }
+
+    /**
+     * @return bool
+     */
+    public function isStopped()
+    {
+        $this->getEntity()
+            ->shouldBeStopped();
+    }
+
+    /**
+     * Returns true if command is running or sleeping
+     * @return bool
+     */
+    public function isActive()
+    {
+        $entity = $this->getEntity();
+        $diff   = time() - $entity->updated_at->timestamp;
+
+        if($entity->isSleeping() && $diff <= $this->sleepInterval)
+        {
+            return true;
+        }
+
+        if($entity->isRunning() && $entity->updated_at->timestamp + $this->tickTime > time())
+        {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * @param bool $force
+     * @return ModulesGarden\Servers\ProxmoxVps\Core\Models\Commands|Commands
+     */
+    protected function getEntity($force = false)
+    {
+        if($this->entity && $force === false)
+        {
+            return $this->entity;
+        }
+
+        $this->entity = Commands::where('name', $this->name)->first();
+
+        if(!$this->entity)
+        {
+            $this->entity        = new Commands();
+            $this->entity->name  = $this->name;
+            $this->entity->uuid  = uniqid();
+            $this->entity->save();
+        }
+
+        return $this->entity;
+    }
+
+    /**
+     *
+     */
+    protected function registerTickHandler()
+    {
+        $tick   = new Tick(function(){
+            $this->ping();
+        }, 10);
+        $tick->start();
+    }
+
+    /**
+     * Mark process as stopped and exit. This function will be called when you press ctrl c from console
+     */
+    protected function registerSignalHandler()
+    {
+        if(!function_exists('pcntl_signal'))
+        {
+            return;
+        }
+
+        //works from PHP 7.1
+        if(function_exists('pcntl_async_signals'))
+        {
+            pcntl_async_signals(true);
+        }
+
+        $exit = function(){
+            $this->getEntity()->setStopped();
+            exit;
+        };
+
+        pcntl_signal(SIGINT,  $exit);
+        pcntl_signal(SIGHUP, $exit);
+        pcntl_signal(SIGUSR1, $exit);
+    }
+}

+ 8 - 0
core/CommandLine/Job.php

@@ -0,0 +1,8 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\CommandLine;
+
+class Job
+{
+
+}

+ 86 - 0
core/CommandLine/JobsLoop.php

@@ -0,0 +1,86 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\CommandLine;
+
+use Symfony\Component\Console\Input\InputOption;
+
+class JobsLoop extends AbstractCommand
+{
+    /**
+     * Loop interval in seconds
+     * @var int
+     */
+    protected $loopInterval = 5;
+
+    /**
+     * @var int
+     */
+    protected $maxChildren  = 5;
+
+    /**
+     * @var int
+     */
+    protected $tasksPerChildren = 10;
+    /**
+     *
+     */
+    final protected function configure()
+    {
+        parent::configure();
+    }
+
+    /**
+     *
+     */
+    final protected function setup()
+    {
+        $this->addOption('parent', InputOption::VALUE_OPTIONAL, 'Parent id', null);
+        $this->addOption('id', InputOption::VALUE_OPTIONAL, 'Child id', null);
+    }
+
+    /**
+     * Execute command in the loop
+     * @param InputInterface $input
+     * @param OutputInterface $output
+     */
+    final protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        $parent         =    $input->getOption('parent');
+        $id                 = $input->getOption('id');
+        $parentHypervior    = new Hypervisor($this->getName());
+
+        //Lock parent
+        if(!$parent)
+        {
+            $parentHypervior->lock();
+        }
+        else
+        {
+            $parentHypervior->checkIfRunning();
+        }
+
+        if($id)
+        {
+
+        }
+
+        do
+        {
+            parent::process($input, $output, new SymfonyStyle($input, $output));
+
+            sleep($this->loopInterval);
+        }
+        while(!$hypervisor->isStopped());
+    }
+
+    /**
+     * @param $jobs[]
+     */
+    protected function processJobs($jobs)
+    {
+        foreach($jobs as $job)
+        {
+
+        }
+    }
+}

+ 64 - 0
core/CommandLine/ReaderCronTask.php

@@ -0,0 +1,64 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\CommandLine;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\FileReader\Reader;
+use ModulesGarden\Servers\ProxmoxVps\Core\ModuleConstants;
+
+/**
+ * Description of AbstractReaderYml
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class ReaderCronTask
+{
+    /**
+     * @var array
+     */
+    protected $data = [];
+
+    public function __construct()
+    {
+        if (count($this->data) == 0)
+        {
+            $this->load();
+        }
+    }
+
+    public function getData()
+    {
+        return $this->data;
+    }
+
+    protected function readYml($name)
+    {
+        return Reader::read($name)->get();
+    }
+
+    public static function get()
+    {
+
+        $instance = new static;
+        return $instance->getData();
+    }
+
+    protected function load()
+    {
+        $this->data = $this->rebuildData($this->readYml(ModuleConstants::getFullPath('app', 'Config', 'cron.yml')));
+    }
+    
+    protected function rebuildData($data)
+    {
+        $return = [];
+        foreach ($data['list'] as $name => $isRun)
+        {
+            if ((bool)$isRun)
+            {
+                $return[] = $name;
+            }
+        }
+        
+        return $return;
+    }
+    
+}

+ 68 - 0
core/CommandLine/Tick.php

@@ -0,0 +1,68 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\CommandLine;
+
+/**
+ * Count time between callback time. It requires declare(ticks = 1);
+ * @package ModulesGarden\Servers\ProxmoxVps\Core\CommandLine
+ */
+class Tick
+{
+    /**
+     * @var callable
+     */
+    protected $callback          = null;
+    /**
+     * @var int
+     */
+    protected $callbackTime      = 0;
+    /**
+     * @var int
+     */
+    protected $callbackInterval  = 5;
+
+    /**
+     * Tick constructor.
+     * @param $callback
+     * @param $time
+     */
+    public function __construct($callback, $time)
+    {
+        $this->callback     = $callback;
+        $this->callbackTime = $time;
+    }
+
+    /**
+     *
+     */
+    public function start()
+    {
+        register_tick_function(function(){
+            $this->tick();
+        }, true);
+    }
+
+    /**
+     * @return int
+     */
+    public function getTimeFromLastCallback()
+    {
+        return time() - $this->callbackTime;
+    }
+
+    /**
+     * Call callback if time diffeence is
+     */
+    public function tick()
+    {
+        $difference = $this->getTimeFromLastCallback();
+
+        if($difference > $this->callbackInterval)
+        {
+            $this->callbackTime = time();
+            $callback   = $this->callback;
+
+            $callback();
+        }
+    }
+}

+ 8 - 0
core/Config/configuration.yml

@@ -0,0 +1,8 @@
+version: '1.0.0'
+systemName: 'ProxmoxVps'
+name: 'proxmoxVPS'
+description: 'Modules Garden Module Framework.<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>'
+fields: []
+moduleIcon: 'crm'

+ 1 - 0
core/Config/cron.yml

@@ -0,0 +1 @@
+class:

+ 5 - 0
core/Config/di/buildWithDefaultMethod.yml

@@ -0,0 +1,5 @@
+class:
+    - {name: "\\ModulesGarden\\Servers\\ProxmoxVps\\Core\\Http\\Request", method: "build",                        args: []}
+    - {name: '\\ModulesGarden\\Servers\\ProxmoxVps\\Core\\Http\\View\\Smarty',  method: "get",                    args: [NULL,NULL]}
+    - {name: '\\ModulesGarden\\Servers\\ProxmoxVps\\Core\\HandlerError\\Logger',  method: "get",                  args: ["default","debug.log","warning.log","error.log"]}
+    - {name: '\\ModulesGarden\\Servers\\ProxmoxVps\\Core\\RegisterManager\\Register',  method: "getInstace",      args: []}

+ 1 - 0
core/Config/di/interface.yml

@@ -0,0 +1 @@
+interface: []

+ 30 - 0
core/Config/di/register.yml

@@ -0,0 +1,30 @@
+class:
+    - {namespace: '\\ModulesGarden\\Servers\\ProxmoxVps\\Core\\Configuration\\Addon\\Config\\After',            alias: "", singleton: true , auto: false}
+    - {namespace: '\\ModulesGarden\\Servers\\ProxmoxVps\\Core\\Configuration\\Addon\\Activate\\After',          alias: "", singleton: true , auto: false}
+    - {namespace: '\\ModulesGarden\\Servers\\ProxmoxVps\\Core\\Configuration\\Addon\\Deactivate\\After',        alias: "", singleton: true , auto: false}
+    - {namespace: '\\ModulesGarden\\Servers\\ProxmoxVps\\Core\\Configuration\\Addon\\Update\\After',            alias: "", singleton: true , auto: false}
+    - {namespace: '\\ModulesGarden\\Servers\\ProxmoxVps\\Core\\Configuration\\Addon\\Config\\Before',           alias: "", singleton: true , auto: false}
+    - {namespace: '\\ModulesGarden\\Servers\\ProxmoxVps\\Core\\Configuration\\Addon\\Activate\\Before',         alias: "", singleton: true , auto: false}
+    - {namespace: '\\ModulesGarden\\Servers\\ProxmoxVps\\Core\\Configuration\\Addon\\Deactivate\\Before',       alias: "", singleton: true , auto: false}
+    - {namespace: '\\ModulesGarden\\Servers\\ProxmoxVps\\Core\\Configuration\\Addon\\Update\\Before',           alias: "", singleton: true , auto: false}
+    - {namespace: '\\ModulesGarden\\Servers\\ProxmoxVps\\Core\\App\\Controllers\\Instances\\Addon\\Config', alias: "configurationAddon", singleton: true , auto: false}
+    - {namespace: '\\ModulesGarden\\Servers\\ProxmoxVps\\Core\\Configuration\\Data',           alias: "configurationData", singleton: true , auto: false}
+    - {namespace: '\\ModulesGarden\\Servers\\ProxmoxVps\\Core\\Lang\\Lang',                               alias: "lang", singleton: false ,auto: false}
+    - {namespace: '\\ModulesGarden\\Servers\\ProxmoxVps\\Core\\Http\\View\\Smarty',                       alias: "smarty", singleton: true , auto: true }
+    - {namespace: '\\ModulesGarden\\Servers\\ProxmoxVps\\Core\\HandlerError\\Logger',                     alias: "logger", singleton: true , auto: false}
+    - {namespace: '\\ModulesGarden\\Servers\\ProxmoxVps\\Core\\HandlerError\\ErrorManager',         alias: "errorManager", singleton: true , auto: false}
+    - {namespace: '\\ModulesGarden\\Servers\\ProxmoxVps\\Core\\Http\\Request',                           alias: "request", singleton: true , auto: true }
+    - {namespace: '\\ModulesGarden\\Servers\\ProxmoxVps\\Core\\UI\\View',                                   alias: "view", singleton: true , auto: true }
+    - {namespace: '\\ModulesGarden\\Servers\\ProxmoxVps\\Core\\UI\\ViewAjax',                           alias: "viewAjax", singleton: true , auto: true }
+    - {namespace: '\\ModulesGarden\\Servers\\ProxmoxVps\\Core\\UI\\ViewIntegrationAddon',   alias: "viewIntegrationAddon", singleton: true , auto: true }
+    - {namespace: '\\ModulesGarden\\Servers\\ProxmoxVps\\Core\\Http\\AbstractController',             alias: "controller", singleton: true , auto: true }
+    - {namespace: '\\ModulesGarden\\Servers\\ProxmoxVps\\Core\\Http\\AbstractClientController', alias: "clientController", singleton: true , auto: true }
+    - {namespace: '\\ModulesGarden\\Servers\\ProxmoxVps\\Core\\Http\\AbstractHooksClient',alias: "clientHookController", singleton: true , auto: true }
+    - {namespace: '\\ModulesGarden\\Servers\\ProxmoxVps\\Core\\Configuration\\Addon\\Update\\PatchManager',alias: "patchManager",singleton: true ,auto: false}
+    - {namespace: '\\ModulesGarden\\Servers\\ProxmoxVps\\Core\\HandlerError\\WhmcsLogsHandler',      alias: "whmcsLogger", singleton: true , auto: false}
+    - {namespace: '\\ModulesGarden\\Servers\\ProxmoxVps\\Core\\Logger\\Entity',                     alias: "entityLogger", singleton: true , auto: true }
+    - {namespace: '\\ModulesGarden\\Servers\\ProxmoxVps\\Core\\CommandLine\\CronManager',            alias: "cronManager", singleton: true , auto: true }
+    - {namespace: '\\ModulesGarden\\Servers\\ProxmoxVps\\Core\\RegisterManager\\Register',              alias: "register", singleton: true , auto: false}
+    - {namespace: '\\ModulesGarden\\Servers\\ProxmoxVps\\Core\\UI\\Widget\\Sidebar\\SidebarService',    alias: "sidebar", singleton: true ,auto: false}
+    - {namespace: '\\ModulesGarden\\Servers\\ProxmoxVps\\Core\\Helper\\WhmcsParams',                 alias: "whmcsParams", singleton: false ,auto: false}
+    - {namespace: '\\ModulesGarden\\Servers\\ProxmoxVps\\Core\\App\\AppParamsContainer',      alias: "appParamsContainer", singleton: false ,auto: false}

+ 8 - 0
core/Config/di/services.php

@@ -0,0 +1,8 @@
+<?php
+
+return [
+    \ModulesGarden\Servers\ProxmoxVps\Core\Lang\Lang::class,
+    \ModulesGarden\Servers\ProxmoxVps\Core\Events\Dispatcher::class,
+    \ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\Addon\Config::class,
+    \ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Sidebar\SidebarService::class
+];

+ 5 - 0
core/Config/di/services.yml

@@ -0,0 +1,5 @@
+- \ModulesGarden\Servers\ProxmoxVps\Core\Lang\Lang
+- \ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\Addon\Config
+- \ModulesGarden\Servers\ProxmoxVps\Core\UI\Widget\Sidebar\SidebarService
+- \ModulesGarden\Servers\ProxmoxVps\Core\Helper\WhmcsParams
+- \ModulesGarden\Servers\ProxmoxVps\Core\App\AppParamsContainer

+ 18 - 0
core/Configuration/Addon/AbstractAfter.php

@@ -0,0 +1,18 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Addon;
+
+/**
+ * Description of AbstractAfter
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+abstract class AbstractAfter
+{
+    public function __construct()
+    {
+        
+    }
+
+    abstract public function execute(array $params = []);
+}

+ 17 - 0
core/Configuration/Addon/AbstractBefore.php

@@ -0,0 +1,17 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Addon;
+
+/**
+ * Description of AbstractBefore
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+abstract class AbstractBefore
+{
+
+    public function __construct()
+    {
+
+    }
+}

+ 22 - 0
core/Configuration/Addon/Activate/After.php

@@ -0,0 +1,22 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Addon\Activate;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Addon\AbstractAfter;
+
+/**
+ * Runs after module activation actions
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class After extends AbstractAfter
+{
+    /**
+     * @param array $params
+     * @return array
+     */
+    public function execute(array $params = [])
+    {
+        return $params;
+    }
+}

+ 34 - 0
core/Configuration/Addon/Activate/Before.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Addon\Activate;
+
+use \ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Addon\AbstractBefore;
+use \ModulesGarden\Servers\ProxmoxVps\Core\ModuleConstants;
+use \ModulesGarden\Servers\ProxmoxVps\Core\ServiceLocator;
+/**
+ * Runs before module activation actions
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Before extends AbstractBefore
+{
+
+    /**
+     * @param array $params
+     * @return array
+     */
+    public function execute(array $params = [])
+    {
+        $path = ModuleConstants::getModuleRootDir() . DS . 'storage';
+
+        if (is_writable($path) === false || is_readable($path) === false)
+        {
+            $params['status'] = 'error';
+            $params['description'] .= PHP_EOL . ServiceLocator::call('lang')
+                    ->addReplacementConstant('storage_path', ModuleConstants::getFullPath('storage'))
+                    ->absoluteT('permissionsStorage');
+        }
+
+        return $params;
+    }
+}

+ 24 - 0
core/Configuration/Addon/Config/After.php

@@ -0,0 +1,24 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Addon\Config;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Addon\AbstractAfter;
+
+/**
+ * Runs after loading module configuration
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class After extends AbstractAfter
+{
+
+    /**
+     * @param array $params
+     * @return array
+     */
+    public function execute(array $params = [])
+    {
+
+        return $params;
+    }
+}

+ 23 - 0
core/Configuration/Addon/Config/Before.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Addon\Config;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Addon\AbstractBefore;
+
+/**
+ * Runs before loading module configuration
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Before extends AbstractBefore
+{
+
+    /**
+     * @param array $params
+     * @return array
+     */
+    public function execute(array $params = [])
+    {
+        return $params;
+    }
+}

+ 24 - 0
core/Configuration/Addon/Deactivate/After.php

@@ -0,0 +1,24 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Addon\Deactivate;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Addon\AbstractAfter;
+
+/**
+ * Runs after addon deactivation
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class After extends AbstractAfter
+{
+
+    /**
+     * @param array $params
+     * @return array
+     */
+    public function execute(array $params = [])
+    {
+
+        return $params;
+    }
+}

+ 24 - 0
core/Configuration/Addon/Deactivate/Before.php

@@ -0,0 +1,24 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Addon\Deactivate;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Addon\AbstractBefore;
+
+/**
+ * Runs before addon deactivation
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Before extends AbstractBefore
+{
+
+    /**
+     * @param array $params
+     * @return array
+     */
+    public function execute(array $params = [])
+    {
+
+        return $params;
+    }
+}

+ 24 - 0
core/Configuration/Addon/Update/After.php

@@ -0,0 +1,24 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Addon\Update;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Addon\AbstractAfter;
+
+/**
+ * runs after module update actions
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class After extends AbstractAfter
+{
+
+    /**
+     * @param array $params
+     * @return array
+     */
+    public function execute(array $params = [])
+    {
+
+        return $params;
+    }
+}

+ 22 - 0
core/Configuration/Addon/Update/Before.php

@@ -0,0 +1,22 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Addon\Update;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Addon\AbstractBefore;
+
+/**
+ * runs after module update actions
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Before extends AbstractBefore
+{
+
+    /**
+     * @return array
+     */
+    public function execute($version)
+    {
+        return [];
+    }
+}

+ 78 - 0
core/Configuration/Addon/Update/Patch/AbstractPatch.php

@@ -0,0 +1,78 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Addon\Update\Patch;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\Helper\DatabaseHelper;
+use ModulesGarden\Servers\ProxmoxVps\Core\ModuleConstants;
+
+/**
+ * Description of AbstractPatch
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class AbstractPatch
+{
+    /**
+     * @var DatabaseHelper 
+     */
+    protected $databaseHelper;
+
+    /**
+     * @var string
+     */
+    private $path;
+
+    /**
+     * @var string
+     */
+    private $versionName;
+
+    protected $version;
+
+    /**
+     * @param DatabaseHelper $databaseHelper
+     */
+    public function __construct(DatabaseHelper $databaseHelper)
+    {
+        $this->databaseHelper = $databaseHelper;
+        $this->path = ModuleConstants::getModuleRootDir() . DS . 'app' . DS . 'Database';
+        $this->versionName = end(explode("\\",get_called_class()));
+    }
+
+    /**
+     * @return bool
+     */
+    protected function runSchema()
+    {
+        return ($this->databaseHelper->performQueryFromFile($this->path . DS . $this->versionName . DS . 'schema.sql') === true)
+                ?false
+                :true;
+    }
+
+    /**
+     * @return bool
+     */
+    protected function runData()
+    {
+        return ($this->databaseHelper->performQueryFromFile($this->path . DS . $this->versionName . DS . 'data.sql') === true)
+                ?false
+                :true;
+    }
+
+    public function setVersion($version = null)
+    {
+        $this->version = $version;
+
+        return $this;
+    }
+
+    public function getVersion()
+    {
+        return $this->version;
+    }
+
+    public function execute()
+    {
+        
+    }
+}

+ 105 - 0
core/Configuration/Addon/Update/PatchManager.php

@@ -0,0 +1,105 @@
+<?php
+namespace ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Addon\Update;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\ModuleConstants;
+use ModulesGarden\Servers\ProxmoxVps\Core\DependencyInjection;
+use ModulesGarden\Servers\ProxmoxVps\Core\ServiceLocator;
+
+/**
+ * Description of PatchManager
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class PatchManager
+{
+    
+    protected $updatePath;
+    
+    protected $updateFiles = [];
+        
+    public function __construct()
+    {
+        $this->updatePath = ModuleConstants::getModuleRootDir() . DS . "app" . DS . "Configuration" . DS . "Addon" . DS . "Update" . DS . "Patch";
+        $this->loadUpdatePath();
+    }
+    
+    public function run($newVersion, $oldVersion)
+    {
+        $fullPath = $this->getUpdatePath();
+        array_map(function ($version, $fileName) use($newVersion, $oldVersion, $fullPath)
+        {
+            if ($this->checkVersion($newVersion, $oldVersion, $version))
+            {
+                try
+                {
+                    $className = ModuleConstants::getRootNamespace() . "\App\Configuration\Addon\Update\Patch\\" . $fileName;
+                    DependencyInjection::create($className)->setVersion($version)->execute();
+                }
+                catch (\Exception $exc)
+                {
+                    ServiceLocator::call("errorManager")
+                        ->addError(
+                            self::class,
+                            $exc->getMessage(),
+                            [
+                                "newVersion"    => $newVersion,
+                                "oldVersion"    => $oldVersion,
+                                "updateVersion" => $version,
+                                "fullFileName"  => $fullPath . DS . $fileName . ".php"
+                            ]
+                    );
+                }
+                
+            }
+        },
+        array_keys($this->getUpdateFiles()),
+        $this->getUpdateFiles()
+        );
+        
+        return $this;
+    }
+    
+    
+    protected function checkVersion($newVersion, $oldVersion, $fileVersion)
+    {
+        if (version_compare($oldVersion, $fileVersion, "<"))
+        {
+            return true;
+        }
+        
+        return false;
+    }
+
+    protected function getUpdatePath()
+    {
+        return $this->updatePath;
+    }
+    
+    protected function getUpdateFiles()
+    {
+        return $this->updateFiles;
+    }
+
+    protected function loadUpdatePath()
+    {
+        $files = scandir($this->getUpdatePath(), 1);
+        
+        if (count($files) != 0)
+        {
+            foreach ($files as $file)
+            {
+               if ($file !== "." && $file !== "..")
+               {
+                   $version = $this->generateVersion($file);
+                   $this->updateFiles[$version] = explode(".", $file)[0];
+               }
+            }
+        }
+    }
+    
+    protected function generateVersion($fileName)
+    {
+        $name = explode('.', $fileName)[0];
+        return str_replace(["M","P"],".",substr($name,1));
+    }
+}

+ 122 - 0
core/Configuration/Data.php

@@ -0,0 +1,122 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\Configuration;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\FileReader\Reader;
+use ModulesGarden\Servers\ProxmoxVps\Core\ModuleConstants;
+
+/**
+ * Description of Data
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Data
+{
+    protected static $data = [];
+
+    public function __construct()
+    {
+        $this->load();
+    }
+
+    public function __get($name)
+    {
+        $this->load();
+        if (array_key_exists(lcfirst($name), self::$data))
+        {
+            return self::$data[lcfirst($name)];
+        }
+        return null;
+    }
+
+    public function getAll()
+    {
+        return self::$data;
+    }
+
+    private function load()
+    {
+        if (count(self::$data) == 0)
+        {
+            $this->loadConfig();
+        }
+    }
+
+    /**
+     * Loads YML configuration files
+     */
+    private function loadConfig()
+    {
+        $dataDev  = $this->read(ModuleConstants::getDevConfigDir() . DS . 'configuration.yml');
+        $dataCore = $this->read(ModuleConstants::getCoreConfigDir() . DS . 'configuration.yml');
+
+        $data = $this->parseConfigData($dataDev, $dataCore);
+
+        $this->loadPackageConfig($data);
+
+        self::$data = $data ? : [];
+    }
+
+    /**
+     * @param self::$data $data
+     *
+     * overwrites module version and wiki url basing on moduleVersion.php file,
+     * this file is added automatically during package creation
+     */
+    private function loadPackageConfig(&$data)
+    {
+        if (file_exists(ModuleConstants::getModuleRootDir() . DS . 'moduleVersion.php'))
+        {
+            include ModuleConstants::getModuleRootDir() . DS . 'moduleVersion.php';
+            if ($moduleVersion)
+            {
+                $data['version'] = $moduleVersion;
+            }
+        }
+
+        if ($data['description'] && strpos($data['description'], ':WIKI_URL:'))
+        {
+            $data['description'] = str_replace(':WIKI_URL:', ($moduleWikiUrl ? : 'https://www.docs.modulesgarden.com/'), $data['description']);
+        }
+
+        $data['debug'] = (file_exists(ModuleConstants::getModuleRootDir() . DIRECTORY_SEPARATOR . '.debug'))
+                ? true : false;
+    }
+
+    private function parseConfigData($dataDev, $dataCore)
+    {
+        if (!$dataDev && $dataCore)
+        {
+            return $dataCore;
+        }
+
+        if (!$dataDev && $dataCore)
+        {
+            return $dataCore;
+        }
+
+        foreach ($dataCore as $coreKey => $core)
+        {
+            $isFind = false;
+            foreach ($dataDev as $devKey => $dev)
+            {
+                if ($devKey === $coreKey)
+                {
+                    $isFind = true;
+                    break;
+                }
+            }
+            if (!$isFind)
+            {
+                $dataDev[$coreKey] = $core;
+            }
+        }
+
+        return $dataDev;
+    }
+
+    private function read($name)
+    {
+        return Reader::read($name)->get();
+    }
+}

+ 13 - 0
core/Configuration/Data/Version.php

@@ -0,0 +1,13 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Data;
+
+/**
+ * Description of Version
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Version
+{
+    //put your code here
+}

+ 30 - 0
core/Configuration/Requirements/Files.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\Configuration\Requirements;
+
+/**
+ * Description of RemoveFiles
+ *
+ * @author INBSX-37H
+ */
+class Files extends \ModulesGarden\Servers\ProxmoxVps\Core\App\Requirements\Instances\Files
+{
+    protected $requirementsList = [
+        [
+            self::PATH => self::MODULE_PATH . '/storage',
+            self::TYPE => self::IS_WRITABLE
+        ],
+        [
+            self::PATH => self::MODULE_PATH . '/storage/app',
+            self::TYPE => self::IS_WRITABLE
+        ],
+        [
+            self::PATH => self::MODULE_PATH . '/storage/crons',
+            self::TYPE => self::IS_WRITABLE
+        ],
+        [
+            self::PATH => self::MODULE_PATH . '/storage/logs',
+            self::TYPE => self::IS_WRITABLE
+        ]
+    ];
+}

+ 0 - 0
core/Database/data.sql


+ 0 - 0
core/Database/schema.sql


+ 14 - 0
core/DependencyInjection.php

@@ -0,0 +1,14 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core;
+
+
+/**
+ * Description of DependencyInjection
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class DependencyInjection extends \ModulesGarden\Servers\ProxmoxVps\Core\DependencyInjection\DependencyInjection
+{
+
+}

+ 76 - 0
core/DependencyInjection/Builder.php

@@ -0,0 +1,76 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\DependencyInjection;
+
+use \ModulesGarden\Servers\ProxmoxVps\Core\SL\Data\DataSL;
+
+class Builder
+{
+    /**
+     * @var DataSL
+     */
+    protected $data = null;
+
+    /**
+     * @var array
+     */
+    protected $registers    = [];
+
+    public function __construct()
+    {
+        $this->init();
+        $this->loadAliases();
+        $this->loadRewrites();
+        $this->loadInstances();
+    }
+
+    protected function init()
+    {
+        Container::setInstance(new Container());
+
+        $this->data = new DataSL();
+
+        $this->registers    = $this->data->getRegisters();
+    }
+
+    protected function loadRewrites()
+    {
+        foreach($this->data->getRewrites() as $alias => $className)
+        {
+            Container::getInstance()->alias($className, $alias);
+        }
+    }
+
+    protected function loadAliases()
+    {
+        foreach($this->data->getAllAlias() as $className => $alias)
+        {
+            Container::getInstance()->alias($className, $alias);
+        }
+    }
+
+    protected function loadInstances()
+    {
+        foreach($this->data->getConfigurations() as $config)
+        {
+            $className  = $config['name'];
+            $method     = $config['method'];
+            $arguments  = $config['args'];
+
+
+            if(!$method)
+            {
+                $obj    = Container::getInstance()->make($className);
+            }
+            else
+            {
+                $obj    = call_user_func_array("$className::$method", $arguments);
+            }
+
+            if(array_key_exists($className, $this->registers) && $this->registers[$className]['singleton'])
+            {
+                Container::getInstance()->instance($className, $obj);
+            }
+        }
+    }
+}

+ 204 - 0
core/DependencyInjection/Container.php

@@ -0,0 +1,204 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\DependencyInjection;
+
+use Illuminate\Contracts\Container\Container as ContainerContract;
+use ModulesGarden\Servers\ProxmoxVps\Core\Helper\WhmcsVersionComparator;
+
+class Container extends \Illuminate\Container\Container
+{
+    protected static $instance = null;
+
+    public static function getInstance()
+    {
+        if (is_null(self::$instance))
+        {
+            self::$instance = new static;
+        }
+
+        return static::$instance;
+    }
+
+    public static function setInstance(ContainerContract $container=null)
+    {
+        self::$instance = $container;
+    }
+
+    /**
+     * @param $parameters
+     * @param array $primitives
+     * @return array
+     */
+    protected function getDependencies($parameters, array $primitives = array())
+    {
+        $dependencies = array();
+        foreach ($parameters as $parameter)
+        {
+            if($parameter->isOptional())
+            {
+                break;
+            }
+
+            $dependency = $parameter->getClass();
+            // If the class is null, it means the dependency is a string or some other
+            // primitive type which we can not resolve since it is not a class and
+            // we will just bomb out with an error since we have no-where to go.
+            if (array_key_exists($parameter->name, $primitives))
+            {
+                $dependencies[] = $primitives[$parameter->name];
+            }
+            elseif (is_null($dependency))
+            {
+                $dependencies[] = $this->resolveNonClass($parameter);
+            }
+            else
+            {
+                $dependencies[] = $this->resolveClass($parameter);
+            }
+        }
+        return (array) $dependencies;
+    }
+
+    /**
+     * Set null value as default parameter when cannot find default value
+     * @param ReflectionParameter $parameter
+     * @return null
+     */
+    protected function resolveNonClass(\ReflectionParameter $parameter)
+    {
+        if ($parameter->isDefaultValueAvailable())
+        {
+            return $parameter->getDefaultValue();
+        }
+
+        return null;
+    }
+
+    /* --------------------------------------- WHMCS 8 --------------------------------------- */
+    /**
+     * Resolve the given type from the container.
+     *
+     * @param  string  $abstract
+     * @param  array  $parameters
+     * @return mixed
+     *
+     * @throws \Illuminate\Contracts\Container\BindingResolutionException
+     */
+    public function make($abstract, array $parameters = [])
+    {
+        /* If $abstract contains namespace without slash at the begging, we need to add it */
+        $explodedAbstract = explode('\\', $abstract);
+        if($explodedAbstract[0] == 'ModulesGarden' && count($explodedAbstract) > 1)
+        {
+            $abstract = '\\'.$abstract;
+        }
+
+        /* This function executes a different code, depending on the version of the container - WHMCS 8 has a much newer version */
+        $version8OrHigher = (new WhmcsVersionComparator)->isWVersionHigherOrEqual('8.0.0');
+        if($version8OrHigher)
+        {
+            return $this->resolve($abstract, $parameters);
+        }
+
+        $abstract = $this->getAlias($this->normalize($abstract));
+        if (isset($this->instances[$abstract])) {
+            return $this->instances[$abstract];
+        }
+
+        $concrete = $this->getConcrete($abstract);
+        if ($this->isBuildable($concrete, $abstract)) {
+            $object = $this->build($concrete, $parameters);
+        } else {
+            $object = $this->make($concrete, $parameters);
+        }
+
+        foreach ($this->getExtenders($abstract) as $extender) {
+            $object = $extender($object, $this);
+        }
+
+        if ($this->isShared($abstract)) {
+            $this->instances[$abstract] = $object;
+        }
+
+        $this->fireResolvingCallbacks($abstract, $object);
+        $this->resolved[$abstract] = true;
+
+        return $object;
+    }
+
+    /**
+     * Resolve all of the dependencies from the ReflectionParameters.
+     *
+     * @param  array  $dependencies
+     * @return array
+     *
+     * @throws \Illuminate\Contracts\Container\BindingResolutionException
+     */
+    protected function resolveDependencies(array $dependencies)
+    {
+        $results = [];
+        foreach ($dependencies as $dependency) {
+            if($dependency->isOptional())
+            {
+                break;
+            }
+
+            if ($this->hasParameterOverride($dependency)) {
+                $results[] = $this->getParameterOverride($dependency);
+
+                continue;
+            }
+
+            $result = is_null($dependency->getClass())
+                ? $this->resolvePrimitive($dependency)
+                : $this->resolveClass($dependency);
+
+            if ($dependency->isVariadic()) {
+                $results = array_merge($results, $result);
+            } else {
+                $results[] = $result;
+            }
+        }
+
+        return $results;
+    }
+
+    /**
+     * Resolve a non-class hinted primitive dependency.
+     *
+     * @param  \ReflectionParameter  $parameter
+     * @return mixed
+     *
+     * @throws \Illuminate\Contracts\Container\BindingResolutionException
+     */
+    protected function resolvePrimitive(\ReflectionParameter $parameter)
+    {
+        if (! is_null($concrete = $this->getContextualConcrete('$'.$parameter->name))) {
+            return $concrete instanceof \Closure ? $concrete($this) : $concrete;
+        }
+
+        if ($parameter->isDefaultValueAvailable()) {
+            return $parameter->getDefaultValue();
+        }
+
+        if($parameter->hasType())
+        {
+            $returnEmptyType = [];
+            switch(strtolower($parameter->getType()->getName()))
+            {
+                case 'string':
+                    $returnEmptyType  = '';
+                    break;
+                case 'array':
+                    $returnEmptyType  = [];
+                    break;
+                default:
+                    return null;
+            }
+
+            return $returnEmptyType;
+        }
+
+        return null;
+    }
+}

+ 57 - 0
core/DependencyInjection/DependencyInjection.php

@@ -0,0 +1,57 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\DependencyInjection;
+
+/**
+ * Class DependencyInjection
+ * @package ModulesGarden\Servers\ProxmoxVps\Core\DependencyInjection
+ */
+class DependencyInjection
+{
+    /**
+     * @param null $className
+     * @param null $methodName
+     * @param bool $canClone
+     * @return mixed
+     */
+    public static function get($className = null, $methodName = null, $canClone = true)
+    {
+        if($methodName)
+        {
+            return Container::getInstance()->call("$className@$methodName");
+        }
+
+        return Container::getInstance()->make($className);
+    }
+
+    /**
+     * @param null $className
+     * @param null $methodName
+     * @param bool $canClone
+     * @return mixed
+     */
+    public static function create($className = null, $methodName = null, $canClone = true)
+    {
+        if($methodName)
+        {
+            return Container::getInstance()->call("$className@$methodName");
+        }
+
+        return Container::getInstance()->make($className);
+    }
+
+    /**
+     * @param null $className
+     * @param null $methodName
+     * @return mixed
+     */
+    public static function call($className = null, $methodName = null)
+    {
+        if($methodName)
+        {
+            return Container::getInstance()->call("$className@$methodName");
+        }
+
+        return Container::getInstance()->make($className);
+    }
+}

+ 63 - 0
core/DependencyInjection/Services.php

@@ -0,0 +1,63 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\DependencyInjection;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\ModuleConstants;
+use ModulesGarden\Servers\ProxmoxVps\Core\FileReader\Reader;
+
+/**
+ * Load all services from yml file and mark them as shared in DI container
+ * @author Mariusz Miodowski <mariusz@modulesgarden.com>
+ * @package ModulesGarden\DomainOrdersExtended\Core\Services
+ */
+class Services
+{
+    /**
+     * Services constructor.
+     */
+    public function __construct()
+    {
+        $this->load();
+    }
+
+    /**
+     * Load all needed servies to DI container
+     */
+    protected function load()
+    {
+        foreach($this->getFilesList() as $file)
+        {
+            $servicesList   = Reader::read($file)->get();;
+            if(!is_array($servicesList) || empty($servicesList))
+            {
+                continue;
+            }
+
+            $this->registerServices($servicesList);
+        }
+    }
+
+    /**
+     * Register all services in DI container
+     * @param $servicesList
+     */
+    protected function registerServices($servicesList)
+    {
+        foreach($servicesList as $service)
+        {
+            Container::getInstance()->singleton($service);
+        }
+    }
+
+    /**
+     * Get file list with servies configuration
+     * @return array
+     */
+    protected function getFilesList()
+    {
+        return [
+            ModuleConstants::getFullPath('app', 'Config', 'di', 'services.yml'),
+            ModuleConstants::getFullPath('core', 'Config', 'di', 'services.yml')
+        ];
+    }
+}

+ 36 - 0
core/Enum/Enum.php

@@ -0,0 +1,36 @@
+<?php
+
+/* * ********************************************************************
+ * ProxmoxVps product developed. (Jan 8, 2019)
+ * *
+ *
+ *  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\ProxmoxVps\Core\Enum;
+
+/**
+ * Description of Enum
+ *
+ * @author Pawel Kopec <pawelk@modulesgardne.com>
+ */
+abstract class Enum
+{
+    static function getKeys(){
+        $class = new \ReflectionClass(get_called_class());
+        return array_keys($class->getConstants());
+    }
+
+
+}

+ 33 - 0
core/Enum/Level.php

@@ -0,0 +1,33 @@
+<?php
+
+/* * ********************************************************************
+ * ProxmoxVps product developed. (Jan 8, 2019)
+ * *
+ *
+ *  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\ProxmoxVps\Core\Enum;
+
+/**
+ * Description of Level
+ *
+ * @author Pawel Kopec <pawelk@modulesgardne.com>
+ */
+final class Level extends Enum
+{
+    const LOW     = "low";
+    const MEDIUM  = "medium";
+    const HIGHT   = "hight";
+}

+ 37 - 0
core/Enum/Status.php

@@ -0,0 +1,37 @@
+<?php
+
+/* * ********************************************************************
+ * ProxmoxVps product developed. (Jan 8, 2019)
+ * *
+ *
+ *  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\ProxmoxVps\Core\Enum;
+
+/**
+ * Description of Status
+ *
+ * @author Pawel Kopec <pawelk@modulesgardne.com>
+ */
+final class Status extends Enum
+{
+
+    const DEBUG    = "debug";
+    const ERROR    = "error";
+    const INFO     = "info";
+    const SUCCESS  = "success";
+    const CRITICAL = "critical";
+    
+}

+ 47 - 0
core/Enum/StatusColor.php

@@ -0,0 +1,47 @@
+<?php
+
+/* * ********************************************************************
+ * ProxmoxVps product developed. (Jan 23, 2019)
+ * *
+ *
+ *  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\ProxmoxVps\Core\Enum;
+
+/**
+ * Description of StatusColor
+ *
+ * @author Pawel Kopec <pawelk@modulesgardne.com>
+ */
+final class StatusColor extends Enum
+{
+    const PENDING   = "f89406";
+    const ACTIVE    = "46a546";
+    const COMPLETED = "008b8b";
+    const SUSPENDED = "0768b8";
+    const CANCELLED = "bfbfbf";
+    const FRAUD     = "000";
+    
+    public static function getColors(){
+        return [
+            "Pending"   => self::PENDING,
+            "Active"    => self::ACTIVE,
+            "Completed" => self::COMPLETED,
+            "Suspended" => self::SUSPENDED,
+            "Cancelled" => self::CANCELLED,
+            "Fraud"     => self::FRAUD
+        ];
+    }
+}

+ 80 - 0
core/Events/Dispatcher.php

@@ -0,0 +1,80 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\Events;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\DependencyInjection;
+use ModulesGarden\Servers\ProxmoxVps\Core\DependencyInjection\Container;
+use ModulesGarden\Servers\ProxmoxVps\Core\ModuleConstants;
+use ModulesGarden\Servers\ProxmoxVps\Core\Queue\DatabaseQueue;
+
+class Dispatcher extends \Illuminate\Events\Dispatcher
+{
+    public function __construct(Container $container)
+    {
+        $this->container    = $container;
+
+        $this->initialize();
+    }
+
+    /**
+     *
+     */
+    protected function initialize()
+    {
+        /**
+         * Load available events
+         */
+        $path   = ModuleConstants::getFullPath('app', 'Config', 'events.php');
+        $config = include($path);
+
+
+        foreach($config as $event => $listeners)
+        {
+            foreach($listeners as $listener)
+            {
+                $this->listen($event, $listener);
+            }
+        }
+
+        /**
+         * Set queue resolver
+         */
+        $this->setQueueResolver(function(){
+            return DependencyInjection::create(DatabaseQueue::class);
+        });
+    }
+
+    /**
+     * @param $class
+     * @param $arguments
+     */
+    public function queue($class, $arguments, $parentId = null, $relType = null, $relId = null, $customId = null)
+    {
+        $class  = implode('@', $this->parseClassCallable($class));
+
+        return $this->resolveQueue()->push("$class", serialize($arguments), $parentId, $relType, $relId, $customId);
+    }
+
+    /**
+     * @param $class
+     * @param $method
+     * @override
+     * @return \Closure
+     */
+    protected function createQueuedHandlerCallable($class, $method)
+    {
+        return function () use ($class, $method)
+        {
+            $arguments = $this->cloneArgumentsForQueueing(func_get_args());
+
+            if (method_exists($class, 'queue'))
+            {
+                $this->callQueueMethodOnHandler($class, $method, $arguments);
+            }
+            else
+            {
+                $this->resolveQueue()->push("{$class}@{$method}", serialize($arguments));
+            }
+        };
+    }
+}

+ 8 - 0
core/Events/Event.php

@@ -0,0 +1,8 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\Events;
+
+class Event
+{
+
+}

+ 8 - 0
core/Events/Listener.php

@@ -0,0 +1,8 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\Events;
+
+class Listener
+{
+
+}

+ 41 - 0
core/FileReader/Directory.php

@@ -0,0 +1,41 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\FileReader;
+
+/**
+ * Description of Directory
+ *
+ * @author INBSX-37H
+ */
+class Directory extends PathValidator
+{
+    public function getFilesList($path, $extension = null, $trimExtensions = false)
+    {
+        if (!$this->pathExists($path) || !$this->isPathReadable($path))
+        {
+            return [];
+        }
+
+        $list = [];
+        $files = scandir($path, 1);
+        if (!$files)
+        {
+            return [];
+        }
+
+        foreach ($files as $key => $value)
+        {
+            //remove dots and a files with unwanted extensions
+            if ($value === "." || $value === ".." || 
+                    (is_string($extension) && $extension !=='' && !(stripos($value, $extension) > 0)))
+            {
+                unset($files[$key]);
+                continue;
+            }
+
+            $list[] = $trimExtensions ? str_replace($extension, '', $value) : $value;
+        }
+
+        return $list;
+    }
+}

+ 68 - 0
core/FileReader/File.php

@@ -0,0 +1,68 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\FileReader;
+
+/**
+ * Description of File
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class File
+{
+    public static function createFile()
+    {
+        // next version
+    }
+
+    public static function createPaths()
+    {
+        foreach (func_get_args() as $path)
+        {
+            if (is_array($path) && isset($path['permission']) && self::createPath($path['full'], $path['permission']) === false)
+            {
+                $parentPath = explode(DS, $path['full']);
+                array_pop($pathFull);
+                $parentPath = implode(DS, $parentPath);
+                self::setPermission($parentPath);
+                self::setUser($path['full'], 'www-data');
+                self::createPath($path['full'], $path['permission']);
+            }
+            elseif (is_array($path) && self::createPath($path['full']) === false)
+            {
+                $parentPath = explode(DS, $path['full']);
+                array_pop($pathFull);
+                $parentPath = implode(DS, $parentPath);
+                self::setPermission($parentPath);
+                self::setUser($path['full'], 'www-data');
+                self::createPath($path['full']);
+            }
+            else
+            {
+                self::createPath($path);
+            }
+        }
+    }
+
+    public static function createPath($path, $permission = 0777)
+    {
+        return mkdir($path, $permission);
+    }
+
+    public static function setPermission($file, $permission = 0777)
+    {
+        return chmod($file, $permission);
+    }
+
+    public static function setUser($file, $user)
+    {
+        return chown($file, $user);
+    }
+
+    /**
+     * @return PathValidator
+     */
+    public static function getValidator()
+    {
+        return new PathValidator();
+    }
+}

+ 85 - 0
core/FileReader/PathValidator.php

@@ -0,0 +1,85 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\FileReader;
+
+/**
+ * Wrapper for files and directories validation methods
+ *
+ * @author Sławomir Miśkowicz <slawomir@modulesgarden.com>
+ */
+class PathValidator
+{
+    /**
+     * @param string $path -a a path to be validated, can be a file path or a dir path
+     * @param bool $isReadable - states if path should be readable
+     * @param bool $isWritable - states if path should be writable
+     * @param bool $create - states if should try to create a directory if not exists
+     * @return bool
+     */
+    public function validatePath($path = "", $isReadable = true, $isWritable = false, $create = true)
+    {
+        //try to create a dir if does not exist
+        if ($create)
+        {
+            $this->createDirIfNotExists($path);
+        }
+
+        //if path does not exists
+        if (!$this->pathExists($path))
+        {
+            return false;
+        }
+
+        //if should be readable and it is not
+        if ($isReadable && !$this->isPathReadable($path))
+        {
+            return false;
+        }
+
+        //if should be writable and it is not
+        if ($isWritable && !$this->isPathWritable($path))
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * @param string $path - if provided path does not exist, a dir will be created
+     */
+    public function createDirIfNotExists($path)
+    {
+        if (!$this->pathExists($path))
+        {
+            mkdir($path);
+        }
+    }
+
+    /**
+     * @param string $path -a a path to be validated, can be a file path or a dir path
+     * @return bool
+     */
+    public function pathExists($path)
+    {
+        return file_exists($path);
+    }
+
+    /**
+     * @param $path -a a path to be validated, can be a file path or a dir path
+     * @return bool
+     */
+    public function isPathReadable($path)
+    {
+        return is_readable($path);
+    }
+
+    /**
+     * @param $path -a a path to be validated, can be a file path or a dir path
+     * @return bool
+     */
+    public function isPathWritable($path)
+    {
+        return is_writable($path);
+    }
+}

+ 84 - 0
core/FileReader/Reader.php

@@ -0,0 +1,84 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\FileReader;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\FileReader\Reader\Ini;
+use ModulesGarden\Servers\ProxmoxVps\Core\FileReader\Reader\Json;
+use ModulesGarden\Servers\ProxmoxVps\Core\FileReader\Reader\Xml;
+use ModulesGarden\Servers\ProxmoxVps\Core\FileReader\Reader\Yml;
+use ModulesGarden\Servers\ProxmoxVps\Core\FileReader\Reader\Php;
+use ModulesGarden\Servers\ProxmoxVps\Core\FileReader\Reader\Sql;
+use ModulesGarden\Servers\ProxmoxVps\Core\FileReader\Reader\Js;
+use ModulesGarden\Servers\ProxmoxVps\Core\FileReader\Reader\Css;
+use ModulesGarden\Servers\ProxmoxVps\Core\FileReader\Reader\Html;
+use ModulesGarden\Servers\ProxmoxVps\Core\FileReader\Reader\AbstractType;
+
+/**
+ * Description of Reader
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Reader
+{
+
+    /**
+     * @param string $file
+     * @return AbstractType
+     */
+    public static function read($file, array $renderData = [])
+    {
+        $path = explode(DIRECTORY_SEPARATOR, $file);
+        $file = end($path);
+        array_pop($path);
+        $path = implode(DIRECTORY_SEPARATOR, $path);
+        $instance = null;
+        $type = self::getType($file);
+
+        switch ($type)
+        {
+            case "xml":
+                $instance = new Xml($file, $path, $renderData);
+                break;
+            case "ini":
+                $instance = new Ini($file, $path, $renderData);
+                break;
+            case "yml":
+                $instance = new Yml($file, $path, $renderData);
+                break;
+            case "json":
+                $instance = new Json($file, $path, $renderData);
+                break;
+            case "php":
+                $instance = new Php($file, $path, $renderData);
+                break;
+            case "sql":
+                $instance = new Sql($file, $path, $renderData);
+                break;
+            case "js":
+                $instance = new Js($file, $path, $renderData);
+                break;
+            case "css":
+                $instance = new Css($file, $path, $renderData);
+                break;
+            case "html":
+                $instance = new Html($file, $path, $renderData);
+                break;
+            default:
+                throw new \Exception('Can\'t read file: ' . $file);
+        }
+
+        return $instance;
+    }
+
+    private static function getType($file)
+    {
+        $type  = null;
+        $array = explode('.', $file);
+        if (is_array($array))
+        {
+            $type = end($array);
+        }
+
+        return strtolower($type);
+    }
+}

+ 49 - 0
core/FileReader/Reader/AbstractType.php

@@ -0,0 +1,49 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\FileReader\Reader;
+
+/**
+ * Description of AbstractType
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+abstract class AbstractType
+{
+    protected $data = [];
+    protected $renderData = [];
+    protected $file = '';
+    protected $path = '';
+
+    public function __construct($file, $path, $renderData = [])
+    {
+        $this->file       = $file;
+        $this->path       = $path;
+        $this->renderData = $renderData;
+        $this->loadFile();
+    }
+
+    abstract protected function loadFile();
+
+    public function get($key = null, $default = null)
+    {
+        if ($key == null)
+        {
+            return $this->data;
+        }
+
+        if ($this->isExist($key))
+        {
+            return $this->data[$key];
+        }
+
+        return $default;
+    }
+
+    protected function isExist($key)
+    {
+        if (isset($this->data[$key]) || array_key_exists($key, $this->data))
+        {
+            return true;
+        }
+    }
+}

+ 36 - 0
core/FileReader/Reader/Css.php

@@ -0,0 +1,36 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\FileReader\Reader;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\ServiceLocator;
+
+/**
+ * Description of Json
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Css extends AbstractType
+{
+
+    protected function loadFile()
+    {
+        $return = '';
+        try
+        {
+            if (file_exists($this->path . DS . $this->file))
+            {
+                $return = file_get_contents($this->path . DS . $this->file);
+                foreach ($this->renderData as $key => $value)
+                {
+                    $return = str_replace("#$key#", $value, $return);
+                }
+            }
+        }
+        catch (\Exception $e)
+        {
+            ServiceLocator::call('errorManager')->addError(self::class, $e->getMessage(), $e->getTrace());
+        }
+
+        $this->data = $return;
+    }
+}

+ 36 - 0
core/FileReader/Reader/Html.php

@@ -0,0 +1,36 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\FileReader\Reader;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\ServiceLocator;
+
+/**
+ * Description of Json
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Html extends AbstractType
+{
+
+    protected function loadFile()
+    {
+        $return = '';
+        try
+        {
+            if (file_exists($this->path . DS . $this->file))
+            {
+                $return = file_get_contents($this->path . DS . $this->file);
+                foreach ($this->renderData as $key => $value)
+                {
+                    $return = str_replace("#$key#", $value, $return);
+                }
+            }
+        }
+        catch (\Exception $e)
+        {
+            ServiceLocator::call('errorManager')->addError(self::class, $e->getMessage(), $e->getTrace());
+        }
+
+        $this->data = $return;
+    }
+}

+ 35 - 0
core/FileReader/Reader/Ini.php

@@ -0,0 +1,35 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\FileReader\Reader;
+
+use Piwik\Ini\IniReader;
+use Piwik\Ini\IniReadingException;
+use ModulesGarden\Servers\ProxmoxVps\Core\ServiceLocator;
+
+/**
+ * Description of Ini
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Ini extends AbstractType
+{
+
+    protected function loadFile()
+    {
+        $return = [];
+        $reader = new IniReader();
+        try
+        {
+            if (file_exists($this->path . DS . $this->file))
+            {
+                $return = $reader->readFile($this->path . DS . $this->file);
+            }
+        }
+        catch (IniReadingException $e)
+        {
+            ServiceLocator::call('errorManager')->addError(self::class, $e->getMessage(), $e->getTrace());
+        }
+
+        $this->data = $return;
+    }
+}

+ 36 - 0
core/FileReader/Reader/Js.php

@@ -0,0 +1,36 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\FileReader\Reader;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\ServiceLocator;
+
+/**
+ * Description of Json
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Js extends AbstractType
+{
+
+    protected function loadFile()
+    {
+        $return = '';
+        try
+        {
+            if (file_exists($this->path . DS . $this->file))
+            {
+                $return = file_get_contents($this->path . DS . $this->file);
+                foreach ($this->renderData as $key => $value)
+                {
+                    $return = str_replace("#$key#", $value, $return);
+                }
+            }
+        }
+        catch (\Exception $e)
+        {
+            ServiceLocator::call('errorManager')->addError(self::class, $e->getMessage(), $e->getTrace());
+        }
+
+        $this->data = $return;
+    }
+}

+ 33 - 0
core/FileReader/Reader/Json.php

@@ -0,0 +1,33 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\FileReader\Reader;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\ServiceLocator;
+
+/**
+ * Description of Json
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Json extends AbstractType
+{
+
+    protected function loadFile()
+    {
+        $return = [];
+        try
+        {
+            if (file_exists($this->path . DS . $this->file))
+            {
+                $readFile = file_get_contents($this->path . DS . $this->file);
+                $return   = json_decode($readFile, true);
+            }
+        }
+        catch (\Exception $e)
+        {
+            ServiceLocator::call('errorManager')->addError(self::class, $e->getMessage(), $e->getTrace());
+        }
+
+        $this->data = $return;
+    }
+}

+ 36 - 0
core/FileReader/Reader/Php.php

@@ -0,0 +1,36 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\FileReader\Reader;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\ServiceLocator;
+
+/**
+ * Description of Json
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Php extends AbstractType
+{
+
+    protected function loadFile()
+    {
+        $return = '';
+        try
+        {
+            if (file_exists($this->path . DS . $this->file))
+            {
+                $return = file_get_contents($this->path . DS . $this->file);
+                foreach ($this->renderData as $key => $value)
+                {
+                    $return = str_replace("#$key#", $value, $return);
+                }
+            }
+        }
+        catch (\Exception $e)
+        {
+            ServiceLocator::call('errorManager')->addError(self::class, $e->getMessage(), $e->getTrace());
+        }
+
+        $this->data = $return;
+    }
+}

+ 70 - 0
core/FileReader/Reader/Sql.php

@@ -0,0 +1,70 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\FileReader\Reader;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\ServiceLocator;
+use ModulesGarden\Servers\ProxmoxVps\Core\ModuleConstants;
+
+/**
+ * Description of Sql
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Sql extends AbstractType
+{
+
+    protected function loadFile()
+    {
+        $return = '';
+        try
+        {
+            if (file_exists($this->path . DS . $this->file))
+            {
+                $collation = $this->getWHMCSTablesCollation();
+                $charset   = $this->getWHMCSTablesCharset();
+                $return = file_get_contents($this->path . DS . $this->file);
+                $return = str_replace("#collation#", $collation, $return);
+                $return = str_replace("#charset#", $charset, $return);
+                $return = str_replace("#prefix#", ModuleConstants::getPrefixDataBase(), $return);
+                foreach ($this->renderData as $key => $value)
+                {
+                    $return = str_replace("#$key#", $value, $return);
+                }
+            }
+        }
+        catch (\Exception $e)
+        {
+            ServiceLocator::call('errorManager')->addError(self::class, $e->getMessage(), $e->getTrace());
+        }
+
+        $this->data = $return;
+    }
+
+    protected function getWHMCSTablesCollation()
+    {
+        $pdo       = \Illuminate\Database\Capsule\Manager::connection()->getPdo();
+        $query = $pdo->prepare("SHOW TABLE STATUS WHERE name = 'tblclients'");
+        $query->execute();
+        $result = $query->fetchObject();
+
+        return $result->Collation;
+    }
+
+    protected function getWHMCSTablesCharset()
+    {
+        require ROOTDIR . DS . 'configuration.php';
+
+        $pdo = \Illuminate\Database\Capsule\Manager::connection()->getPdo();
+
+        $query = $pdo->prepare("SELECT CCSA.character_set_name as Charset FROM information_schema.`TABLES` T,
+            information_schema.`COLLATION_CHARACTER_SET_APPLICABILITY` CCSA
+            WHERE CCSA.collation_name = T.table_collation
+            AND T.table_schema = :db_name
+            AND T.table_name = 'tblclients';");
+
+        $query->execute(['db_name' => $db_name]);
+        $result = $query->fetchObject();
+
+        return $result->Charset;
+    }
+}

+ 23 - 0
core/FileReader/Reader/Xml.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\FileReader\Reader;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\ServiceLocator;
+
+/**
+ * Description of Xml
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Xml extends AbstractType
+{
+
+    protected function loadFile()
+    {
+
+        // https://packagist.org/packages/sabre/xml
+
+        $this->data = [];
+        ServiceLocator::call('errorManager')->addError(self::class, "First install composer sabre/xml", ['url' => 'https://packagist.org/packages/sabre/xml']);
+    }
+}

+ 46 - 0
core/FileReader/Reader/Yml.php

@@ -0,0 +1,46 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\FileReader\Reader;
+
+use Symfony\Component\Yaml\Yaml;
+use ModulesGarden\Servers\ProxmoxVps\Core\ServiceLocator;
+
+/**
+ * Description of Yml
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Yml extends AbstractType
+{
+
+    protected function loadFile()
+    {
+        $return = [];
+        try
+        {
+            if (file_exists($this->path . DS . $this->file))
+            {
+                $return = Yaml::parse(file_get_contents($this->path . DS . $this->file));
+                $return = array_map(self::class . '::replaceBackslash', $return ? : []);
+            }
+        }
+        catch (\Symfony\Component\Yaml\Exception\ParseException $e)
+        {
+            ServiceLocator::call('errorManager')->addError(self::class, $e->getMessage(), $e->getTrace());
+        }
+
+        $this->data = $return;
+    }
+
+    protected static function replaceBackslash($data)
+    {
+        if (is_array($data))
+        {
+            return array_map(self::class . '::replaceBackslash', $data);
+        }
+        else
+        {
+            return str_replace('\\\\', '\\', $data);
+        }
+    }
+}

+ 109 - 0
core/HandlerError/ErrorCodes/ErrorCode.php

@@ -0,0 +1,109 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\ErrorCodes;
+
+class ErrorCode
+{
+    use \ModulesGarden\Servers\ProxmoxVps\Core\Traits\Lang;
+
+    protected $code = null;
+    protected $message = null;
+    protected $token = null;
+    protected $logable = false;
+
+    public function __construct($code = null, $codeDetails = null, $token = null)
+    {
+        $this->setToken($token);
+        $this->setCode($code);
+
+        $this->setDetails($codeDetails);
+    }
+
+    /**
+     * @param null $code
+     */
+    public function setCode($code = null)
+    {
+        if (is_string($code))
+        {
+            $this->code = $code;
+        }
+    }
+
+    /**
+     * @param null $message
+     */
+    public function setMessage($message = null)
+    {
+        if (is_string($message) && $message !== '')
+        {
+            $this->message = $message;
+        }
+    }
+
+    /**
+     * @param null $token
+     */
+    public function setToken($token = null)
+    {
+        if (is_string($token))
+        {
+            $this->token = $token;
+        }
+    }
+
+    /**
+     * @return string
+     */
+    public function getCode()
+    {
+        return $this->code === null ? '' : $this->code;
+    }
+
+    /**
+     * @return string
+     */
+    public function getToken()
+    {
+        return $this->token === null ? '' : $this->token;
+    }
+
+    /**
+     * @return string
+     */
+    public function getMessage()
+    {
+        return $this->message === null ? '' : $this->message;
+    }
+
+    public function getRawErrorMessage()
+    {
+        return 'Error Code: ' . ($this->getCode() ? : 'none') . ' Error Token: ' . ($this->getToken() ? : 'none') . 'Error Message: ' . $this->getMessage() ? : 'none.';
+    }
+
+    public function setLogable($logable)
+    {
+        if (is_bool($logable))
+        {
+            $this->logable = $logable;
+        }
+    }
+
+    public function isLogable()
+    {
+        return $this->logable;
+    }
+
+    public function setDetails($codeDetails)
+    {
+        if (is_string($codeDetails))
+        {
+            $this->setMessage($codeDetails);
+
+            return;
+        }
+
+        $this->setMessage($codeDetails[ErrorCodes::MESSAGE]);
+        $this->setLogable($codeDetails[ErrorCodes::LOG]);
+    }
+}

+ 73 - 0
core/HandlerError/ErrorCodes/ErrorCodes.php

@@ -0,0 +1,73 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\ErrorCodes;
+
+abstract class ErrorCodes
+{
+    const MESSAGE       = 'message';
+    const LOG           = 'log';
+    const CODE          = 'code';
+    const DEV_MESSAGE   = 'dev_message';
+    
+    /**
+     * @param null $code
+     * @param null $errorToken
+     * @return ErrorCode|null
+     */
+    public function getErrorMessageByCode($code = null, $errorToken = null)
+    {
+        $constantName = get_class($this) . '::' . $code;
+        if (!defined($constantName))
+        {
+            return $this->getUndefinedErrorMessage($code, $errorToken);
+        }
+
+        return $this->getErrorCode($code, constant($constantName), $errorToken);
+    }
+
+    /**
+     * @param null|string $code
+     * @param null|string $errorToken
+     * @return ErrorCode|null
+     */
+    public function getUndefinedErrorMessage($code = null, $errorToken = null)
+    {
+        return $this->getErrorCode($code, 'Invalid Error Code!', $errorToken);
+    }
+
+    /**
+     * @param null|string $code
+     * @param null|string $message
+     * @param null|string $token
+     * @return ErrorCode|null
+     */
+    protected function getErrorCode($code = null, $message = null, $token = null)
+    {
+        $token = new ErrorCode($code, $message, ($token ? : $this->genToken()));
+
+        return $token;
+    }
+
+    /**
+     * returns a string
+     */
+    protected function genToken()
+    {
+        return md5(time());
+    }
+
+    /**
+     * @param null|string $code
+     * @return bool
+     */
+    public function errorCodeExists($code = null)
+    {
+        $constantName = get_class($this) . '::' . $code;
+        if (!defined($constantName))
+        {
+            return false;
+        }
+
+        return true;
+    }
+}

+ 122 - 0
core/HandlerError/ErrorCodes/ErrorCodesLib.php

@@ -0,0 +1,122 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\ErrorCodes;
+
+class ErrorCodesLib extends ErrorCodes
+{
+    const CORE_CT_000001 = 'Provided controller does not exists';
+    const CORE_CT_000002 = 'Provided controller does not exists';
+
+    const CORE_ACT_000001 = 'Database error';
+    const CORE_ACT_000002 = 'Database error';
+    const CORE_ACT_000003 = 'Database error';
+    const CORE_ACT_000004 = 'Database error';
+
+    /**
+     * Default error, used when no error code defined
+     */
+    const CORE_ERR_000001 = [
+        self::MESSAGE => 'Uncategorised error occured',
+        self::CODE => 'CORE_ERR_000001',
+        self::DEV_MESSAGE => "It's a default error code, used when no error code was specified"
+    ];
+
+    /**
+     * Logs class
+     */
+    const CORE_LOG_000001 = [
+        self::MESSAGE => 'Method does not exist in the Logger class',
+        self::CODE => 'CORE_LOG_000001',
+    ];
+
+    /**
+     * Register cache
+     */
+    const CORE_CREG_000001 = [
+        self::MESSAGE => 'Register key already exists',
+        self::CODE => 'CORE_CREG_000001',
+    ];
+
+    /**
+     * Database cache
+     */
+    const CORE_CDB_000001 = [
+        self::MESSAGE => 'The callback needs to ba a callable',
+        self::CODE => 'CORE_CDB_000001',
+    ];
+
+    /**
+     * GRAPHS
+     */
+    const CORE_GRA_000001 = [
+        self::MESSAGE => 'Tooltip mode does not exists',
+        self::CODE => 'CORE_GRA_000001',
+    ];
+
+    const CORE_GRA_000002 = [
+        self::MESSAGE => 'Width value is not numeric(:width:)',
+        self::CODE => 'CORE_GRA_000002',
+    ];
+
+    const CORE_GRA_000003 = [
+        self::MESSAGE => 'Height value is not numeric(:height:)',
+        self::CODE => 'CORE_GRA_000003',
+    ];
+
+    /**
+     * CURL
+     */
+    const CORE_CURL_000001 = [
+        self::MESSAGE => 'CURL error',
+        self::CODE => 'CORE_CURL_000001',
+    ];
+
+    const CORE_CURL_000002 = [
+        self::MESSAGE => 'CURL error',
+        self::CODE => 'CORE_CURL_000002',
+    ];
+
+    /**
+     * WHMCS API core lib
+     */
+    const CORE_WAPI_000001 = [
+        self::MESSAGE => 'No WHMCS files found',
+        self::CODE => 'CORE_WAPI_000001',
+    ];
+
+    const CORE_WAPI_000002 = [
+        self::MESSAGE => 'WHMCS API error',
+        self::CODE => 'CORE_WAPI_000002',
+    ];
+
+    const CORE_WAPI_000003 = [
+        self::MESSAGE => 'There is no admin with ID equal to ":adminId:"',
+        self::CODE => 'CORE_WAPI_000003',
+    ];
+
+    const CORE_WAPI_000004 = [
+        self::MESSAGE => 'WHMCS API error',
+        self::CODE => 'CORE_WAPI_000004',
+    ];
+
+    /**
+     * LIBS
+     */
+    const CORE_LIBS_DH_000001 = [
+        self::MESSAGE => 'The TLD is missing in tld.list file',
+        self::CODE => 'CORE_LIBS_DH_000001',
+    ];
+
+    /**
+     * WHMCS Service Package
+     */
+    const CORE_WS_000001 = [
+        self::MESSAGE => 'Invalid service ID',
+        self::CODE => 'CORE_WS_000001',
+    ];
+
+    const CORE_WS_000002 = [
+        self::MESSAGE => 'Invalid product ID',
+        self::CODE => 'CORE_WS_000001',
+    ];
+}

+ 263 - 0
core/HandlerError/ErrorManager.php

@@ -0,0 +1,263 @@
+<?php
+
+namespace ModulesGarden\Servers\ProxmoxVps\Core\HandlerError;
+
+use ModulesGarden\Servers\ProxmoxVps\Core\ServiceLocator;
+
+/**
+ * Description of ErrorManager
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class ErrorManager
+{
+    const TYPE_ERROR   = "Error";
+    const TYPE_WARNING = "Warning";
+    
+    protected static $lastToken = null;
+    
+    /**
+     * @var \ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Model\Error[]
+     */
+    protected static $errors = [];
+    
+    /**
+     * @var \ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Model\Warning[]
+     */
+    protected static $warnings = [];
+
+    /**
+     * @var \ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\WhmcsLogsHandler
+     */
+    protected static $whmcsLogger;
+
+
+    /**
+     * @var \ModulesGarden\Servers\ProxmoxVps\Core\Interfaces\LoggerInterface
+     */
+    protected $logger;
+    
+    /**
+     * @var bool
+     */
+    protected $withWarning = false;
+
+    /**
+     * @param Logger $logger
+     */
+    public function __construct(Logger $logger)
+    {
+        $this->logger = $logger;
+    }
+
+    /**
+     * @param string $classname
+     * @param string $message
+     * @param array $trace
+     */
+    public function addError($classname = null, $message = '', $trace = [])
+    {
+        $error = $this->createNewModel(self::TYPE_ERROR, $classname, $message, $trace);
+        $this->_addError($error)
+                ->logger->addError($error->getFullMessage(), $error->getTrace());
+        $this->getWhmcsLogger()->addModuleLog(
+            [
+                "type"    => "ERROR",
+                "class"   => $error->getClass(),
+                "message" => $error->getMessage(),
+                "data"    => $error->getTrace()
+            ]
+        );
+        
+        return $this;
+    }
+    
+    public  static function getLastErrorToken()
+    {
+        return self::$lastToken;
+    }
+
+    public  static function setLastErrorToken($token)
+    {
+        self::$lastToken = $token;
+        
+        return self;
+    }
+    
+    /**
+     * @return \ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Model\Error
+     */
+    public static function getFirstError()
+    {
+        return (count(self::$errors)>0)?self::$errors[0]:null;
+    }
+
+    /**
+     * @param string $classname
+     * @param string $message
+     * @param array $trace
+     */
+    public function addWarning($classname = null, $message = '', $trace = [])
+    {
+        $warning = $this->createNewModel(self::TYPE_WARNING, $classname, $message, $trace);
+        $this->_addWarning($warning)
+                ->logger->addWarning($warning->getFullMessage(), $warning->getTrace());
+        $this->getWhmcsLogger()->addModuleLog(
+            [
+                "type"    => "WARNING",
+                "class"   => $warning->getClass(),
+                "message" => $warning->getMessage(),
+                "data"    => $warning->getTrace()
+            ]
+        );
+        
+        return $this;
+    }
+
+    /**
+     * @return \ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Model\Error[]
+     */
+    public static function getErrors()
+    {
+        return self::$errors;
+    }
+    
+    /**
+     * @return \ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Model\Warning[]
+     */
+    public static function getWarnings()
+    {
+        return self::$warnings;
+    }
+    
+    public static function reset()
+    {
+        self::$warnings = [];
+        self::$errors   = [];
+        
+        return self;
+    }
+    
+    /**
+     * @return \ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\WhmcsLogsHandler
+     */
+    public function getWhmcsLogger()
+    {
+        if (isset(self::$whmcsLogger) === false)
+        {
+            self::$whmcsLogger = ServiceLocator::call("whmcsLogger");
+        }
+        
+        return self::$whmcsLogger;
+    }
+
+    /**
+     * @return bool
+     */
+    public function hesError()
+    {
+        return (bool) (count(self::$errors) != 0);
+    }
+    
+    /**
+     * @return bool
+     */
+    public function hesWarning()
+    {
+        return (bool) (count(self::$warnings) != 0);
+    }
+    
+    public function withWarnings()
+    {
+        $this->withWarning = true;
+        
+        return $this;
+    }
+    
+    public function withoutWarnings()
+    {
+        $this->withWarning = false;
+        
+        return $this;
+    }
+
+    /**
+     * @return string
+     */
+    public function __toString()
+    {
+        $string = '';
+        if (count(self::getErrors()) != 0 || (count(self::getWarnings()) != 0 ) && $this->withWarning)
+        {
+            $string .= '<div class="list-group">';
+            foreach (self::getErrors() as $error)
+            {
+                $string .= '<div class="alert alert-danger">';
+                $string .= '<h4>Class: <strong>';
+                $string .= $error->getClass();
+                $string .= '<span class="pull-right">' . $error->getDate() . " " . $error->getTime() . '</span>';
+                $string .= '</strong></h4>';
+                $string .= '<p>' . $error->getMessage() . '</p>';
+                $string .= '</div>';
+            }
+            if ($this->withWarning)
+            {
+                foreach (self::getWarnings() as $warning)
+                {
+                    $string .= '<div class="alert alert-warning">';
+                    $string .= '<h4>Class: <strong>';
+                    $string .= $warning->getClass();
+                    $string .= '<span class="pull-right">' . $warning->getDate() . " " . $warning->getTime() . '</span>';
+                    $string .= '</strong></h4>';
+                    $string .= '<p>' . $warning->getMessage() . '</p>';
+                    $string .= '</div>';
+                }
+            }
+            
+            $string      .= '</div>';
+            self::reset();
+        }
+        return $string;
+    }
+    
+    private function createNewModel($type = self::TYPE_ERROR, $class = "", $massage = "", $trace = [])
+    {
+        return $this->{"createNewModel".$type}($class, $massage, $trace);
+    }
+    
+    /**
+     * @param string $class
+     * @param string $massage
+     * @param array $trace
+     * @return \ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Model\Error
+     */
+    private function createNewModelError($class = "", $massage = "", $trace = [])
+    {
+        return new \ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Model\Error($class, $massage, $trace);
+    }
+    
+    /**
+     * @param string $class
+     * @param string $massage
+     * @param array $trace
+     * @return \ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Model\Warning
+     */
+    private function createNewModelWarning($class = "", $massage = "", $trace = [])
+    {
+        return new \ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Model\Error($class, $massage, $trace);
+    }
+    
+    protected function _addError(\ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Model\Error $error)
+    {
+        array_push(self::$errors, $error);
+        
+        return $this;
+    }
+    
+    protected function _addWarning(\ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Model\Warning $warning)
+    {
+        array_push(self::$warnings, $warning);
+        
+        return $this;
+    }
+}

部分文件因文件數量過多而無法顯示