From 6ee2744e3a61d3a3d4324214bb488ee3fa53c801 Mon Sep 17 00:00:00 2001 From: REDL Date: Thu, 30 Jul 2026 02:00:01 +0000 Subject: [PATCH] =?UTF-8?q?=D0=A1=D0=B1=D0=BE=D1=80=D0=BA=D0=B0=20REDL:=20?= =?UTF-8?q?=D0=BF=D0=B0=D0=BD=D0=B5=D0=BB=D1=8C=20=D0=BD=D0=B0=20PHP=208,?= =?UTF-8?q?=20=D0=BA=D0=B0=D0=BF=D1=87=D0=B0-=D1=82=D1=83=D0=BC=D0=B1?= =?UTF-8?q?=D0=BB=D0=B5=D1=80,=20=D0=B7=D0=B0=D0=BA=D1=80=D1=8B=D1=82?= =?UTF-8?q?=D1=8B=D0=B5=20=D1=83=D1=8F=D0=B7=D0=B2=D0=B8=D0=BC=D0=BE=D1=81?= =?UTF-8?q?=D1=82=D0=B8,=20=D1=83=D1=81=D1=82=D0=B0=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=D1=89=D0=B8=D0=BA=D0=B8=20=D0=B2=20=D0=BE=D0=B4=D0=B8=D0=BD=20?= =?UTF-8?q?=D0=BA=D0=BB=D0=B8=D0=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - панель работает на PHP 8.4 (оригинал под PHP 7.0): elFinder utf8_encode, apache_get_modules, warnings - капча выключена и управляется из админки (флаг captcha_enable + блок настроек) - закрыты две SQL-инъекции без авторизации (createAuthLog: пароль из POST и CF-Connecting-IP) - убрано хранение паролей в открытом виде в authlog, XSS в поле ref - установщики install-panel.sh и install-node.sh (оригинальный затирал sources.list репозиториями Debian 9) - современный Dockerfile (оригинальный на debian:stretch больше не собирается) - планировщик и автозапуск работают без systemd - брендинг REDL.IO, год 2026, ссылки на redl.io - документация на русском: ИЗМЕНЕНИЯ, БЕЗОПАСНОСТЬ, ИНСТРУКЦИЯ --- .gitignore | 8 + README.md | 154 + docker/Dockerfile | 48 + docker/Dockerfile.original-stretch | 19 + install-node.sh | 252 + install-panel.sh | 256 + panel/.htaccess | 7 + panel/LICENSE | 9 + panel/application/.htaccess | 1 + panel/application/config.php | 84 + .../application/controllers/account/bonus.php | 171 + .../application/controllers/account/error.php | 25 + .../controllers/account/invoices.php | 63 + .../application/controllers/account/login.php | 220 + .../controllers/account/logout.php | 28 + panel/application/controllers/account/pay.php | 564 + .../controllers/account/perevod.php | 101 + .../controllers/account/restore.php | 181 + .../controllers/account/success.php | 113 + .../application/controllers/account/waste.php | 48 + .../controllers/admin/checksys/index.php | 29 + .../controllers/admin/emailinfo/index.php | 72 + .../controllers/admin/games/create.php | 140 + .../controllers/admin/games/edit.php | 204 + .../controllers/admin/games/index.php | 47 + panel/application/controllers/admin/index.php | 62 + .../controllers/admin/infobox/index.php | 53 + .../controllers/admin/infobox/send.php | 91 + .../controllers/admin/invoices/index.php | 59 + .../controllers/admin/locations/create.php | 110 + .../controllers/admin/locations/edit.php | 171 + .../controllers/admin/locations/index.php | 47 + .../controllers/admin/mods/create.php | 117 + .../controllers/admin/mods/edit.php | 162 + .../controllers/admin/mods/index.php | 47 + .../controllers/admin/news/create.php | 79 + .../controllers/admin/news/edit.php | 135 + .../controllers/admin/news/index.php | 49 + .../controllers/admin/promo/create.php | 86 + .../controllers/admin/promo/edit.php | 142 + .../controllers/admin/promo/index.php | 47 + .../controllers/admin/repo/create.php | 104 + .../controllers/admin/repo/edit.php | 157 + .../controllers/admin/repo/index.php | 47 + .../controllers/admin/servers/control.php | 687 + .../controllers/admin/servers/index.php | 234 + .../controllers/admin/settings.php | 119 + .../controllers/admin/statistics/index.php | 76 + .../admin/ticketcategory/create.php | 81 + .../controllers/admin/ticketcategory/edit.php | 138 + .../admin/ticketcategory/index.php | 48 + .../controllers/admin/tickets/create.php | 93 + .../controllers/admin/tickets/index.php | 74 + .../controllers/admin/tickets/view.php | 254 + .../controllers/admin/users/edit.php | 196 + .../controllers/admin/users/index.php | 232 + .../controllers/admin/waste/index.php | 61 + .../controllers/admin/webhost/control.php | 185 + .../controllers/admin/webhost/index.php | 74 + .../controllers/admin/weblocations/create.php | 116 + .../controllers/admin/weblocations/edit.php | 180 + .../controllers/admin/weblocations/index.php | 47 + .../controllers/admin/webtarifs/create.php | 93 + .../controllers/admin/webtarifs/edit.php | 149 + .../controllers/admin/webtarifs/index.php | 47 + .../controllers/common/admheader.php | 89 + .../application/controllers/common/footer.php | 76 + .../application/controllers/common/header.php | 90 + .../controllers/common/loginfooter.php | 11 + .../controllers/common/loginheader.php | 300 + panel/application/controllers/common/main.php | 64 + .../controllers/contacts/index.php | 31 + panel/application/controllers/main/acc.php | 428 + panel/application/controllers/main/cron.php | 661 + panel/application/controllers/main/index.php | 51 + panel/application/controllers/news/index.php | 53 + panel/application/controllers/news/view.php | 96 + .../application/controllers/offline/index.php | 14 + .../application/controllers/result/anypay.php | 70 + panel/application/controllers/result/enot.php | 70 + .../controllers/result/freekassa.php | 69 + .../controllers/result/litekassa.php | 70 + panel/application/controllers/result/qiwi.php | 98 + .../controllers/result/robokassa.php | 69 + .../controllers/result/unitpay.php | 105 + .../controllers/result/yandexkassa.php | 78 + .../controllers/servers/autoinstall.php | 260 + .../controllers/servers/config.php | 168 + .../controllers/servers/console.php | 371 + .../controllers/servers/control.php | 1257 + .../controllers/servers/firewall.php | 233 + panel/application/controllers/servers/ftp.php | 344 + .../application/controllers/servers/index.php | 208 + .../application/controllers/servers/mysql.php | 246 + .../application/controllers/servers/order.php | 281 + .../application/controllers/servers/owner.php | 210 + .../application/controllers/servers/repo.php | 183 + .../controllers/servers/statistics.php | 109 + .../application/controllers/servers/tasks.php | 216 + .../application/controllers/status/index.php | 76 + .../controllers/tickets/create.php | 131 + panel/application/controllers/tickets/faq.php | 38 + .../application/controllers/tickets/index.php | 70 + .../application/controllers/tickets/view.php | 297 + .../controllers/webhost/control.php | 223 + .../application/controllers/webhost/index.php | 49 + .../application/controllers/webhost/order.php | 216 + panel/application/models/games.php | 112 + panel/application/models/invoices.php | 123 + panel/application/models/locations.php | 100 + panel/application/models/mail.php | 109 + panel/application/models/news.php | 115 + panel/application/models/newsMessages.php | 116 + panel/application/models/promos.php | 99 + panel/application/models/servers.php | 1671 + panel/application/models/tickets.php | 135 + panel/application/models/ticketsCategory.php | 113 + panel/application/models/ticketsMessages.php | 116 + panel/application/models/users.php | 284 + panel/application/models/waste.php | 117 + panel/application/models/webLocations.php | 101 + panel/application/models/webhost.php | 314 + panel/application/models/webhostTarifs.php | 102 + panel/application/public/.htaccess | 1 + .../application/public/css/elfinder.full.css | 5351 + .../css/elfinderT/Material/css/theme-gray.css | 1729 + .../elfinderT/Material/css/theme-light.css | 1729 + .../css/elfinderT/Material/css/theme.css | 1729 + .../css/elfinderT/Material/icons/material.eot | Bin 0 -> 24708 bytes .../css/elfinderT/Material/icons/material.svg | 195 + .../css/elfinderT/Material/icons/material.ttf | Bin 0 -> 24540 bytes .../elfinderT/Material/icons/material.woff | Bin 0 -> 14416 bytes .../elfinderT/Material/icons/material.woff2 | Bin 0 -> 11844 bytes .../elfinderT/Material/images/icons-big.svg | 1 + .../elfinderT/Material/images/icons-small.svg | 1 + .../css/elfinderT/Material/images/loading.svg | 37 + .../css/elfinderT/default/css/theme.css | 430 + .../public/img/elfinder/arrows-active.png | Bin 0 -> 152 bytes .../public/img/elfinder/arrows-normal.png | Bin 0 -> 169 bytes .../application/public/img/elfinder/crop.gif | Bin 0 -> 323 bytes .../public/img/elfinder/dialogs.png | Bin 0 -> 5818 bytes .../public/img/elfinder/edit_aceeditor.png | Bin 0 -> 514 bytes .../public/img/elfinder/edit_ckeditor.png | Bin 0 -> 729 bytes .../public/img/elfinder/edit_ckeditor5.png | Bin 0 -> 141 bytes .../public/img/elfinder/edit_codemirror.png | Bin 0 -> 528 bytes .../img/elfinder/edit_creativecloud.png | Bin 0 -> 659 bytes .../img/elfinder/edit_onlineconvert.png | Bin 0 -> 934 bytes .../public/img/elfinder/edit_pixlreditor.png | Bin 0 -> 882 bytes .../public/img/elfinder/edit_pixlrexpress.png | Bin 0 -> 927 bytes .../public/img/elfinder/edit_simplemde.png | Bin 0 -> 144 bytes .../public/img/elfinder/edit_tinymce.png | Bin 0 -> 242 bytes .../public/img/elfinder/edit_tuiimgedit.png | Bin 0 -> 189 bytes .../public/img/elfinder/edit_zohooffice.png | Bin 0 -> 460 bytes .../public/img/elfinder/editor-icons.png | Bin 0 -> 2719 bytes .../public/img/elfinder/icons-big.png | Bin 0 -> 6880 bytes .../public/img/elfinder/icons-big.svg | 1 + .../public/img/elfinder/icons-small.png | Bin 0 -> 3674 bytes .../application/public/img/elfinder/logo.png | Bin 0 -> 4893 bytes .../public/img/elfinder/progress.gif | Bin 0 -> 667 bytes .../public/img/elfinder/quicklook-bg.png | Bin 0 -> 71 bytes .../public/img/elfinder/quicklook-icons.png | Bin 0 -> 1604 bytes .../public/img/elfinder/resize.png | Bin 0 -> 83 bytes .../public/img/elfinder/spinner-mini.gif | Bin 0 -> 1434 bytes .../public/img/elfinder/toolbar.png | Bin 0 -> 7506 bytes .../public/img/elfinder/trashmesh.png | Bin 0 -> 164 bytes .../public/img/elfinder/tui-icon-a.svg | 235 + .../public/img/elfinder/tui-icon-b.svg | 224 + .../public/img/elfinder/tui-icon-c.svg | 224 + .../public/img/elfinder/tui-icon-d.svg | 224 + .../img/elfinder/ui-icons_ffffff_256x240.png | Bin 0 -> 3759 bytes .../public/img/elfinder/volume_icon_box.png | Bin 0 -> 621 bytes .../public/img/elfinder/volume_icon_box.svg | 1 + .../img/elfinder/volume_icon_dropbox.png | Bin 0 -> 413 bytes .../img/elfinder/volume_icon_dropbox.svg | 1 + .../public/img/elfinder/volume_icon_ftp.png | Bin 0 -> 371 bytes .../public/img/elfinder/volume_icon_ftp.svg | 1 + .../img/elfinder/volume_icon_googledrive.png | Bin 0 -> 663 bytes .../img/elfinder/volume_icon_googledrive.svg | 1 + .../public/img/elfinder/volume_icon_local.png | Bin 0 -> 357 bytes .../public/img/elfinder/volume_icon_local.svg | 1 + .../img/elfinder/volume_icon_network.png | Bin 0 -> 872 bytes .../img/elfinder/volume_icon_network.svg | 1 + .../img/elfinder/volume_icon_onedrive.png | Bin 0 -> 204 bytes .../img/elfinder/volume_icon_onedrive.svg | 1 + .../public/img/elfinder/volume_icon_sql.png | Bin 0 -> 572 bytes .../public/img/elfinder/volume_icon_sql.svg | 1 + .../public/img/elfinder/volume_icon_trash.png | Bin 0 -> 706 bytes .../public/img/elfinder/volume_icon_trash.svg | 1 + .../public/img/elfinder/volume_icon_zip.png | Bin 0 -> 475 bytes .../public/img/elfinder/volume_icon_zip.svg | 1 + panel/application/public/img/error.gif | Bin 0 -> 181741 bytes panel/application/public/img/hostinpl.jpg | Bin 0 -> 161220 bytes panel/application/public/img/hostinpl56.png | Bin 0 -> 362305 bytes panel/application/public/img/pay/anypay.jpg | Bin 0 -> 12255 bytes panel/application/public/img/pay/enot.png | Bin 0 -> 7175 bytes .../application/public/img/pay/freekassa.png | Bin 0 -> 5222 bytes .../application/public/img/pay/interkassa.png | Bin 0 -> 8453 bytes .../application/public/img/pay/litekassa.png | Bin 0 -> 7881 bytes panel/application/public/img/pay/qiwi.jpg | Bin 0 -> 19091 bytes .../application/public/img/pay/robokassa.jpg | Bin 0 -> 41984 bytes panel/application/public/img/pay/unitpay.jpg | Bin 0 -> 18546 bytes .../public/img/pay/yandexmoney.jpg | Bin 0 -> 16337 bytes panel/application/public/img/user.png | Bin 0 -> 19003 bytes panel/application/public/js/elfinder.min.js | 25 + .../public/js/extras/editors.default.js | 2644 + .../public/js/extras/editors.default.min.js | 2 + .../public/js/extras/quicklook.googledocs.js | 75 + .../js/extras/quicklook.googledocs.min.js | 1 + .../application/public/js/i18n/elfinder.ru.js | 581 + panel/application/public/js/jquery-ui.min.js | 13 + .../application/public/js/jquery.form.min.js | 7 + panel/application/public/js/main.js | 7 + .../public/js/proxy/elFinderSupportVer1.js | 408 + panel/application/public/js/proxy/proxy.php | 7 + .../public/js/worker/calcfilehash.js | 20 + .../public/js/worker/quicklook.tiff.js | 7 + .../public/js/worker/quicklook.unzip.js | 55 + panel/application/public/sounds/rm.wav | Bin 0 -> 92204 bytes panel/application/views/account/activate.php | 58 + panel/application/views/account/bonus.php | 115 + panel/application/views/account/complete.php | 41 + panel/application/views/account/error.php | 28 + panel/application/views/account/invoices.php | 110 + panel/application/views/account/login.php | 2 + panel/application/views/account/pay.php | 588 + panel/application/views/account/perevod.php | 55 + .../views/account/restore/complete.php | 41 + panel/application/views/account/success.php | 30 + panel/application/views/account/waste.php | 47 + .../views/admin/checksys/index.php | 153 + .../views/admin/emailinfo/index.php | 55 + .../application/views/admin/games/create.php | 97 + panel/application/views/admin/games/edit.php | 109 + panel/application/views/admin/games/index.php | 69 + panel/application/views/admin/index.php | 325 + .../application/views/admin/infobox/index.php | 52 + .../application/views/admin/infobox/send.php | 75 + .../views/admin/invoices/index.php | 55 + .../views/admin/locations/create.php | 75 + .../views/admin/locations/edit.php | 113 + .../views/admin/locations/index.php | 71 + panel/application/views/admin/mods/create.php | 106 + panel/application/views/admin/mods/edit.php | 86 + panel/application/views/admin/mods/index.php | 65 + panel/application/views/admin/news/create.php | 55 + panel/application/views/admin/news/edit.php | 60 + panel/application/views/admin/news/index.php | 55 + .../application/views/admin/promo/create.php | 81 + panel/application/views/admin/promo/edit.php | 84 + panel/application/views/admin/promo/index.php | 57 + panel/application/views/admin/repo/create.php | 73 + panel/application/views/admin/repo/edit.php | 83 + panel/application/views/admin/repo/index.php | 65 + .../views/admin/servers/control.php | 546 + .../application/views/admin/servers/index.php | 103 + panel/application/views/admin/settings.php | 450 + .../views/admin/statistics/index.php | 305 + .../views/admin/ticketcategory/create.php | 102 + .../views/admin/ticketcategory/edit.php | 105 + .../views/admin/ticketcategory/index.php | 98 + .../views/admin/tickets/create.php | 99 + .../application/views/admin/tickets/index.php | 99 + .../application/views/admin/tickets/view.php | 267 + panel/application/views/admin/users/edit.php | 271 + panel/application/views/admin/users/index.php | 161 + panel/application/views/admin/waste/index.php | 50 + .../views/admin/webhost/control.php | 276 + .../application/views/admin/webhost/index.php | 55 + .../views/admin/weblocations/create.php | 79 + .../views/admin/weblocations/edit.php | 117 + .../views/admin/weblocations/index.php | 67 + .../views/admin/webtarifs/create.php | 61 + .../views/admin/webtarifs/edit.php | 73 + .../views/admin/webtarifs/index.php | 65 + panel/application/views/common/admheader.php | 884 + panel/application/views/common/footer.php | 65 + panel/application/views/common/header.php | 557 + .../application/views/common/loginfooter.php | 25 + .../application/views/common/loginheader.php | 418 + panel/application/views/common/menuserver.php | 98 + panel/application/views/contacts/index.php | 46 + .../views/mail/account/change_email.php | 139 + .../views/mail/account/newpassword.php | 132 + .../views/mail/account/register.php | 140 + .../views/mail/account/register_activate.php | 140 + .../views/mail/account/restore.php | 139 + panel/application/views/mail/info/users.php | 130 + panel/application/views/mail/infobox/user.php | 130 + .../views/mail/servers/deleted.php | 137 + panel/application/views/mail/servers/lock.php | 129 + .../views/mail/servers/needPay.php | 129 + .../application/views/mail/servers/owner.php | 137 + .../views/mail/tickets/newMessage.php | 129 + .../views/mail/webhost/deleted.php | 137 + panel/application/views/mail/webhost/lock.php | 129 + .../views/mail/webhost/needPay.php | 129 + panel/application/views/main/acc.php | 577 + panel/application/views/main/error.php | 41 + panel/application/views/main/index.php | 99 + panel/application/views/news/index.php | 103 + panel/application/views/news/view.php | 150 + panel/application/views/news/view1.php | 153 + panel/application/views/offline/index.php | 41 + .../application/views/servers/autoinstall.php | 116 + panel/application/views/servers/config.php | 48 + panel/application/views/servers/console.php | 298 + panel/application/views/servers/control.php | 1019 + panel/application/views/servers/firewall.php | 178 + panel/application/views/servers/ftp.php | 300 + panel/application/views/servers/index.php | 149 + panel/application/views/servers/mysql.php | 267 + panel/application/views/servers/order.php | 407 + panel/application/views/servers/owner.php | 170 + panel/application/views/servers/repo.php | 96 + .../application/views/servers/statistics.php | 302 + panel/application/views/servers/tasks.php | 219 + panel/application/views/status/index.php | 115 + panel/application/views/tickets/create.php | 106 + panel/application/views/tickets/faq.php | 298 + panel/application/views/tickets/index.php | 82 + panel/application/views/tickets/view.php | 256 + panel/application/views/webhost/control.php | 299 + panel/application/views/webhost/index.php | 55 + panel/application/views/webhost/order.php | 308 + .../css/fonts/@fortawesome/fa-brands-400.eot | Bin 0 -> 136822 bytes .../css/fonts/@fortawesome/fa-brands-400.eot_ | Bin 0 -> 136822 bytes .../css/fonts/@fortawesome/fa-brands-400.svg | 3717 + .../css/fonts/@fortawesome/fa-brands-400.ttf | Bin 0 -> 136516 bytes .../css/fonts/@fortawesome/fa-brands-400.woff | Bin 0 -> 92136 bytes .../fonts/@fortawesome/fa-brands-400.woff2 | Bin 0 -> 78460 bytes .../css/fonts/@fortawesome/fa-regular-400.eot | Bin 0 -> 34350 bytes .../fonts/@fortawesome/fa-regular-400.eot_ | Bin 0 -> 34350 bytes .../css/fonts/@fortawesome/fa-regular-400.svg | 801 + .../css/fonts/@fortawesome/fa-regular-400.ttf | Bin 0 -> 34052 bytes .../fonts/@fortawesome/fa-regular-400.woff | Bin 0 -> 16772 bytes .../fonts/@fortawesome/fa-regular-400.woff2 | Bin 0 -> 13548 bytes .../css/fonts/@fortawesome/fa-solid-900.eot | Bin 0 -> 204814 bytes .../css/fonts/@fortawesome/fa-solid-900.eot_ | Bin 0 -> 204814 bytes .../css/fonts/@fortawesome/fa-solid-900.svg | 5028 + .../css/fonts/@fortawesome/fa-solid-900.ttf | Bin 0 -> 204528 bytes .../css/fonts/@fortawesome/fa-solid-900.woff | Bin 0 -> 104280 bytes .../css/fonts/@fortawesome/fa-solid-900.woff2 | Bin 0 -> 80300 bytes panel/assets/css/fonts/flaticon/Flaticon.eot | Bin 0 -> 75950 bytes panel/assets/css/fonts/flaticon/Flaticon.eot_ | Bin 0 -> 75950 bytes panel/assets/css/fonts/flaticon/Flaticon.svg | 2702 + panel/assets/css/fonts/flaticon/Flaticon.ttf | Bin 0 -> 75772 bytes panel/assets/css/fonts/flaticon/Flaticon.woff | Bin 0 -> 45580 bytes .../assets/css/fonts/flaticon2/Flaticon2.eot | Bin 0 -> 49358 bytes .../assets/css/fonts/flaticon2/Flaticon2.eot_ | Bin 0 -> 49358 bytes .../assets/css/fonts/flaticon2/Flaticon2.svg | 1491 + .../assets/css/fonts/flaticon2/Flaticon2.ttf | Bin 0 -> 49180 bytes .../assets/css/fonts/flaticon2/Flaticon2.woff | Bin 0 -> 29816 bytes .../assets/css/fonts/keenthemes-icons/Ki.eot | Bin 0 -> 11586 bytes .../assets/css/fonts/keenthemes-icons/Ki.eot_ | Bin 0 -> 11586 bytes .../assets/css/fonts/keenthemes-icons/Ki.svg | 344 + .../assets/css/fonts/keenthemes-icons/Ki.ttf | Bin 0 -> 11408 bytes .../assets/css/fonts/keenthemes-icons/Ki.woff | Bin 0 -> 6052 bytes .../css/fonts/line-awesome/la-brands-400.eot | Bin 0 -> 156260 bytes .../css/fonts/line-awesome/la-brands-400.eot_ | Bin 0 -> 156260 bytes .../css/fonts/line-awesome/la-brands-400.svg | 1313 + .../css/fonts/line-awesome/la-brands-400.ttf | Bin 0 -> 156072 bytes .../css/fonts/line-awesome/la-brands-400.woff | Bin 0 -> 98673 bytes .../fonts/line-awesome/la-brands-400.woff2 | Bin 0 -> 84772 bytes .../css/fonts/line-awesome/la-regular-400.eot | Bin 0 -> 33916 bytes .../fonts/line-awesome/la-regular-400.eot_ | Bin 0 -> 33916 bytes .../css/fonts/line-awesome/la-regular-400.svg | 467 + .../css/fonts/line-awesome/la-regular-400.ttf | Bin 0 -> 33724 bytes .../fonts/line-awesome/la-regular-400.woff | Bin 0 -> 15489 bytes .../fonts/line-awesome/la-regular-400.woff2 | Bin 0 -> 12900 bytes .../css/fonts/line-awesome/la-solid-900.eot | Bin 0 -> 226312 bytes .../css/fonts/line-awesome/la-solid-900.eot_ | Bin 0 -> 226312 bytes .../css/fonts/line-awesome/la-solid-900.svg | 2894 + .../css/fonts/line-awesome/la-solid-900.ttf | Bin 0 -> 226128 bytes .../css/fonts/line-awesome/la-solid-900.woff | Bin 0 -> 125421 bytes .../css/fonts/line-awesome/la-solid-900.woff2 | Bin 0 -> 96752 bytes panel/assets/css/fonts/socicon/socicon.eot | Bin 0 -> 52592 bytes panel/assets/css/fonts/socicon/socicon.eot_ | Bin 0 -> 52592 bytes panel/assets/css/fonts/socicon/socicon.svg | 178 + panel/assets/css/fonts/socicon/socicon.ttf | Bin 0 -> 52428 bytes panel/assets/css/fonts/socicon/socicon.woff | Bin 0 -> 38700 bytes .../css/fonts/summernote/summernote.eot | Bin 0 -> 12072 bytes .../css/fonts/summernote/summernote.eot_ | Bin 0 -> 12072 bytes .../css/fonts/summernote/summernote.ttf | Bin 0 -> 11896 bytes .../css/fonts/summernote/summernote.woff | Bin 0 -> 7428 bytes .../css/fonts/summernote/summernote.woff2 | Bin 0 -> 6156 bytes panel/assets/css/fullcalendar.bundle.css | 1312 + panel/assets/css/login-2.css | 36 + panel/assets/css/plugins.bundle.css | 25857 +++++ panel/assets/css/prismjs.bundle.css | 121 + panel/assets/css/style.bundle.css | 63635 ++++++++++ panel/assets/image/bg.jpg | Bin 0 -> 366266 bytes panel/assets/js/clipboard.js | 25 + panel/assets/js/fullcalendar.bundle.js | 14505 +++ panel/assets/js/login.js | 272 + panel/assets/js/plugins.bundle.js | 96517 ++++++++++++++++ panel/assets/js/prismjs.bundle.js | 1882 + panel/assets/js/scripts.bundle.js | 10942 ++ panel/assets/js/toastr.js.map | 8 + panel/assets/js/widgets.js | 1670 + panel/engine/.htaccess | 1 + panel/engine/database/mysql.php | 78 + panel/engine/engine_ftp/.tmp/.htaccess | 2 + panel/engine/engine_ftp/autoload.php | 55 + .../editors/OnlineConvert/editor.php | 113 + .../engine_ftp/editors/ZipArchive/editor.php | 12 + .../engine_ftp/editors/ZohoOffice/editor.php | 206 + panel/engine/engine_ftp/editors/editor.php | 79 + panel/engine/engine_ftp/elFinder.class.php | 5273 + .../engine_ftp/elFinderConnector.class.php | 380 + panel/engine/engine_ftp/elFinderPlugin.php | 113 + panel/engine/engine_ftp/elFinderSession.php | 337 + .../engine_ftp/elFinderSessionInterface.php | 57 + .../engine_ftp/elFinderVolumeBox.class.php | 1972 + .../engine_ftp/elFinderVolumeDriver.class.php | 7612 ++ .../engine_ftp/elFinderVolumeFTP.class.php | 1810 + .../engine_ftp/elFinderVolumeGroup.class.php | 315 + .../elFinderVolumeLocalFileSystem.class.php | 1442 + .../engine_ftp/elFinderVolumeTrash.class.php | 51 + panel/engine/engine_ftp/libs/GdBmp.php | 473 + panel/engine/engine_ftp/mime.types | 781 + .../engine_ftp/plugins/AutoResize/plugin.php | 151 + .../engine_ftp/plugins/AutoRotate/plugin.php | 148 + .../engine_ftp/plugins/Normalizer/plugin.php | 204 + .../engine_ftp/plugins/Sanitizer/plugin.php | 157 + .../engine_ftp/plugins/Watermark/logo.png | Bin 0 -> 8931 bytes .../engine_ftp/plugins/Watermark/plugin.php | 432 + panel/engine/fonts/tahoma.ttf | Bin 0 -> 697972 bytes panel/engine/games/game_settings.php | 73 + panel/engine/libs/SampRconAPI.php | 406 + panel/engine/libs/mail.php | 71 + panel/engine/libs/pagination.php | 81 + panel/engine/libs/query.php | 36 + panel/engine/libs/query/base.php | 37 + .../engine/libs/query/lgsl/lgsl_protocol.php | 4295 + panel/engine/libs/query/mine.driver.php | 51 + panel/engine/libs/query/mtasa.driver.php | 50 + panel/engine/libs/query/ragemp.driver.php | 50 + panel/engine/libs/query/samp.driver.php | 50 + panel/engine/libs/query/valve.driver.php | 50 + panel/engine/libs/seclib/Crypt/AES.php | 196 + panel/engine/libs/seclib/Crypt/Base.php | 2660 + panel/engine/libs/seclib/Crypt/Blowfish.php | 644 + panel/engine/libs/seclib/Crypt/DES.php | 1516 + panel/engine/libs/seclib/Crypt/Hash.php | 929 + panel/engine/libs/seclib/Crypt/RC2.php | 761 + panel/engine/libs/seclib/Crypt/RC4.php | 366 + panel/engine/libs/seclib/Crypt/RSA.php | 3285 + panel/engine/libs/seclib/Crypt/Random.php | 338 + panel/engine/libs/seclib/Crypt/Rijndael.php | 1050 + panel/engine/libs/seclib/Crypt/TripleDES.php | 517 + panel/engine/libs/seclib/Crypt/Twofish.php | 889 + panel/engine/libs/seclib/File/ANSI.php | 604 + panel/engine/libs/seclib/File/ASN1.php | 1561 + panel/engine/libs/seclib/File/X509.php | 5178 + panel/engine/libs/seclib/Math/BigInteger.php | 3833 + panel/engine/libs/seclib/Net/SCP.php | 378 + panel/engine/libs/seclib/Net/SFTP.php | 3226 + panel/engine/libs/seclib/Net/SFTP/Stream.php | 815 + panel/engine/libs/seclib/Net/SSH1.php | 1691 + panel/engine/libs/seclib/Net/SSH2.php | 5072 + panel/engine/libs/seclib/System/SSH/Agent.php | 561 + panel/engine/libs/seclib/System/SSH_Agent.php | 39 + panel/engine/libs/seclib/bootstrap.php | 16 + panel/engine/libs/seclib/openssl.cnf | 6 + panel/engine/libs/sftp.php | 38 + panel/engine/libs/ssh2.php | 43 + panel/engine/libs/validate.php | 113 + panel/engine/main/action.php | 94 + panel/engine/main/config.php | 29 + panel/engine/main/controller.php | 29 + panel/engine/main/cookie.php | 21 + panel/engine/main/db.php | 37 + panel/engine/main/document.php | 48 + panel/engine/main/game_settings.php | 25 + panel/engine/main/load.php | 64 + panel/engine/main/model.php | 21 + panel/engine/main/registry.php | 20 + panel/engine/main/request.php | 41 + panel/engine/main/response.php | 29 + panel/engine/main/session.php | 14 + panel/engine/main/user.php | 176 + panel/favicon.ico | Bin 0 -> 17092 bytes panel/hostinpl.sql | 809 + panel/index.php | 72 + panel/logo.png | Bin 0 -> 17092 bytes panel/tmp/.htaccess | 1 + panel/tmp/avatar/.gitkeep | 0 panel/tmp/mods/.gitkeep | 0 panel/tmp/tickets_img/.gitkeep | 0 БЕЗОПАСНОСТЬ.md | 241 + ИЗМЕНЕНИЯ.md | 200 + ИНСТРУКЦИЯ.md | 349 + 492 files changed, 354172 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 docker/Dockerfile create mode 100644 docker/Dockerfile.original-stretch create mode 100755 install-node.sh create mode 100755 install-panel.sh create mode 100644 panel/.htaccess create mode 100644 panel/LICENSE create mode 100644 panel/application/.htaccess create mode 100644 panel/application/config.php create mode 100644 panel/application/controllers/account/bonus.php create mode 100644 panel/application/controllers/account/error.php create mode 100644 panel/application/controllers/account/invoices.php create mode 100644 panel/application/controllers/account/login.php create mode 100644 panel/application/controllers/account/logout.php create mode 100644 panel/application/controllers/account/pay.php create mode 100644 panel/application/controllers/account/perevod.php create mode 100644 panel/application/controllers/account/restore.php create mode 100644 panel/application/controllers/account/success.php create mode 100644 panel/application/controllers/account/waste.php create mode 100644 panel/application/controllers/admin/checksys/index.php create mode 100644 panel/application/controllers/admin/emailinfo/index.php create mode 100644 panel/application/controllers/admin/games/create.php create mode 100644 panel/application/controllers/admin/games/edit.php create mode 100644 panel/application/controllers/admin/games/index.php create mode 100644 panel/application/controllers/admin/index.php create mode 100644 panel/application/controllers/admin/infobox/index.php create mode 100644 panel/application/controllers/admin/infobox/send.php create mode 100644 panel/application/controllers/admin/invoices/index.php create mode 100644 panel/application/controllers/admin/locations/create.php create mode 100644 panel/application/controllers/admin/locations/edit.php create mode 100644 panel/application/controllers/admin/locations/index.php create mode 100644 panel/application/controllers/admin/mods/create.php create mode 100644 panel/application/controllers/admin/mods/edit.php create mode 100644 panel/application/controllers/admin/mods/index.php create mode 100644 panel/application/controllers/admin/news/create.php create mode 100644 panel/application/controllers/admin/news/edit.php create mode 100644 panel/application/controllers/admin/news/index.php create mode 100644 panel/application/controllers/admin/promo/create.php create mode 100644 panel/application/controllers/admin/promo/edit.php create mode 100644 panel/application/controllers/admin/promo/index.php create mode 100644 panel/application/controllers/admin/repo/create.php create mode 100644 panel/application/controllers/admin/repo/edit.php create mode 100644 panel/application/controllers/admin/repo/index.php create mode 100644 panel/application/controllers/admin/servers/control.php create mode 100644 panel/application/controllers/admin/servers/index.php create mode 100644 panel/application/controllers/admin/settings.php create mode 100644 panel/application/controllers/admin/statistics/index.php create mode 100644 panel/application/controllers/admin/ticketcategory/create.php create mode 100644 panel/application/controllers/admin/ticketcategory/edit.php create mode 100644 panel/application/controllers/admin/ticketcategory/index.php create mode 100644 panel/application/controllers/admin/tickets/create.php create mode 100644 panel/application/controllers/admin/tickets/index.php create mode 100644 panel/application/controllers/admin/tickets/view.php create mode 100644 panel/application/controllers/admin/users/edit.php create mode 100644 panel/application/controllers/admin/users/index.php create mode 100644 panel/application/controllers/admin/waste/index.php create mode 100644 panel/application/controllers/admin/webhost/control.php create mode 100644 panel/application/controllers/admin/webhost/index.php create mode 100644 panel/application/controllers/admin/weblocations/create.php create mode 100644 panel/application/controllers/admin/weblocations/edit.php create mode 100644 panel/application/controllers/admin/weblocations/index.php create mode 100644 panel/application/controllers/admin/webtarifs/create.php create mode 100644 panel/application/controllers/admin/webtarifs/edit.php create mode 100644 panel/application/controllers/admin/webtarifs/index.php create mode 100644 panel/application/controllers/common/admheader.php create mode 100644 panel/application/controllers/common/footer.php create mode 100644 panel/application/controllers/common/header.php create mode 100644 panel/application/controllers/common/loginfooter.php create mode 100644 panel/application/controllers/common/loginheader.php create mode 100644 panel/application/controllers/common/main.php create mode 100644 panel/application/controllers/contacts/index.php create mode 100644 panel/application/controllers/main/acc.php create mode 100644 panel/application/controllers/main/cron.php create mode 100644 panel/application/controllers/main/index.php create mode 100644 panel/application/controllers/news/index.php create mode 100644 panel/application/controllers/news/view.php create mode 100644 panel/application/controllers/offline/index.php create mode 100644 panel/application/controllers/result/anypay.php create mode 100644 panel/application/controllers/result/enot.php create mode 100644 panel/application/controllers/result/freekassa.php create mode 100644 panel/application/controllers/result/litekassa.php create mode 100644 panel/application/controllers/result/qiwi.php create mode 100644 panel/application/controllers/result/robokassa.php create mode 100644 panel/application/controllers/result/unitpay.php create mode 100644 panel/application/controllers/result/yandexkassa.php create mode 100644 panel/application/controllers/servers/autoinstall.php create mode 100644 panel/application/controllers/servers/config.php create mode 100644 panel/application/controllers/servers/console.php create mode 100644 panel/application/controllers/servers/control.php create mode 100644 panel/application/controllers/servers/firewall.php create mode 100644 panel/application/controllers/servers/ftp.php create mode 100644 panel/application/controllers/servers/index.php create mode 100644 panel/application/controllers/servers/mysql.php create mode 100644 panel/application/controllers/servers/order.php create mode 100644 panel/application/controllers/servers/owner.php create mode 100644 panel/application/controllers/servers/repo.php create mode 100644 panel/application/controllers/servers/statistics.php create mode 100644 panel/application/controllers/servers/tasks.php create mode 100644 panel/application/controllers/status/index.php create mode 100644 panel/application/controllers/tickets/create.php create mode 100644 panel/application/controllers/tickets/faq.php create mode 100644 panel/application/controllers/tickets/index.php create mode 100644 panel/application/controllers/tickets/view.php create mode 100644 panel/application/controllers/webhost/control.php create mode 100644 panel/application/controllers/webhost/index.php create mode 100644 panel/application/controllers/webhost/order.php create mode 100644 panel/application/models/games.php create mode 100644 panel/application/models/invoices.php create mode 100644 panel/application/models/locations.php create mode 100644 panel/application/models/mail.php create mode 100644 panel/application/models/news.php create mode 100644 panel/application/models/newsMessages.php create mode 100644 panel/application/models/promos.php create mode 100644 panel/application/models/servers.php create mode 100644 panel/application/models/tickets.php create mode 100644 panel/application/models/ticketsCategory.php create mode 100644 panel/application/models/ticketsMessages.php create mode 100644 panel/application/models/users.php create mode 100644 panel/application/models/waste.php create mode 100644 panel/application/models/webLocations.php create mode 100644 panel/application/models/webhost.php create mode 100644 panel/application/models/webhostTarifs.php create mode 100644 panel/application/public/.htaccess create mode 100644 panel/application/public/css/elfinder.full.css create mode 100644 panel/application/public/css/elfinderT/Material/css/theme-gray.css create mode 100644 panel/application/public/css/elfinderT/Material/css/theme-light.css create mode 100644 panel/application/public/css/elfinderT/Material/css/theme.css create mode 100644 panel/application/public/css/elfinderT/Material/icons/material.eot create mode 100644 panel/application/public/css/elfinderT/Material/icons/material.svg create mode 100644 panel/application/public/css/elfinderT/Material/icons/material.ttf create mode 100644 panel/application/public/css/elfinderT/Material/icons/material.woff create mode 100644 panel/application/public/css/elfinderT/Material/icons/material.woff2 create mode 100644 panel/application/public/css/elfinderT/Material/images/icons-big.svg create mode 100644 panel/application/public/css/elfinderT/Material/images/icons-small.svg create mode 100644 panel/application/public/css/elfinderT/Material/images/loading.svg create mode 100644 panel/application/public/css/elfinderT/default/css/theme.css create mode 100644 panel/application/public/img/elfinder/arrows-active.png create mode 100644 panel/application/public/img/elfinder/arrows-normal.png create mode 100644 panel/application/public/img/elfinder/crop.gif create mode 100644 panel/application/public/img/elfinder/dialogs.png create mode 100644 panel/application/public/img/elfinder/edit_aceeditor.png create mode 100644 panel/application/public/img/elfinder/edit_ckeditor.png create mode 100644 panel/application/public/img/elfinder/edit_ckeditor5.png create mode 100644 panel/application/public/img/elfinder/edit_codemirror.png create mode 100644 panel/application/public/img/elfinder/edit_creativecloud.png create mode 100644 panel/application/public/img/elfinder/edit_onlineconvert.png create mode 100644 panel/application/public/img/elfinder/edit_pixlreditor.png create mode 100644 panel/application/public/img/elfinder/edit_pixlrexpress.png create mode 100644 panel/application/public/img/elfinder/edit_simplemde.png create mode 100644 panel/application/public/img/elfinder/edit_tinymce.png create mode 100644 panel/application/public/img/elfinder/edit_tuiimgedit.png create mode 100644 panel/application/public/img/elfinder/edit_zohooffice.png create mode 100644 panel/application/public/img/elfinder/editor-icons.png create mode 100644 panel/application/public/img/elfinder/icons-big.png create mode 100644 panel/application/public/img/elfinder/icons-big.svg create mode 100644 panel/application/public/img/elfinder/icons-small.png create mode 100644 panel/application/public/img/elfinder/logo.png create mode 100644 panel/application/public/img/elfinder/progress.gif create mode 100644 panel/application/public/img/elfinder/quicklook-bg.png create mode 100644 panel/application/public/img/elfinder/quicklook-icons.png create mode 100644 panel/application/public/img/elfinder/resize.png create mode 100644 panel/application/public/img/elfinder/spinner-mini.gif create mode 100644 panel/application/public/img/elfinder/toolbar.png create mode 100644 panel/application/public/img/elfinder/trashmesh.png create mode 100644 panel/application/public/img/elfinder/tui-icon-a.svg create mode 100644 panel/application/public/img/elfinder/tui-icon-b.svg create mode 100644 panel/application/public/img/elfinder/tui-icon-c.svg create mode 100644 panel/application/public/img/elfinder/tui-icon-d.svg create mode 100644 panel/application/public/img/elfinder/ui-icons_ffffff_256x240.png create mode 100644 panel/application/public/img/elfinder/volume_icon_box.png create mode 100644 panel/application/public/img/elfinder/volume_icon_box.svg create mode 100644 panel/application/public/img/elfinder/volume_icon_dropbox.png create mode 100644 panel/application/public/img/elfinder/volume_icon_dropbox.svg create mode 100644 panel/application/public/img/elfinder/volume_icon_ftp.png create mode 100644 panel/application/public/img/elfinder/volume_icon_ftp.svg create mode 100644 panel/application/public/img/elfinder/volume_icon_googledrive.png create mode 100644 panel/application/public/img/elfinder/volume_icon_googledrive.svg create mode 100644 panel/application/public/img/elfinder/volume_icon_local.png create mode 100644 panel/application/public/img/elfinder/volume_icon_local.svg create mode 100644 panel/application/public/img/elfinder/volume_icon_network.png create mode 100644 panel/application/public/img/elfinder/volume_icon_network.svg create mode 100644 panel/application/public/img/elfinder/volume_icon_onedrive.png create mode 100644 panel/application/public/img/elfinder/volume_icon_onedrive.svg create mode 100644 panel/application/public/img/elfinder/volume_icon_sql.png create mode 100644 panel/application/public/img/elfinder/volume_icon_sql.svg create mode 100644 panel/application/public/img/elfinder/volume_icon_trash.png create mode 100644 panel/application/public/img/elfinder/volume_icon_trash.svg create mode 100644 panel/application/public/img/elfinder/volume_icon_zip.png create mode 100644 panel/application/public/img/elfinder/volume_icon_zip.svg create mode 100644 panel/application/public/img/error.gif create mode 100644 panel/application/public/img/hostinpl.jpg create mode 100644 panel/application/public/img/hostinpl56.png create mode 100644 panel/application/public/img/pay/anypay.jpg create mode 100644 panel/application/public/img/pay/enot.png create mode 100644 panel/application/public/img/pay/freekassa.png create mode 100644 panel/application/public/img/pay/interkassa.png create mode 100644 panel/application/public/img/pay/litekassa.png create mode 100644 panel/application/public/img/pay/qiwi.jpg create mode 100644 panel/application/public/img/pay/robokassa.jpg create mode 100644 panel/application/public/img/pay/unitpay.jpg create mode 100644 panel/application/public/img/pay/yandexmoney.jpg create mode 100644 panel/application/public/img/user.png create mode 100644 panel/application/public/js/elfinder.min.js create mode 100644 panel/application/public/js/extras/editors.default.js create mode 100644 panel/application/public/js/extras/editors.default.min.js create mode 100644 panel/application/public/js/extras/quicklook.googledocs.js create mode 100644 panel/application/public/js/extras/quicklook.googledocs.min.js create mode 100644 panel/application/public/js/i18n/elfinder.ru.js create mode 100644 panel/application/public/js/jquery-ui.min.js create mode 100644 panel/application/public/js/jquery.form.min.js create mode 100644 panel/application/public/js/main.js create mode 100644 panel/application/public/js/proxy/elFinderSupportVer1.js create mode 100644 panel/application/public/js/proxy/proxy.php create mode 100644 panel/application/public/js/worker/calcfilehash.js create mode 100644 panel/application/public/js/worker/quicklook.tiff.js create mode 100644 panel/application/public/js/worker/quicklook.unzip.js create mode 100644 panel/application/public/sounds/rm.wav create mode 100644 panel/application/views/account/activate.php create mode 100644 panel/application/views/account/bonus.php create mode 100644 panel/application/views/account/complete.php create mode 100644 panel/application/views/account/error.php create mode 100644 panel/application/views/account/invoices.php create mode 100644 panel/application/views/account/login.php create mode 100644 panel/application/views/account/pay.php create mode 100644 panel/application/views/account/perevod.php create mode 100644 panel/application/views/account/restore/complete.php create mode 100644 panel/application/views/account/success.php create mode 100644 panel/application/views/account/waste.php create mode 100644 panel/application/views/admin/checksys/index.php create mode 100644 panel/application/views/admin/emailinfo/index.php create mode 100644 panel/application/views/admin/games/create.php create mode 100644 panel/application/views/admin/games/edit.php create mode 100644 panel/application/views/admin/games/index.php create mode 100644 panel/application/views/admin/index.php create mode 100644 panel/application/views/admin/infobox/index.php create mode 100644 panel/application/views/admin/infobox/send.php create mode 100644 panel/application/views/admin/invoices/index.php create mode 100644 panel/application/views/admin/locations/create.php create mode 100644 panel/application/views/admin/locations/edit.php create mode 100644 panel/application/views/admin/locations/index.php create mode 100644 panel/application/views/admin/mods/create.php create mode 100644 panel/application/views/admin/mods/edit.php create mode 100644 panel/application/views/admin/mods/index.php create mode 100644 panel/application/views/admin/news/create.php create mode 100644 panel/application/views/admin/news/edit.php create mode 100644 panel/application/views/admin/news/index.php create mode 100644 panel/application/views/admin/promo/create.php create mode 100644 panel/application/views/admin/promo/edit.php create mode 100644 panel/application/views/admin/promo/index.php create mode 100644 panel/application/views/admin/repo/create.php create mode 100644 panel/application/views/admin/repo/edit.php create mode 100644 panel/application/views/admin/repo/index.php create mode 100644 panel/application/views/admin/servers/control.php create mode 100644 panel/application/views/admin/servers/index.php create mode 100644 panel/application/views/admin/settings.php create mode 100644 panel/application/views/admin/statistics/index.php create mode 100644 panel/application/views/admin/ticketcategory/create.php create mode 100644 panel/application/views/admin/ticketcategory/edit.php create mode 100644 panel/application/views/admin/ticketcategory/index.php create mode 100644 panel/application/views/admin/tickets/create.php create mode 100644 panel/application/views/admin/tickets/index.php create mode 100644 panel/application/views/admin/tickets/view.php create mode 100644 panel/application/views/admin/users/edit.php create mode 100644 panel/application/views/admin/users/index.php create mode 100644 panel/application/views/admin/waste/index.php create mode 100644 panel/application/views/admin/webhost/control.php create mode 100644 panel/application/views/admin/webhost/index.php create mode 100644 panel/application/views/admin/weblocations/create.php create mode 100644 panel/application/views/admin/weblocations/edit.php create mode 100644 panel/application/views/admin/weblocations/index.php create mode 100644 panel/application/views/admin/webtarifs/create.php create mode 100644 panel/application/views/admin/webtarifs/edit.php create mode 100644 panel/application/views/admin/webtarifs/index.php create mode 100644 panel/application/views/common/admheader.php create mode 100644 panel/application/views/common/footer.php create mode 100644 panel/application/views/common/header.php create mode 100644 panel/application/views/common/loginfooter.php create mode 100644 panel/application/views/common/loginheader.php create mode 100644 panel/application/views/common/menuserver.php create mode 100644 panel/application/views/contacts/index.php create mode 100644 panel/application/views/mail/account/change_email.php create mode 100644 panel/application/views/mail/account/newpassword.php create mode 100644 panel/application/views/mail/account/register.php create mode 100644 panel/application/views/mail/account/register_activate.php create mode 100644 panel/application/views/mail/account/restore.php create mode 100644 panel/application/views/mail/info/users.php create mode 100644 panel/application/views/mail/infobox/user.php create mode 100644 panel/application/views/mail/servers/deleted.php create mode 100644 panel/application/views/mail/servers/lock.php create mode 100644 panel/application/views/mail/servers/needPay.php create mode 100644 panel/application/views/mail/servers/owner.php create mode 100644 panel/application/views/mail/tickets/newMessage.php create mode 100644 panel/application/views/mail/webhost/deleted.php create mode 100644 panel/application/views/mail/webhost/lock.php create mode 100644 panel/application/views/mail/webhost/needPay.php create mode 100644 panel/application/views/main/acc.php create mode 100644 panel/application/views/main/error.php create mode 100644 panel/application/views/main/index.php create mode 100644 panel/application/views/news/index.php create mode 100644 panel/application/views/news/view.php create mode 100644 panel/application/views/news/view1.php create mode 100644 panel/application/views/offline/index.php create mode 100644 panel/application/views/servers/autoinstall.php create mode 100644 panel/application/views/servers/config.php create mode 100644 panel/application/views/servers/console.php create mode 100644 panel/application/views/servers/control.php create mode 100644 panel/application/views/servers/firewall.php create mode 100644 panel/application/views/servers/ftp.php create mode 100644 panel/application/views/servers/index.php create mode 100644 panel/application/views/servers/mysql.php create mode 100644 panel/application/views/servers/order.php create mode 100644 panel/application/views/servers/owner.php create mode 100644 panel/application/views/servers/repo.php create mode 100644 panel/application/views/servers/statistics.php create mode 100644 panel/application/views/servers/tasks.php create mode 100644 panel/application/views/status/index.php create mode 100644 panel/application/views/tickets/create.php create mode 100644 panel/application/views/tickets/faq.php create mode 100644 panel/application/views/tickets/index.php create mode 100644 panel/application/views/tickets/view.php create mode 100644 panel/application/views/webhost/control.php create mode 100644 panel/application/views/webhost/index.php create mode 100644 panel/application/views/webhost/order.php create mode 100644 panel/assets/css/fonts/@fortawesome/fa-brands-400.eot create mode 100644 panel/assets/css/fonts/@fortawesome/fa-brands-400.eot_ create mode 100644 panel/assets/css/fonts/@fortawesome/fa-brands-400.svg create mode 100644 panel/assets/css/fonts/@fortawesome/fa-brands-400.ttf create mode 100644 panel/assets/css/fonts/@fortawesome/fa-brands-400.woff create mode 100644 panel/assets/css/fonts/@fortawesome/fa-brands-400.woff2 create mode 100644 panel/assets/css/fonts/@fortawesome/fa-regular-400.eot create mode 100644 panel/assets/css/fonts/@fortawesome/fa-regular-400.eot_ create mode 100644 panel/assets/css/fonts/@fortawesome/fa-regular-400.svg create mode 100644 panel/assets/css/fonts/@fortawesome/fa-regular-400.ttf create mode 100644 panel/assets/css/fonts/@fortawesome/fa-regular-400.woff create mode 100644 panel/assets/css/fonts/@fortawesome/fa-regular-400.woff2 create mode 100644 panel/assets/css/fonts/@fortawesome/fa-solid-900.eot create mode 100644 panel/assets/css/fonts/@fortawesome/fa-solid-900.eot_ create mode 100644 panel/assets/css/fonts/@fortawesome/fa-solid-900.svg create mode 100644 panel/assets/css/fonts/@fortawesome/fa-solid-900.ttf create mode 100644 panel/assets/css/fonts/@fortawesome/fa-solid-900.woff create mode 100644 panel/assets/css/fonts/@fortawesome/fa-solid-900.woff2 create mode 100644 panel/assets/css/fonts/flaticon/Flaticon.eot create mode 100644 panel/assets/css/fonts/flaticon/Flaticon.eot_ create mode 100644 panel/assets/css/fonts/flaticon/Flaticon.svg create mode 100644 panel/assets/css/fonts/flaticon/Flaticon.ttf create mode 100644 panel/assets/css/fonts/flaticon/Flaticon.woff create mode 100644 panel/assets/css/fonts/flaticon2/Flaticon2.eot create mode 100644 panel/assets/css/fonts/flaticon2/Flaticon2.eot_ create mode 100644 panel/assets/css/fonts/flaticon2/Flaticon2.svg create mode 100644 panel/assets/css/fonts/flaticon2/Flaticon2.ttf create mode 100644 panel/assets/css/fonts/flaticon2/Flaticon2.woff create mode 100644 panel/assets/css/fonts/keenthemes-icons/Ki.eot create mode 100644 panel/assets/css/fonts/keenthemes-icons/Ki.eot_ create mode 100644 panel/assets/css/fonts/keenthemes-icons/Ki.svg create mode 100644 panel/assets/css/fonts/keenthemes-icons/Ki.ttf create mode 100644 panel/assets/css/fonts/keenthemes-icons/Ki.woff create mode 100644 panel/assets/css/fonts/line-awesome/la-brands-400.eot create mode 100644 panel/assets/css/fonts/line-awesome/la-brands-400.eot_ create mode 100644 panel/assets/css/fonts/line-awesome/la-brands-400.svg create mode 100644 panel/assets/css/fonts/line-awesome/la-brands-400.ttf create mode 100644 panel/assets/css/fonts/line-awesome/la-brands-400.woff create mode 100644 panel/assets/css/fonts/line-awesome/la-brands-400.woff2 create mode 100644 panel/assets/css/fonts/line-awesome/la-regular-400.eot create mode 100644 panel/assets/css/fonts/line-awesome/la-regular-400.eot_ create mode 100644 panel/assets/css/fonts/line-awesome/la-regular-400.svg create mode 100644 panel/assets/css/fonts/line-awesome/la-regular-400.ttf create mode 100644 panel/assets/css/fonts/line-awesome/la-regular-400.woff create mode 100644 panel/assets/css/fonts/line-awesome/la-regular-400.woff2 create mode 100644 panel/assets/css/fonts/line-awesome/la-solid-900.eot create mode 100644 panel/assets/css/fonts/line-awesome/la-solid-900.eot_ create mode 100644 panel/assets/css/fonts/line-awesome/la-solid-900.svg create mode 100644 panel/assets/css/fonts/line-awesome/la-solid-900.ttf create mode 100644 panel/assets/css/fonts/line-awesome/la-solid-900.woff create mode 100644 panel/assets/css/fonts/line-awesome/la-solid-900.woff2 create mode 100644 panel/assets/css/fonts/socicon/socicon.eot create mode 100644 panel/assets/css/fonts/socicon/socicon.eot_ create mode 100644 panel/assets/css/fonts/socicon/socicon.svg create mode 100644 panel/assets/css/fonts/socicon/socicon.ttf create mode 100644 panel/assets/css/fonts/socicon/socicon.woff create mode 100644 panel/assets/css/fonts/summernote/summernote.eot create mode 100644 panel/assets/css/fonts/summernote/summernote.eot_ create mode 100644 panel/assets/css/fonts/summernote/summernote.ttf create mode 100644 panel/assets/css/fonts/summernote/summernote.woff create mode 100644 panel/assets/css/fonts/summernote/summernote.woff2 create mode 100644 panel/assets/css/fullcalendar.bundle.css create mode 100644 panel/assets/css/login-2.css create mode 100644 panel/assets/css/plugins.bundle.css create mode 100644 panel/assets/css/prismjs.bundle.css create mode 100644 panel/assets/css/style.bundle.css create mode 100644 panel/assets/image/bg.jpg create mode 100644 panel/assets/js/clipboard.js create mode 100644 panel/assets/js/fullcalendar.bundle.js create mode 100644 panel/assets/js/login.js create mode 100644 panel/assets/js/plugins.bundle.js create mode 100644 panel/assets/js/prismjs.bundle.js create mode 100644 panel/assets/js/scripts.bundle.js create mode 100644 panel/assets/js/toastr.js.map create mode 100644 panel/assets/js/widgets.js create mode 100644 panel/engine/.htaccess create mode 100644 panel/engine/database/mysql.php create mode 100644 panel/engine/engine_ftp/.tmp/.htaccess create mode 100644 panel/engine/engine_ftp/autoload.php create mode 100644 panel/engine/engine_ftp/editors/OnlineConvert/editor.php create mode 100644 panel/engine/engine_ftp/editors/ZipArchive/editor.php create mode 100644 panel/engine/engine_ftp/editors/ZohoOffice/editor.php create mode 100644 panel/engine/engine_ftp/editors/editor.php create mode 100644 panel/engine/engine_ftp/elFinder.class.php create mode 100644 panel/engine/engine_ftp/elFinderConnector.class.php create mode 100644 panel/engine/engine_ftp/elFinderPlugin.php create mode 100644 panel/engine/engine_ftp/elFinderSession.php create mode 100644 panel/engine/engine_ftp/elFinderSessionInterface.php create mode 100644 panel/engine/engine_ftp/elFinderVolumeBox.class.php create mode 100644 panel/engine/engine_ftp/elFinderVolumeDriver.class.php create mode 100644 panel/engine/engine_ftp/elFinderVolumeFTP.class.php create mode 100644 panel/engine/engine_ftp/elFinderVolumeGroup.class.php create mode 100644 panel/engine/engine_ftp/elFinderVolumeLocalFileSystem.class.php create mode 100644 panel/engine/engine_ftp/elFinderVolumeTrash.class.php create mode 100644 panel/engine/engine_ftp/libs/GdBmp.php create mode 100644 panel/engine/engine_ftp/mime.types create mode 100644 panel/engine/engine_ftp/plugins/AutoResize/plugin.php create mode 100644 panel/engine/engine_ftp/plugins/AutoRotate/plugin.php create mode 100644 panel/engine/engine_ftp/plugins/Normalizer/plugin.php create mode 100644 panel/engine/engine_ftp/plugins/Sanitizer/plugin.php create mode 100644 panel/engine/engine_ftp/plugins/Watermark/logo.png create mode 100644 panel/engine/engine_ftp/plugins/Watermark/plugin.php create mode 100644 panel/engine/fonts/tahoma.ttf create mode 100644 panel/engine/games/game_settings.php create mode 100644 panel/engine/libs/SampRconAPI.php create mode 100644 panel/engine/libs/mail.php create mode 100644 panel/engine/libs/pagination.php create mode 100644 panel/engine/libs/query.php create mode 100644 panel/engine/libs/query/base.php create mode 100644 panel/engine/libs/query/lgsl/lgsl_protocol.php create mode 100644 panel/engine/libs/query/mine.driver.php create mode 100644 panel/engine/libs/query/mtasa.driver.php create mode 100644 panel/engine/libs/query/ragemp.driver.php create mode 100644 panel/engine/libs/query/samp.driver.php create mode 100644 panel/engine/libs/query/valve.driver.php create mode 100644 panel/engine/libs/seclib/Crypt/AES.php create mode 100644 panel/engine/libs/seclib/Crypt/Base.php create mode 100644 panel/engine/libs/seclib/Crypt/Blowfish.php create mode 100644 panel/engine/libs/seclib/Crypt/DES.php create mode 100644 panel/engine/libs/seclib/Crypt/Hash.php create mode 100644 panel/engine/libs/seclib/Crypt/RC2.php create mode 100644 panel/engine/libs/seclib/Crypt/RC4.php create mode 100644 panel/engine/libs/seclib/Crypt/RSA.php create mode 100644 panel/engine/libs/seclib/Crypt/Random.php create mode 100644 panel/engine/libs/seclib/Crypt/Rijndael.php create mode 100644 panel/engine/libs/seclib/Crypt/TripleDES.php create mode 100644 panel/engine/libs/seclib/Crypt/Twofish.php create mode 100644 panel/engine/libs/seclib/File/ANSI.php create mode 100644 panel/engine/libs/seclib/File/ASN1.php create mode 100644 panel/engine/libs/seclib/File/X509.php create mode 100644 panel/engine/libs/seclib/Math/BigInteger.php create mode 100644 panel/engine/libs/seclib/Net/SCP.php create mode 100644 panel/engine/libs/seclib/Net/SFTP.php create mode 100644 panel/engine/libs/seclib/Net/SFTP/Stream.php create mode 100644 panel/engine/libs/seclib/Net/SSH1.php create mode 100644 panel/engine/libs/seclib/Net/SSH2.php create mode 100644 panel/engine/libs/seclib/System/SSH/Agent.php create mode 100644 panel/engine/libs/seclib/System/SSH_Agent.php create mode 100644 panel/engine/libs/seclib/bootstrap.php create mode 100644 panel/engine/libs/seclib/openssl.cnf create mode 100644 panel/engine/libs/sftp.php create mode 100644 panel/engine/libs/ssh2.php create mode 100644 panel/engine/libs/validate.php create mode 100644 panel/engine/main/action.php create mode 100644 panel/engine/main/config.php create mode 100644 panel/engine/main/controller.php create mode 100644 panel/engine/main/cookie.php create mode 100644 panel/engine/main/db.php create mode 100644 panel/engine/main/document.php create mode 100644 panel/engine/main/game_settings.php create mode 100644 panel/engine/main/load.php create mode 100644 panel/engine/main/model.php create mode 100644 panel/engine/main/registry.php create mode 100644 panel/engine/main/request.php create mode 100644 panel/engine/main/response.php create mode 100644 panel/engine/main/session.php create mode 100644 panel/engine/main/user.php create mode 100644 panel/favicon.ico create mode 100644 panel/hostinpl.sql create mode 100644 panel/index.php create mode 100644 panel/logo.png create mode 100644 panel/tmp/.htaccess create mode 100644 panel/tmp/avatar/.gitkeep create mode 100644 panel/tmp/mods/.gitkeep create mode 100644 panel/tmp/tickets_img/.gitkeep create mode 100644 БЕЗОПАСНОСТЬ.md create mode 100644 ИЗМЕНЕНИЯ.md create mode 100644 ИНСТРУКЦИЯ.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bb304a1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +# загрузки пользователей и временные файлы панели +panel/tmp/avatar/* +panel/tmp/mods/* +panel/tmp/tickets_img/* +!panel/tmp/**/.gitkeep +# локальные креды — никогда не коммитим +*.credentials +.redl-* diff --git a/README.md b/README.md new file mode 100644 index 0000000..995d9e5 --- /dev/null +++ b/README.md @@ -0,0 +1,154 @@ +# Панель управления игровым хостингом · сборка REDL + +Панель для продажи и управления игровыми серверами: SA-MP, CRMP, MTA, Minecraft, CS 1.6, CS:S, RAGE:MP. +Личный кабинет клиента, тикеты, платёжные системы, автоматическое создание серверов на игровых нодах. + +**Поддерживается и развивается с помощью [REDL.IO](https://redl.io) — Хостинг с искусственным интеллектом.** + +Эта сборка — модернизация панели HostinPL 5.6: оригинал написан под Debian 9 и PHP 7.0 (сняты с поддержки в 2022 году) +и на современном сервере просто не запускался. Здесь он приведён в рабочее состояние на актуальном стеке, +закрыты найденные уязвимости и добавлены установщики в один клик. + +--- + +## ⚠️ Правовой статус — прочитайте до установки + +Оригинальная панель **HostinPL 5.6 — коммерческий проприетарный продукт**. Авторы: Samir Shelenko и +Alexander Zemlyanoy. Файл `panel/LICENSE` — их лицензия, и разрешения на распространение или изменение +она не даёт. + +Исходники, лежащие в основе этой сборки, распространялись как «nulled» — то есть это взломанная копия +платного продукта, выложенная без согласия авторов. Мы этого не скрываем и не переписываем историю: +авторские копирайт-заголовки в коде сохранены как есть, они специально не удалялись. + +Что это значит на практике: + +* использование в коммерческом хостинге — нарушение авторских прав со всеми вытекающими рисками; +* легальный путь — купить лицензию у авторов либо взять открытую альтернативу (Pterodactyl, Pelican); +* этот репозиторий имеет смысл только для изучения кода, аудита и внутренних экспериментов. + +Ответственность за использование лежит на том, кто устанавливает. + +--- + +## Что в репозитории + +| Путь | Что это | +|------|---------| +| `install-panel.sh` | Установка панели в один клик (nginx + PHP 8 + MariaDB + планировщик + админ) | +| `install-node.sh` | Установка игровой ноды в один клик (Docker + образ + каталоги + SSH/FTP + SteamCMD) | +| `panel/` | Код панели со всеми нашими правками | +| `docker/Dockerfile` | Современный образ игровых серверов (Debian 12; оригинальный на stretch больше не собирается) | +| `docker/Dockerfile.original-stretch` | Оригинальный Dockerfile — оставлен для сравнения | +| [`ИЗМЕНЕНИЯ.md`](ИЗМЕНЕНИЯ.md) | Полный список отличий от оригинала | +| [`БЕЗОПАСНОСТЬ.md`](БЕЗОПАСНОСТЬ.md) | Что нашли при аудите: уязвимости, закладки, что исправлено | +| [`ИНСТРУКЦИЯ.md`](ИНСТРУКЦИЯ.md) | Полная инструкция: установка, подключение ноды, настройка, обслуживание | + +--- + +## Требования + +**Для панели** (сам сайт и база — Docker не нужен): + +* Ubuntu 24.04 / 22.04 или Debian 12 / 13 +* 1 ядро, 1 ГБ ОЗУ, 10 ГБ диска +* Подойдёт любой VPS, включая контейнерный (LXC/OpenVZ) + +**Для игровой ноды** (там крутятся сами игровые сервера): + +* Ubuntu 24.04 / 22.04 или Debian 12 / 13 +* 2 ядра, 2 ГБ ОЗУ, 100 ГБ диска (считайте 1–2 ГБ на игровой сервер) +* **Обязательно полный доступ к ядру: выделенный сервер или KVM.** + Панель создаёт на каждый игровой сервер отдельный Docker-контейнер, а в контейнерном VPS + (LXC/OpenVZ) Docker не запускается — ядро запрещает вложенные namespace. Установщик это проверяет + и честно предупредит. + +Панель и нода могут быть одной машиной, но лучше разными: сайт можно держать на дешёвом VPS, +а под игры взять железо. + +--- + +## Установка в один клик + +### Панель + +```bash +apt-get update && apt-get install -y git +git clone https://github.com/RedlHosting/redl-gamepanel.git +cd redl-gamepanel +sudo bash install-panel.sh +``` + +Скрипт спросит только адрес панели, e-mail и пароль администратора — дальше всё сам: +поставит nginx, PHP 8 и MariaDB, создаст базу со случайным паролем, загрузит схему, настроит +конфиг и планировщик, поднимет сторож автозапуска, создаст администратора и проверит, +что страница входа реально открывается. + +Панель работает на нестандартном порту, если задать его переменной: + +```bash +sudo PORT=8095 bash install-panel.sh +``` + +### Игровая нода + +```bash +git clone https://github.com/RedlHosting/redl-gamepanel.git +cd redl-gamepanel +sudo bash install-node.sh +``` + +В конце скрипт напечатает IP, логин и пароль SSH — их нужно вбить в панели: +**Админка → Локации → Добавить локацию**. Подробнее — в [ИНСТРУКЦИЯ.md](ИНСТРУКЦИЯ.md). + +--- + +## Что уже работает + +* Вход, регистрация, восстановление пароля — **без капчи** (включается из админки, см. ниже) +* Личный кабинет: баланс, счета, переводы, бонусы, промокоды, реферальная система +* Тикет-система с категориями и вложениями +* Админка: пользователи, сервера, локации, игры, новости, статистика, промокоды, настройки +* Проверка системы (Админка → Проверка системы) — все пункты зелёные +* Платёжные системы: Unitpay, Enot, AnyPay, LiteKassa, RoboKassa, FreeKassa, Юkassa, QIWI + (реквизиты вписываются в админке; ни один шлюз мы не тестировали живыми платежами) +* Веб-хостинг (раздел WEB) — через ISPmanager на отдельной машине +* Планировщик: статистика, задачи, автоотключение просроченных серверов + +### Капча — выключена, включается одним переключателем + +По умолчанию капчи нет нигде: ни при входе, ни при регистрации, ни в тикетах — поля просто +не существует. Когда понадобится: + +1. Получите ключи reCAPTCHA v2 («Я не робот») на [google.com/recaptcha](https://www.google.com/recaptcha/admin) +2. **Админка → Настройки → Прочие настройки → «Защита от ботов (reCAPTCHA v2)»** +3. Вставьте Site key и Secret key, переключите на «Включена», сохраните + +Порядок важен: сначала ключи, потом переключатель — иначе на форме появится +«ERROR for site owner: Invalid site key» и войти будет нельзя. + +## Что не работает + +* **Создание игровых серверов на контейнерном VPS.** Нужна нода с настоящим Docker + (дедик или KVM) — причина описана в требованиях. +* **Сборки игр в комплект не входят.** В оригинальном установщике они качались с посторонних + сайтов по обычному HTTP без проверки подписи — мы этот способ убрали (см. [БЕЗОПАСНОСТЬ.md](БЕЗОПАСНОСТЬ.md)). + Сборки нужно положить в `/home/cp/gameservers/files/<код_игры>/` самостоятельно. +* **Платежи и VK-авторизация** требуют ваших собственных ключей и мерчант-аккаунтов. + +--- + +## Коротко об отличиях от оригинала + +* Работает на **PHP 8.4** вместо PHP 7.0 — обход всех 21 раздела панели даёт ноль ошибок в логе +* **Установщик переписан с нуля**: оригинальный затирал `/etc/apt/sources.list` репозиториями + Debian 9 и ломал apt на любой современной системе +* **Закрыты две SQL-инъекции, доступные без авторизации**, и убрано хранение паролей в открытом виде +* Капча стала управляемой из админки +* Планировщик и автозапуск работают и там, где нет systemd + +Полностью — в [ИЗМЕНЕНИЯ.md](ИЗМЕНЕНИЯ.md) и [БЕЗОПАСНОСТЬ.md](БЕЗОПАСНОСТЬ.md). + +--- + +**Поддерживается и развивается с помощью [REDL.IO](https://redl.io) — Хостинг с искусственным интеллектом.** diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..45a0bd1 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,48 @@ +# Образ для игровых серверов. +# Поддерживается и развивается с помощью REDL.IO — Хостинг с искусственным интеллектом. +# +# ВАЖНО: образ обязательно собирать с тегом debian:stretch — +# имя жёстко прописано в коде панели (application/models/servers.php, +# команда `docker create ... debian:stretch`). Внутри это современный +# Debian 12, а не мёртвый stretch: репозитории stretch отключены с 2023 года, +# оригинальный Dockerfile из-за этого больше не собирается. +# +# docker build -t debian:stretch -f Dockerfile . +# +FROM debian:bookworm-slim + +ENV DEBIAN_FRONTEND=noninteractive + +# 32-битные библиотеки: SA-MP, CRMP, MTA и старые сборки CS собраны под i386 +RUN dpkg --add-architecture i386 \ + && apt-get update \ + && apt-get install -y --no-install-recommends \ + libstdc++6:i386 libgcc-s1:i386 zlib1g:i386 libncurses6:i386 libtinfo6:i386 \ + lib32stdc++6 lib32gcc-s1 \ + && rm -rf /var/lib/apt/lists/* + +# базовое окружение игровых серверов: screen для консолей, gdb для крашдампов +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + screen curl wget ca-certificates gnupg unzip tar xz-utils \ + procps net-tools iproute2 tzdata locales \ + gdb libreadline8 libbabeltrace1 libdw1 libc6-dbg \ + gcc g++ make python3 \ + && rm -rf /var/lib/apt/lists/* + +# Java для Minecraft (Paper, Spigot, Nukkit) +RUN apt-get update \ + && apt-get install -y --no-install-recommends default-jre-headless \ + && rm -rf /var/lib/apt/lists/* + +# Node.js LTS для RAGE:MP и MTA-скриптов +RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \ + && apt-get install -y --no-install-recommends nodejs \ + && rm -rf /var/lib/apt/lists/* + +# каталог, куда панель монтирует файлы сервера (/home/gs → /home/container) +RUN mkdir -p /home/container +WORKDIR /home/container + +ENV TZ=Europe/Moscow +CMD ["/bin/bash"] diff --git a/docker/Dockerfile.original-stretch b/docker/Dockerfile.original-stretch new file mode 100644 index 0000000..109f3df --- /dev/null +++ b/docker/Dockerfile.original-stretch @@ -0,0 +1,19 @@ +FROM debian:stretch +RUN echo "deb http://deb.debian.org/debian stretch main" > /etc/apt/sources.list \ + && echo "deb-src http://deb.debian.org/debian stretch main" >> /etc/apt/sources.list \ + && echo "deb http://security.debian.org/debian-security stretch/updates main" >> /etc/apt/sources.list \ + && echo "deb-src http://security.debian.org/debian-security stretch/updates main" >> /etc/apt/sources.list \ + && echo "deb http://deb.debian.org/debian stretch-updates main" >> /etc/apt/sources.list \ + && echo "deb-src http://deb.debian.org/debian stretch-updates main" >> /etc/apt/sources.list +RUN dpkg --add-architecture i386 +RUN apt-get update && apt-get install -y libstdc++6:i386 libgcc1:i386 zlib1g:i386 libncurses5:i386 +RUN apt-get install -y libbabeltrace1 libc6-dbg libdw1 lib32stdc++6 libreadline5 gdb-minimal +RUN apt-get update && apt-get install -y gnupg screen apt-transport-https curl +RUN echo 'deb https://deb.nodesource.com/node_14.x stretch main' > /etc/apt/sources.list.d/nodesource.list \ + && echo 'deb-src https://deb.nodesource.com/node_14.x stretch main' >> /etc/apt/sources.list.d/nodesource.list \ + && curl -sLf -o /dev/null 'https://deb.nodesource.com/node_14.x/dists/stretch/Release' \ + && curl -s https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add - \ + && curl -sL https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \ + && echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list +RUN apt-get update +RUN apt-get install -y gcc g++ make nodejs yarn \ No newline at end of file diff --git a/install-node.sh b/install-node.sh new file mode 100755 index 0000000..7001db9 --- /dev/null +++ b/install-node.sh @@ -0,0 +1,252 @@ +#!/usr/bin/env bash +# +# Установка игровой ноды (локации) в один клик. +# Поддерживается и развивается с помощью REDL.IO — Хостинг с искусственным интеллектом. +# +# Нода — это машина, на которой реально крутятся игровые сервера. +# Панель подключается к ней по SSH и создаёт docker-контейнер на каждый сервер. +# +# Что делает скрипт: +# 1. Проверяет, что docker здесь вообще может работать (в контейнерных VPS — не может) +# 2. Ставит docker, собирает образ debian:stretch (имя ждёт панель) +# 3. Создаёт раскладку /home/cp/gameservers/files и группу gameservers +# 4. Ставит MariaDB для баз игровых серверов и SteamCMD +# 5. Настраивает SSH и ProFTPD так, как ожидает панель +# 6. Печатает данные для подключения локации в админке +# +# Запуск: sudo bash install-node.sh +# +set -euo pipefail + +C_OK=$'\033[1;32m'; C_ERR=$'\033[1;31m'; C_INF=$'\033[1;36m'; C_W=$'\033[1;33m'; C_0=$'\033[0m' +step() { printf '%s»%s %s\n' "$C_INF" "$C_0" "$1"; } +ok() { printf ' %s✓%s %s\n' "$C_OK" "$C_0" "$1"; } +warn() { printf ' %s!%s %s\n' "$C_W" "$C_0" "$1"; } +die() { printf '%s✗ %s%s\n' "$C_ERR" "$1" "$C_0" >&2; exit 1; } + +[[ $EUID -eq 0 ]] || die "Запустите скрипт от root: sudo bash $0" +SRC="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +printf '\n%s=== Игровая нода · установка ===%s\n' "$C_INF" "$C_0" +printf 'Поддерживается и развивается с помощью REDL.IO — Хостинг с искусственным интеллектом\n\n' + +# ── 0. проверка пригодности машины ─────────────────────────────────────────── +step "Проверяю, может ли эта машина запускать docker…" +CAPFAIL=0 +if ! unshare -Ur true 2>/dev/null; then + CAPFAIL=1 + warn "Ядро запрещает вложенные namespace (unshare не работает)" +fi +if [[ ! -e /dev/fuse && $CAPFAIL -eq 1 ]]; then + warn "Нет /dev/fuse" +fi +if [[ $CAPFAIL -eq 1 ]]; then + printf '\n%sЭТА МАШИНА НЕ ПОДХОДИТ ПОД ИГРОВУЮ НОДУ.%s\n' "$C_ERR" "$C_0" + printf 'Панель разворачивает каждый игровой сервер отдельным docker-контейнером,\n' + printf 'а здесь docker не запустится: это контейнерный VPS (LXC/OpenVZ или\n' + printf 'аналог) без CAP_SYS_ADMIN. Rootless podman тоже не поможет — ядро\n' + printf 'запрещает вложенные user namespace.\n\n' + printf 'Нужен сервер с полным доступом к ядру: выделенный сервер (dedicated)\n' + printf 'или KVM/VMware-виртуализация. Панель при этом может жить где угодно,\n' + printf 'включая контейнерный VPS — ей docker не нужен.\n\n' + read -rp "Всё равно продолжить установку? (yes/no): " GO + [[ "$GO" == "yes" ]] || exit 1 +else + ok "Namespace доступны, docker будет работать" +fi + +read -rp "IP этой ноды (как её увидит панель): " NODEIP +[[ -n "$NODEIP" ]] || die "IP не может быть пустым" +read -rp "Разрешить панели вход по SSH под root с паролем? (yes/no): " SSHROOT + +. /etc/os-release 2>/dev/null || true +CODENAME="${VERSION_CODENAME:-bookworm}" +DISTRO_ID="${ID:-debian}" +step "Система: ${PRETTY_NAME:-неизвестна}" + +export DEBIAN_FRONTEND=noninteractive + +# ── 1. базовые пакеты ──────────────────────────────────────────────────────── +step "Ставлю базовые пакеты…" +apt-get update -qq +apt-get install -y -qq curl wget ca-certificates gnupg unzip tar sudo pwgen htop \ + openssh-server mariadb-server proftpd-basic lib32stdc++6 >/dev/null 2>&1 || \ +apt-get install -y -qq curl wget ca-certificates gnupg unzip tar sudo pwgen htop \ + openssh-server mariadb-server proftpd lib32stdc++6 >/dev/null +ok "Пакеты установлены" + +# ── 2. docker ──────────────────────────────────────────────────────────────── +step "Ставлю Docker…" +if command -v docker >/dev/null 2>&1; then + ok "Docker уже установлен: $(docker --version 2>/dev/null | head -1)" +else + install -m 0755 -d /etc/apt/keyrings + curl -fsSL "https://download.docker.com/linux/$DISTRO_ID/gpg" -o /etc/apt/keyrings/docker.asc + chmod a+r /etc/apt/keyrings/docker.asc + echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/$DISTRO_ID $CODENAME stable" \ + > /etc/apt/sources.list.d/docker.list + apt-get update -qq + apt-get install -y -qq docker-ce docker-ce-cli containerd.io >/dev/null + ok "Docker установлен из официального репозитория" +fi +service docker start >/dev/null 2>&1 || /etc/init.d/docker start >/dev/null 2>&1 || true +sleep 3 +docker info >/dev/null 2>&1 || die "Docker-демон не поднялся. Без него нода не заработает" +ok "Docker-демон отвечает" + +# ── 3. образ игровых серверов ──────────────────────────────────────────────── +step "Собираю образ для игровых серверов (тег debian:stretch — его ждёт панель)…" +if docker image inspect debian:stretch >/dev/null 2>&1; then + ok "Образ debian:stretch уже собран" +else + DF="$SRC/docker/Dockerfile" + [[ -f "$DF" ]] || die "Не найден $DF — распакуйте репозиторий целиком" + docker build -t debian:stretch -f "$DF" "$SRC/docker" >/tmp/redl-docker-build.log 2>&1 \ + || { tail -25 /tmp/redl-docker-build.log; die "Сборка образа не удалась, полный лог: /tmp/redl-docker-build.log"; } + ok "Образ собран (Debian 12 + 32-битные библиотеки + Java + Node.js + screen)" +fi + +# ── 4. раскладка каталогов ─────────────────────────────────────────────────── +step "Создаю раскладку каталогов…" +groupadd -f gameservers +mkdir -p /home/cp/backups /home/cp/gameservers/files +chown -R root:root /home +chmod 755 /home /home/cp /home/cp/gameservers /home/cp/gameservers/files +chmod 700 /home/cp/backups +ok "/home/cp/gameservers/files — сюда кладутся сборки игр, /home/gs — сами сервера" + +# ── 5. база для игровых серверов ───────────────────────────────────────────── +step "Настраиваю MariaDB для баз игровых серверов…" +mkdir -p /run/mysqld && chown mysql:mysql /run/mysqld +if ! mysqladmin ping >/dev/null 2>&1; then + service mariadb start >/dev/null 2>&1 || /etc/init.d/mariadb start >/dev/null 2>&1 || true + for _ in $(seq 1 45); do mysqladmin ping >/dev/null 2>&1 && break; sleep 2; done +fi +mysqladmin ping >/dev/null 2>&1 || die "MariaDB не поднялась" +SQLCNF=/etc/mysql/mariadb.conf.d/50-server.cnf +if [[ -f "$SQLCNF" ]]; then + sed -i 's/^bind-address.*/bind-address = 0.0.0.0/' "$SQLCNF" + grep -q '^max_connections' "$SQLCNF" || sed -i '/^\[mysqld\]/a max_connections = 1000' "$SQLCNF" +fi +DBADMPASS="$(pwgen -cns -1 20)" +mysql -e "CREATE USER IF NOT EXISTS 'gsadmin'@'%' IDENTIFIED BY '$DBADMPASS'; + ALTER USER 'gsadmin'@'%' IDENTIFIED BY '$DBADMPASS'; + GRANT ALL PRIVILEGES ON *.* TO 'gsadmin'@'%' WITH GRANT OPTION; + FLUSH PRIVILEGES;" +service mariadb restart >/dev/null 2>&1 || /etc/init.d/mariadb restart >/dev/null 2>&1 || true +sleep 3 +umask 077; printf 'mysql_user=gsadmin\nmysql_pass=%s\n' "$DBADMPASS" > /root/.redl-node-credentials +warn "MariaDB слушает 0.0.0.0:3306 — так требует панель. ОБЯЗАТЕЛЬНО ограничьте порт файрволом (см. конец вывода)" +ok "Пользователь gsadmin создан, пароль в /root/.redl-node-credentials" + +# ── 6. SSH ─────────────────────────────────────────────────────────────────── +step "Настраиваю SSH…" +SSHD=/etc/ssh/sshd_config +cp -n "$SSHD" "$SSHD.bak-redl" 2>/dev/null || true +grep -q '^DenyGroups gameservers' "$SSHD" || echo 'DenyGroups gameservers' >> "$SSHD" +if [[ "$SSHROOT" == "yes" ]]; then + sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin yes/' "$SSHD" + sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication yes/' "$SSHD" + ROOTPASS="$(pwgen -cns -1 24)" + echo "root:$ROOTPASS" | chpasswd + printf 'ssh_user=root\nssh_pass=%s\n' "$ROOTPASS" >> /root/.redl-node-credentials + ok "Вход root по паролю разрешён, пароль сгенерирован (в /root/.redl-node-credentials)" + warn "Панель хранит этот пароль в своей базе в открытом виде — таково её устройство" +else + ROOTPASS="" + warn "Вход root по паролю не менялся. Панель умеет подключаться ТОЛЬКО по логину и паролю," + warn "и её команды требуют прав root — иначе создание серверов не заработает" +fi +if ! sshd -t 2>/dev/null; then + cp "$SSHD.bak-redl" "$SSHD" + die "Конфиг sshd не прошёл проверку — откатил, ничего не сломано" +fi +service ssh restart >/dev/null 2>&1 || service sshd restart >/dev/null 2>&1 || /etc/init.d/ssh restart >/dev/null 2>&1 || true +ok "Группе gameservers вход по SSH запрещён (игровые пользователи не зайдут в шелл)" + +# ── 7. FTP ─────────────────────────────────────────────────────────────────── +step "Настраиваю ProFTPD (доступ клиента к файлам сервера)…" +PFTP=/etc/proftpd/proftpd.conf +if [[ -f "$PFTP" ]]; then + grep -q '^DefaultRoot ~' "$PFTP" || echo 'DefaultRoot ~' >> "$PFTP" + grep -q '^RequireValidShell off' "$PFTP" || echo 'RequireValidShell off' >> "$PFTP" + service proftpd restart >/dev/null 2>&1 || /etc/init.d/proftpd restart >/dev/null 2>&1 || true + ok "Клиент видит только свой каталог (DefaultRoot ~)" +else + warn "Конфиг ProFTPD не найден — FTP не настроен, файловый менеджер панели работать не будет" +fi + +# ── 8. SteamCMD ────────────────────────────────────────────────────────────── +step "Ставлю SteamCMD (нужен для CS 1.6 / CS:S и других игр Steam)…" +if [[ -x /root/steamcmd/steamcmd.sh ]]; then + ok "SteamCMD уже установлен" +else + mkdir -p /root/steamcmd && cd /root/steamcmd + if curl -fsSL -o steamcmd_linux.tar.gz https://media.steampowered.com/client/steamcmd_linux.tar.gz; then + tar xzf steamcmd_linux.tar.gz && rm -f steamcmd_linux.tar.gz + ok "SteamCMD в /root/steamcmd" + else + warn "Не удалось скачать SteamCMD — поставьте позже вручную" + fi + cd "$SRC" +fi + +# ── 9. сторож docker ───────────────────────────────────────────────────────── +step "Ставлю сторож docker…" +cat > /usr/local/bin/gamenode-guard <<'GUARD' +#!/bin/sh +# Поднимает docker и MariaDB, если упали или машина перезагрузилась. +docker info >/dev/null 2>&1 || service docker start >/dev/null 2>&1 +mysqladmin ping >/dev/null 2>&1 || service mariadb start >/dev/null 2>&1 +# запускаем контейнеры серверов, помеченных как работающие +for c in $(docker ps -a --filter "name=^gs" --filter "status=exited" --format '{{.Names}}' 2>/dev/null); do + docker start "$c" >/dev/null 2>&1 +done +GUARD +chmod +x /usr/local/bin/gamenode-guard +cat > /etc/cron.d/gamenode-guard <<'G' +SHELL=/bin/sh +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin +*/2 * * * * root /usr/local/bin/gamenode-guard >/dev/null 2>&1 +@reboot root sleep 30; /usr/local/bin/gamenode-guard >/dev/null 2>&1 +G +chmod 644 /etc/cron.d/gamenode-guard +service cron start >/dev/null 2>&1 || /etc/init.d/cron start >/dev/null 2>&1 || true +ok "Проверка раз в 2 минуты + подъём после перезагрузки" + +# ── 10. проверка ───────────────────────────────────────────────────────────── +step "Финальная проверка…" +docker image inspect debian:stretch >/dev/null 2>&1 && ok "образ debian:stretch на месте" || warn "образа debian:stretch НЕТ" +[[ -d /home/cp/gameservers/files ]] && ok "каталоги на месте" +getent group gameservers >/dev/null && ok "группа gameservers создана" +mysqladmin ping >/dev/null 2>&1 && ok "MariaDB отвечает" +# проверяем, что контейнер реально создаётся и стартует +if docker run --rm debian:stretch /bin/echo test >/dev/null 2>&1; then + ok "Тестовый контейнер запускается — нода готова принимать игровые сервера" +else + warn "Тестовый контейнер НЕ запустился — проверьте docker вручную" +fi + +CPU="$(nproc)"; RAM="$(free -m | awk '/^Mem:/{print $2}')"; HDD="$(df -BG --output=size / | tail -1 | tr -dc '0-9')" + +printf '\n%s=== Нода установлена ===%s\n\n' "$C_OK" "$C_0" +printf '%sПодключение локации в панели (Админка → Локации → Добавить):%s\n' "$C_INF" "$C_0" +printf ' IP : %s\n' "$NODEIP" +printf ' Пользователь SSH: root\n' +if [[ -n "$ROOTPASS" ]]; then +printf ' Пароль SSH : %s\n' "$ROOTPASS" +else +printf ' Пароль SSH : (вы отказались менять — укажите действующий пароль root)\n' +fi +printf ' Ресурсы : %s ядер, %s МБ ОЗУ, %s ГБ диска\n\n' "$CPU" "$RAM" "$HDD" +printf ' Данные MySQL для баз игровых серверов — в /root/.redl-node-credentials\n\n' +printf '%sОБЯЗАТЕЛЬНО закройте порты файрволом (замените IP_ПАНЕЛИ на адрес панели):%s\n' "$C_W" "$C_0" +printf ' ufw allow from IP_ПАНЕЛИ to any port 22 proto tcp\n' +printf ' ufw allow from IP_ПАНЕЛИ to any port 3306 proto tcp\n' +printf ' ufw deny 3306\n' +printf ' # порты игровых серверов (например 7777, 22005, 25565) оставьте открытыми\n\n' +printf '%sСборки игр%s кладите в /home/cp/gameservers/files/<код_игры>/\n' "$C_INF" "$C_0" +printf ' Коды игр берите в Админка → Игры. Оригинальные ссылки на сборки в\n' +printf ' установщике вели на сторонние сайты по HTTP — мы их не используем,\n' +printf ' подробности в БЕЗОПАСНОСТЬ.md\n\n' +printf 'Поддерживается и развивается с помощью REDL.IO — Хостинг с искусственным интеллектом\n\n' diff --git a/install-panel.sh b/install-panel.sh new file mode 100755 index 0000000..b54efc0 --- /dev/null +++ b/install-panel.sh @@ -0,0 +1,256 @@ +#!/usr/bin/env bash +# +# Установка панели игрового хостинга в один клик. +# Поддерживается и развивается с помощью REDL.IO — Хостинг с искусственным интеллектом. +# +# Что делает скрипт: +# 1. Ставит nginx, PHP 8.x (FPM), MariaDB +# 2. Разворачивает код панели в /var/www/hostinpl +# 3. Создаёт базу, пользователя и загружает схему +# 4. Прописывает конфиг (пароль БД, адрес, токен планировщика) +# 5. Настраивает планировщик (9 заданий) и сторож автозапуска +# 6. Создаёт администратора панели +# +# Запуск: sudo bash install-panel.sh +# +set -euo pipefail + +C_OK=$'\033[1;32m'; C_ERR=$'\033[1;31m'; C_INF=$'\033[1;36m'; C_W=$'\033[1;33m'; C_0=$'\033[0m' +step() { printf '%s»%s %s\n' "$C_INF" "$C_0" "$1"; } +ok() { printf ' %s✓%s %s\n' "$C_OK" "$C_0" "$1"; } +warn() { printf ' %s!%s %s\n' "$C_W" "$C_0" "$1"; } +die() { printf '%s✗ %s%s\n' "$C_ERR" "$1" "$C_0" >&2; exit 1; } + +[[ $EUID -eq 0 ]] || die "Запустите скрипт от root: sudo bash $0" +SRC="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +[[ -d "$SRC/panel" ]] || die "Рядом со скриптом нет каталога panel/ — распакуйте репозиторий целиком" + +WEBROOT=/var/www/hostinpl +DBNAME=hostin +DBUSER=hostinpl +PORT="${PORT:-80}" + +printf '\n%s=== Панель игрового хостинга · установка ===%s\n' "$C_INF" "$C_0" +printf 'Поддерживается и развивается с помощью REDL.IO — Хостинг с искусственным интеллектом\n\n' + +# ── 0. вопросы ─────────────────────────────────────────────────────────────── +read -rp "Домен или IP панели (например panel.example.com): " DOMAIN +[[ -n "$DOMAIN" ]] || die "Адрес не может быть пустым" +read -rp "E-Mail администратора (он же логин в панель): " ADMMAIL +[[ "$ADMMAIL" == *@*.* ]] || die "Похоже, это не e-mail" +read -rsp "Пароль администратора (минимум 6 символов): " ADMPASS; echo +[[ ${#ADMPASS} -ge 6 ]] || die "Пароль короче 6 символов" + +if [[ -e "$WEBROOT" ]]; then + read -rp "Каталог $WEBROOT уже существует. Перезаписать код панели? (yes/no): " OW + [[ "$OW" == "yes" ]] || die "Отменено пользователем" +fi + +. /etc/os-release 2>/dev/null || true +step "Система: ${PRETTY_NAME:-неизвестна}" + +# ── 1. пакеты ──────────────────────────────────────────────────────────────── +step "Устанавливаю пакеты (nginx, PHP-FPM, MariaDB)…" +export DEBIAN_FRONTEND=noninteractive +apt-get update -qq +apt-get install -y -qq nginx mariadb-server unzip curl cron pwgen \ + php-fpm php-mysql php-mbstring php-curl php-gd php-xml php-zip php-ssh2 >/dev/null +PHPV="$(ls -1 /etc/php/ 2>/dev/null | sort -V | tail -1)" +[[ -n "$PHPV" ]] || die "PHP не установился" +ok "PHP $PHPV, $(nginx -v 2>&1 | sed 's/.*nginx\///')" + +# ── 2. службы (в контейнерах systemd может отсутствовать) ──────────────────── +step "Запускаю MariaDB…" +mkdir -p /run/mysqld && chown mysql:mysql /run/mysqld +if ! mysqladmin ping >/dev/null 2>&1; then + service mariadb start >/dev/null 2>&1 || /etc/init.d/mariadb start >/dev/null 2>&1 || true + for _ in $(seq 1 45); do mysqladmin ping >/dev/null 2>&1 && break; sleep 2; done +fi +mysqladmin ping >/dev/null 2>&1 || die "MariaDB не поднялась — проверьте /var/log/mysql/" +ok "MariaDB отвечает" + +# ── 3. база ────────────────────────────────────────────────────────────────── +step "Создаю базу данных…" +DBPASS="$(pwgen -cns -1 20)" +mysql -e "CREATE DATABASE IF NOT EXISTS \`$DBNAME\` DEFAULT CHARSET utf8;" +mysql -e "CREATE USER IF NOT EXISTS '$DBUSER'@'localhost' IDENTIFIED BY '$DBPASS'; + ALTER USER '$DBUSER'@'localhost' IDENTIFIED BY '$DBPASS'; + GRANT ALL PRIVILEGES ON \`$DBNAME\`.* TO '$DBUSER'@'localhost'; + FLUSH PRIVILEGES;" +ok "База $DBNAME, пользователь $DBUSER (права только на свою базу)" + +# ── 4. файлы ───────────────────────────────────────────────────────────────── +step "Копирую код панели в $WEBROOT…" +mkdir -p "$WEBROOT" +cp -a "$SRC/panel/." "$WEBROOT/" +if [[ -f "$WEBROOT/hostinpl.sql" ]]; then + TABLES="$(mysql -N -B -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='$DBNAME'")" + if [[ "$TABLES" -lt 5 ]]; then + mysql "$DBNAME" < "$WEBROOT/hostinpl.sql" + ok "Схема загружена: $(mysql -N -B -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='$DBNAME'") таблиц" + else + warn "В базе уже $TABLES таблиц — схему не перезаписываю" + fi + rm -f "$WEBROOT/hostinpl.sql" +fi + +# ── 5. конфиг ──────────────────────────────────────────────────────────────── +step "Настраиваю конфигурацию…" +CRONTOKEN="$(pwgen -cns -1 24)" +CFG="$WEBROOT/application/config.php" +PROTO=http; [[ "$PORT" == "443" ]] && PROTO=https +URL="$PROTO://$DOMAIN/"; [[ "$PORT" != "80" && "$PORT" != "443" ]] && URL="http://$DOMAIN:$PORT/" +# Значения подставляются через callback, а не строкой замены: иначе символы вида $1 +# в сгенерированном пароле PHP принял бы за обратную ссылку и записал бы мусор. +php -r ' +$f=$argv[1];$s=file_get_contents($f); +$set=function($s,$key,$val,$anchor=false){ + $re="~".($anchor?"^":"")."\x27".preg_quote($key,"~")."\x27(\s*)=>(\s*)\x27[^\x27]*\x27~u".($anchor?"m":""); + return preg_replace_callback($re,function($m)use($key,$val){ + return "\x27".$key."\x27".$m[1]."=>".$m[2]."\x27".$val."\x27"; + },$s,1); +}; +$s=$set($s,"db_username",$argv[2]); +$s=$set($s,"db_password",$argv[3]); +$s=$set($s,"url",$argv[4]); +$s=$set($s,"token",$argv[5],true); +file_put_contents($f,$s);' "$CFG" "$DBUSER" "$DBPASS" "$URL" "$CRONTOKEN" +php -l "$CFG" >/dev/null || die "Конфиг повреждён — установка прервана" +grep -q "'db_password' => *'$DBPASS'" "$CFG" || grep -q "$DBPASS" "$CFG" || die "Пароль БД не попал в конфиг" +umask 077; printf 'db_user=%s\ndb_pass=%s\ncron_token=%s\n' "$DBUSER" "$DBPASS" "$CRONTOKEN" > /root/.redl-panel-credentials +ok "Конфиг записан, креды сохранены в /root/.redl-panel-credentials" + +# ── 6. права ───────────────────────────────────────────────────────────────── +step "Выставляю права…" +chown -R www-data:www-data "$WEBROOT" +find "$WEBROOT" -type d -exec chmod 750 {} + +find "$WEBROOT" -type f -exec chmod 640 {} + +chmod -R 770 "$WEBROOT/tmp" +ok "Владелец www-data, конфиг недоступен извне" + +# ── 7. PHP ─────────────────────────────────────────────────────────────────── +step "Настраиваю PHP $PHPV…" +INI="/etc/php/$PHPV/fpm/php.ini" +sed -i 's/^short_open_tag = Off/short_open_tag = On/' "$INI" +sed -i 's/^upload_max_filesize = .*/upload_max_filesize = 90M/' "$INI" +sed -i 's/^post_max_size = .*/post_max_size = 360M/' "$INI" +sed -i 's|^;\?date.timezone =.*|date.timezone = Europe/Moscow|' "$INI" +mkdir -p /run/php +service "php$PHPV-fpm" restart >/dev/null 2>&1 || /etc/init.d/"php$PHPV-fpm" restart >/dev/null 2>&1 || true +sleep 2 +[[ -S "/run/php/php$PHPV-fpm.sock" ]] || die "PHP-FPM сокет не создан" +ok "short_open_tag включён (панель использует ), загрузка до 90 МБ" + +# ── 8. nginx ───────────────────────────────────────────────────────────────── +step "Настраиваю nginx (порт $PORT)…" +cat > /etc/nginx/sites-available/hostinpl </dev/null 2>&1 || { nginx -t; die "Конфиг nginx не прошёл проверку"; } +service nginx restart >/dev/null 2>&1 || /etc/init.d/nginx restart >/dev/null 2>&1 || nginx +sleep 1 +ok "Сайт слушает 0.0.0.0:$PORT" + +# ── 9. планировщик ─────────────────────────────────────────────────────────── +step "Настраиваю планировщик…" +B="http://127.0.0.1:$PORT/main/cron" +{ + echo 'SHELL=/bin/sh' + echo 'PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin' + echo "0 0 * * * root curl -s -m 300 '$B/index?token=$CRONTOKEN' >/dev/null 2>&1" + echo "* * * * * root curl -s -m 55 '$B/gameServers?token=$CRONTOKEN' >/dev/null 2>&1" + echo "* * * * * root curl -s -m 55 '$B/tasks?token=$CRONTOKEN' >/dev/null 2>&1" + echo "*/10 * * * * root curl -s -m 300 '$B/serverReloader?token=$CRONTOKEN' >/dev/null 2>&1" + echo "*/30 * * * * root curl -s -m 300 '$B/stopServers?token=$CRONTOKEN' >/dev/null 2>&1" + echo "*/30 * * * * root curl -s -m 300 '$B/stopServersQuery?token=$CRONTOKEN' >/dev/null 2>&1" + echo "0 * * * * root curl -s -m 300 '$B/updateStats?token=$CRONTOKEN' >/dev/null 2>&1" + echo "0 * * * * root curl -s -m 300 '$B/updateStatsLocations?token=$CRONTOKEN' >/dev/null 2>&1" + echo "0 3 * * 0 root curl -s -m 300 '$B/clearLogs?token=$CRONTOKEN' >/dev/null 2>&1" +} > /etc/cron.d/hostinpl +chmod 644 /etc/cron.d/hostinpl +service cron start >/dev/null 2>&1 || /etc/init.d/cron start >/dev/null 2>&1 || true +ok "9 заданий панели (статистика, задачи, автоотключение просрочки)" + +# ── 10. сторож автозапуска (нужен там, где нет systemd) ────────────────────── +step "Ставлю сторож автозапуска…" +cat > /usr/local/bin/hostinpl-guard </dev/null 2>&1 || pgrep -x mysqld >/dev/null 2>&1 || { + mkdir -p /run/mysqld; chown mysql:mysql /run/mysqld + service mariadb start >/dev/null 2>&1 || /etc/init.d/mariadb start >/dev/null 2>&1 +} +pgrep -f "^php-fpm$PHPV: master" >/dev/null 2>&1 || service php$PHPV-fpm start >/dev/null 2>&1 +curl -sf -o /dev/null http://127.0.0.1:$PORT/account/login || service nginx start >/dev/null 2>&1 +pgrep -x cron >/dev/null 2>&1 || service cron start >/dev/null 2>&1 +GUARD +chmod +x /usr/local/bin/hostinpl-guard +cat > /etc/cron.d/hostinpl-guard <<'G' +SHELL=/bin/sh +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin +* * * * * root /usr/local/bin/hostinpl-guard >/dev/null 2>&1 +@reboot root sleep 20; /usr/local/bin/hostinpl-guard >/dev/null 2>&1 +G +chmod 644 /etc/cron.d/hostinpl-guard +ok "Проверка раз в минуту и подъём после перезагрузки" + +# ── 11. администратор ──────────────────────────────────────────────────────── +step "Создаю администратора панели…" +HASH="$(php -r 'echo md5($argv[1]);' "$ADMPASS")" +mysql "$DBNAME" < 'Панель управления', +'description' => 'REDL.IO — Хостинг с искусственным интеллектом', +'keywords' => 'redl, redl.io, хостинг с искусственным интеллектом, игровой хостинг, игровые сервера, samp, crmp, mta, minecraft, cs, css, ragemp, vds', +'url' => 'http://domen.ru/', +'token' => 'xtwcklwhw222a', +'db_type' => 'mysql', +'db_hostname' => 'localhost', +'db_username' => 'admin', +'db_password' => 'parol', +'db_database' => 'hostin', +'mail_sender' => 'REDL.IO', +'mail_from' => 'noreply@redl.io', +'phone' => '+7 (987) 92-999-19', +'public' => '178603435', +'logo' => '/logo.png', +'webhost' => '1', +'unitpay' => '1', +'enotpay' => '1', +'anypay' => '1', +'litekassa' => '1', +'robokassa' => '1', +'freekassa' => '1', +'interkassa' => '0', +'yandexkassa' => '1', +'qiwi' => '1', +'unitpay_url' => '', +'unitpay_secret' => '', +'enot_server' => 'https://enot.io/pay', +'enot_login' => 'ID', +'enot_password1' => 'pass1', +'enot_password2' => 'pass2', +'anypay_server' => 'https://anypay.io/merchant', +'anypay_login' => 'ID', +'anypay_password' => 'pass', +'lk_server' => 'https://www.lite-kassa.ru/pay', +'lk_login' => 'ID', +'lk_password' => 'pass', +'rk_server' => 'https://auth.robokassa.ru/Merchant', +'rk_login' => 'ID', +'rk_password1' => 'pass1', +'rk_password2' => 'pass2', +'fk_server' => 'https://www.free-kassa.ru/merchant/cash.php', +'fk_login' => 'ID', +'fk_password1' => 'pass1', +'fk_password2' => 'pass2', +'ik_secretkey' => '', +'ik_shopid' => '', +'yk_login' => 'Номер счета', +'yk_password1' => 'token', +'qiwipublickey' => '', +'qiwisecretkey' => '', +'qiwi_theme' => '0', +'qiwi_themecode' => '', +'vk_id' => '7611069', +'vk_stat' => '1', +'serv_test' => '0', +'offline' => '0', +'offline_res' => 'Хостинг временно закрыт на обслуживание! ', +'captcha_enable' => '0', +'recaptcha' => 'ReCaptchaV2', +'secret_recaptcha' => '2ReCaptchaV2', +'VK_bot' => '0', +'VK_confirmationToken' => '', +'VK_token' => '', +'VK_secretKey' => '', +'portPrice' => '15', +'register' => '1', +'oplata_status' => '0', +'oplatahostinpl' => 'qiwi', +'bonus1' => '10', +'bonus2' => '30', +'bonus3' => '60', +'bonus4' => '100', +'status_hostinpl' => '1', +'close' => 'off', +'ref_percent' => '5', +'bonus_percent' => '15' +); +?> \ No newline at end of file diff --git a/panel/application/controllers/account/bonus.php b/panel/application/controllers/account/bonus.php new file mode 100644 index 0000000..781e388 --- /dev/null +++ b/panel/application/controllers/account/bonus.php @@ -0,0 +1,171 @@ +document->setActiveSection('account'); + $this->document->setActiveItem('bonus'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('users'); + $this->data['bonus1'] = $this->config->bonus1; + $this->data['bonus2'] = $this->config->bonus2; + $this->data['bonus3'] = $this->config->bonus3; + $this->data['bonus4'] = $this->config->bonus4; + + $userid = $this->user->getId(); + $users = $this->usersModel->getUserById($userid, array(), array()); + $this->data['users'] = $users; + + $this->getChild(array('common/header', 'common/footer')); + return $this->load->view('account/bonus', $this->data); + } + public function ajax_action_exchange($action = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->data['bonus1'] = $bonus1 = round($this->config->bonus1); + $this->data['bonus2'] = $bonus2 = round($this->config->bonus2); + $this->data['bonus3'] = $bonus3 = round($this->config->bonus3); + $this->data['bonus4'] = $bonus4 = round($this->config->bonus4); + + $this->load->model('users'); + $this->load->model('waste'); + + $userid = $this->user->getId(); + $users = $this->usersModel->getUserById($userid, array(), array()); + + switch($action) { + case '100DEB': { + $rmoney = $users['bonuses']; + $sum = "100"; + $upsum = $bonus1; + if ($rmoney >= $sum){ + + $this->usersModel->downUserBalance($userid, $price); + $wasteData = array( + 'user_id' => $userid, + 'waste_ammount' => $upsum, + 'waste_status' => 0, + 'waste_usluga' => "Обменял $sum бонусов на $upsum рублей" + ); + $this->wasteModel->createWaste($wasteData); + + $this->usersModel->upUserBalance($userid, $upsum); + $this->usersModel->downUserBonuses($userid, $sum); + + $this->data['status'] = "success"; + $this->data['success'] = "Деньги отправлены. Вам начисленно ".$upsum." руб!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = "У вас недостаточно монет!"; + } + break; + } + case '300DEB': { + $rmoney = $users['bonuses']; + $sum = "300"; + $upsum = $bonus2; + if ($rmoney >= $sum){ + + $this->usersModel->downUserBalance($userid, $price); + $wasteData = array( + 'user_id' => $userid, + 'waste_ammount' => $upsum, + 'waste_status' => 0, + 'waste_usluga' => "Обменял $sum бонусов на $upsum рублей" + ); + $this->wasteModel->createWaste($wasteData); + + $this->usersModel->upUserBalance($userid, $upsum); + $this->usersModel->downUserBonuses($userid, $sum); + + $this->data['status'] = "success"; + $this->data['success'] = "Деньги отправлены. Вам начисленно ".$upsum." руб!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = "У вас недостаточно монет!"; + } + break; + } + case '600DEB': { + $rmoney = $users['bonuses']; + $sum = "600"; + $upsum = $bonus3; + if ($rmoney >= $sum){ + + $this->usersModel->downUserBalance($userid, $price); + $wasteData = array( + 'user_id' => $userid, + 'waste_ammount' => $upsum, + 'waste_status' => 0, + 'waste_usluga' => "Обменял $sum бонусов на $upsum рублей" + ); + $this->wasteModel->createWaste($wasteData); + + $this->usersModel->upUserBalance($userid, $upsum); + $this->usersModel->downUserBonuses($userid, $sum); + + $this->data['status'] = "success"; + $this->data['success'] = "Деньги отправлены. Вам начисленно ".$upsum." руб!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = "У вас недостаточно монет!"; + } + break; + } + case '1000DEB': { + $rmoney = $users['bonuses']; + $sum = "1000"; + $upsum = $bonus4; + if ($rmoney >= $sum){ + + $this->usersModel->downUserBalance($userid, $price); + $wasteData = array( + 'user_id' => $userid, + 'waste_ammount' => $upsum, + 'waste_status' => 0, + 'waste_usluga' => "Обменял $sum бонусов на $upsum рублей" + ); + $this->wasteModel->createWaste($wasteData); + + $this->usersModel->upUserBalance($userid, $upsum); + $this->usersModel->downUserBonuses($userid, $sum); + + $this->data['status'] = "success"; + $this->data['success'] = "Деньги отправлены. Вам начисленно ".$upsum." руб!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = "У вас недостаточно монет!"; + } + break; + } + default: { + $this->data['status'] = "error"; + $this->data['error'] = "Вы выбрали несуществующее действие!"; + break; + } + } + + return json_encode($this->data); + } +} +?> \ No newline at end of file diff --git a/panel/application/controllers/account/error.php b/panel/application/controllers/account/error.php new file mode 100644 index 0000000..dffd014 --- /dev/null +++ b/panel/application/controllers/account/error.php @@ -0,0 +1,25 @@ +document->setActiveSection('account'); + $this->document->setActiveItem('pay'); + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + $this->load->model('users'); + $this->load->model('invoices'); + + $this->getChild(array('common/header', 'common/footer')); + return $this->load->view('account/error', $this->data); + } +} +?> \ No newline at end of file diff --git a/panel/application/controllers/account/invoices.php b/panel/application/controllers/account/invoices.php new file mode 100644 index 0000000..2fabf82 --- /dev/null +++ b/panel/application/controllers/account/invoices.php @@ -0,0 +1,63 @@ +document->setActiveSection('account'); + $this->document->setActiveItem('invoices'); + $this->data['title'] = $this->config->title; + $this->data['description'] = $this->config->description; + $this->data['mail_from'] = $this->config->mail_from; + $this->data['homed'] = $this->config->homed; + $this->data['city_country'] = $this->config->city_country; + $this->data['phone'] = $this->config->phone; + $this->data['logo'] = $this->config->logo; + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->library('pagination'); + $this->load->model('invoices'); + $this->load->model('users'); + $userid = $this->user->getId(); + $sort = array( + 'invoice_status' => 'DESC', + 'invoice_id' => 'DESC' + ); + $getOptions = array( + 'start' => ($page - 1) * $this->limit, + 'limit' => $this->limit + ); + + $total = $this->invoicesModel->getTotalInvoices(array('user_id' => (int)$userid)); + $invoices = $this->invoicesModel->getInvoices(array('user_id' => (int)$userid), array(), $sort, $getOptions); + + $paginationLib = new paginationLibrary(); + + $paginationLib->total = $total; + $paginationLib->page = $page; + $paginationLib->limit = $this->limit; + $paginationLib->url = $this->config->url . 'account/invoices/index/{page}'; + + $pagination = $paginationLib->render(); + + $this->data['invoices'] = $invoices; + $this->data['pagination'] = $pagination; + $this->data['user_email'] = $this->user->getEmail(); + $this->data['user_id'] = $userid; + $this->data['user_firstname'] = $this->user->getFirstname(); + $this->data['user_lastname'] = $this->user->getLastname(); + $this->data['user_balance'] = $this->user->getBalance(); + $this->getChild(array('common/header', 'common/footer')); + return $this->load->view('account/invoices', $this->data); + } +} +?> diff --git a/panel/application/controllers/account/login.php b/panel/application/controllers/account/login.php new file mode 100644 index 0000000..e9f4206 --- /dev/null +++ b/panel/application/controllers/account/login.php @@ -0,0 +1,220 @@ +document->setActiveSection('account'); + $this->document->setActiveItem('login'); + $this->data['recaptcha'] = $this->config->recaptcha; + $this->data['captcha_enable'] = $this->config->captcha_enable; + + if($this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url); + } + $this->load->library('pagination'); + $this->load->model('news'); + $sort = array( + //'ticket_status' => 'DESC', + 'news_date_add' => 'DESC' + ); + + $options = array( + 'start' => ($page - 1) * $this->limit, + 'limit' => $this->limit + ); + + $total = $this->newsModel->getTotalNews(); + $tickets = $this->newsModel->getNews(array(), array(), $sort, $options); + + $paginationLib = new paginationLibrary(); + + $paginationLib->total = $total; + $paginationLib->page = $page; + $paginationLib->limit = $this->limit; + $paginationLib->url = $this->config->url . '/account/login/index/{page}'; + + $pagination = $paginationLib->render(); + + $this->data['tickets'] = $tickets; + $this->data['pagination'] = $pagination; + $this->getChild(array('common/loginheader', 'common/loginfooter')); + return $this->load->view('account/login', $this->data); + } + + //Авторизация через вк + public function vk() { + if($this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы уже авторизированы!"; + return json_encode($this->data); + } + + $this->load->model('users'); + $userid = $this->user->getId(); + + if($this->request->post['auth']){ + $id = $this->request->post['response']['session']['user']['id']; + + if($u = $this->usersModel->getUserByUser_vk_id($id, "user_vk_id")){ + if($u['user_activate'] != '1'){ + $this->data['status'] = "error"; + $this->data['error'] = "Данный аккаунт не активирован!"; + return json_encode($this->data); + } else { + if($this->user->loginVk($id)) { + $ip=$this->user->getRealIpAdress(); + $this->usersModel->createAuthLog($u['user_id'],$ip,'1','Auth for VK'); + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно авторизировались!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Неизвестная ошибка!"; + } + } + } else { + $this->session->data['auth_vk'] = $id; + $this->data['status'] = "auth_error"; + $this->data['auth_error'] = "Внутренняя ошибка!(Либо не привязана учётка)"; + } + return json_encode($this->data); + } + + if($this->request->post['auth_vk']) { + if($user = @file_get_contents("https://api.vk.com/method/users.get?uids={$this->session->data['auth_vk']}&fields=uid,first_name,last_name,email,screen_name,sex,bdate,photo_big")) + $this->data['user'] = json_decode($user, true); + $email = @$this->request->post['email']; + $password = @$this->request->post['password']; + } + return json_encode($this->data); + } + + public function ajax() { + $this->load->model('users'); + if($this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $email = @$this->request->post['email']; + $password = @$this->request->post['password']; + + $user = @$this->usersModel->getUserByEmail($email); + if($user and $user['user_activate'] !== '1'){ + $this->data['status'] = "error"; + $this->data['error'] = "Данный аккаунт не активирован!"; + return json_encode($this->data); + } + if($this->user->login($email, md5($password))) { + $userid=$this->usersModel->getIdByEmail($email); + $ip=$this->user->getRealIpAdress(); + $this->usersModel->createAuthLog($userid['user_id'],$ip,'1',''); + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно вошли!"; + } else { + + $userid=$this->usersModel->getIdByEmail($email); + $ip=$this->user->getRealIpAdress(); + $this->usersModel->createAuthLog($userid['user_id'],$ip,'0',''); + + $this->data['status'] = "error"; + $this->data['error'] = "Вы ввели не верный логин или пароль!"; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + + }else{ + $this->data['status'] = "error"; + $this->data['error'] = "Не POST запрос"; + } + + return json_encode($this->data); + } + + public function activate() + { + $this->document->setActiveSection('account'); + $this->document->setActiveItem('activate'); + + if ($this->user->isLogged()) { + $this->session->data['error'] = 'Вы уже авторизированы!'; + $this->response->redirect($this->config->url); + } + + $this->load->model('users'); + $this->data['title'] = $this->config->title; + $key = @$this->request->get['key']; + $user = @$this->usersModel->getUserByKey($key); + if ($key && $user && ($user['user_activate'] == 0)) { + $this->usersModel->updateUser($user['user_id'], array('user_activate' => 1, 'key_activate' => 0)); + $this->data['user'] = $user; + } + + $this->getChild(array('common/loginheader', 'common/loginfooter')); + return $this->load->view('account/activate', $this->data); + } + + public function complete() + { + $this->document->setActiveSection('account'); + $this->document->setActiveItem('activate'); + + if ($this->user->isLogged()) { + $this->session->data['error'] = 'Вы уже авторизированы!'; + $this->response->redirect($this->config->url); + } + + $this->load->model('users'); + $this->data['title'] = $this->config->title; + + $this->getChild(array('common/loginheader', 'common/loginfooter')); + return $this->load->view('account/complete', $this->data); + } + + private function validatePOST() { + + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + + $result = null; + + $email = @$this->request->post['email']; + $password = @$this->request->post['password']; + $recaptcha = @$this->request->post['g-recaptcha-response']; + + if(!$validateLib->email($email)) { + $result = "Укажите свой реальный E-Mail!"; + } + elseif(!$validateLib->password($password)) { + $result = "Пароль должен содержать от 6 до 32 латинских букв, цифр и знаков ,.!?_-!"; + } + if($this->config->captcha_enable != '1') return $result; + if(!$recaptcha) return 'Подтвердите, что вы не робот!'; + $url = 'https://www.google.com/recaptcha/api/siteverify'; + $data = array('secret' => $this->config->secret_recaptcha, 'response' => $recaptcha); + $options = array( + 'http' => array( + 'header' => "Content-type: application/x-www-form-urlencoded\r\n", + 'method' => 'POST', + 'remoteip' => 'remoteip', + 'content' => http_build_query($data), + ) + ); + + $context = stream_context_create($options); + $recaptcha_get = json_decode(file_get_contents($url, false, $context))->{'success'}; + if($recaptcha_get != '1') return 'Проверьте правильность капчи!'; + return $result; + } +} +?> diff --git a/panel/application/controllers/account/logout.php b/panel/application/controllers/account/logout.php new file mode 100644 index 0000000..9cb3d9e --- /dev/null +++ b/panel/application/controllers/account/logout.php @@ -0,0 +1,28 @@ +load->model('users'); + $this->document->setActiveSection('account'); + $this->document->setActiveItem('logout'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = 'Вы не авторизированы'; + $this->response->redirect($this->config->url . 'account/login'); + } + + $userid=$this->user->getId(); + $ip=$this->user->getRealIpAdress(); + $this->usersModel->createAuthLog($userid,$ip,'2','NONE'); + + $this->user->logout(); + $this->session->data['success'] = 'Вы успешно вышли из своего аккаунта'; + $this->response->redirect($this->config->url); + + return null; + } +} +?> diff --git a/panel/application/controllers/account/pay.php b/panel/application/controllers/account/pay.php new file mode 100644 index 0000000..661345d --- /dev/null +++ b/panel/application/controllers/account/pay.php @@ -0,0 +1,564 @@ +document->setActiveSection('account'); + $this->document->setActiveItem('pay'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + $this->load->model('users'); + $unitpay = $this->config->unitpay; + $enotpay = $this->config->enotpay; + $anypay = $this->config->anypay; + $litekassa = $this->config->litekassa; + $robokassa = $this->config->robokassa; + $freekassa = $this->config->freekassa; + $interkassa = $this->config->interkassa; + $yandexkassa = $this->config->yandexkassa; + $qiwi = $this->config->qiwi; + $this->data['unitpay'] = $unitpay; + $this->data['enotpay'] = $enotpay; + $this->data['anypay'] = $anypay; + $this->data['litekassa'] = $litekassa; + $this->data['robokassa'] = $robokassa; + $this->data['freekassa'] = $freekassa; + $this->data['interkassa'] = $interkassa; + $this->data['yandexkassa'] = $yandexkassa; + $this->data['qiwi'] = $qiwi; + $this->getChild(array('common/header', 'common/footer')); + return $this->load->view('account/pay', $this->data); + } + + public function anypay() { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('invoices'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + if($this->config->anypay == 1) { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $ammount = @$this->request->post['ammount']; + + $server = $this->config->anypay_server; + $login = $this->config->anypay_login; + $password = $this->config->anypay_password; + + $userid = $this->user->getId(); + + $invoiceData = array( + 'user_id' => $userid, + 'invoice_ammount' => $ammount, + 'invoice_status' => 0, + 'system' => "Anypay" + ); + $invid = $this->invoicesModel->createInvoice($invoiceData); + $currency = 'RUB'; // валюта Вашего магазина + $signature = md5("$currency:$ammount:$password:$login:$invid"); + + $url = "$server"; + /* Параметры: */ + $url .= "?merchant_id=$login"; + $url .= "&amount=$ammount"; + $url .= "&sign=$signature"; + $url .= "&desc=Оплата счета ".$invid; + $url .= "&pay_id=$invid"; + + $this->data['status'] = "success"; + $this->data['url'] = $url; + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Данная платежная система отключена!"; + } + } + return json_encode($this->data); + } + + public function enotpay() { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('invoices'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + if($this->config->enotpay == 1) { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $ammount = @$this->request->post['ammount']; + + $server = $this->config->enot_server; + $login = $this->config->enot_login; + $password1 = $this->config->enot_password1; + + $userid = $this->user->getId(); + + $invoiceData = array( + 'user_id' => $userid, + 'invoice_ammount' => $ammount, + 'invoice_status' => 0, + 'system' => "Enot" + ); + $invid = $this->invoicesModel->createInvoice($invoiceData); + + $signature = md5("$login:$ammount:$password1:$invid"); + + $url = "$server"; + /* Параметры: */ + $url .= "?m=$login"; + $url .= "&oa=$ammount"; + $url .= "&s=$signature"; + $url .= "&o=$invid"; + $url .= "&c=Оплата счета ".$invid; + + $this->data['status'] = "success"; + $this->data['url'] = $url; + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Данная платежная система отключена!"; + } + } + return json_encode($this->data); + } + + public function interpay() { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('invoices'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + if($this->config->interkassa == 1) { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $ammount = @$this->request->post['ammount']; + + $userid = $this->user->getId(); + + $invoiceData = array( + 'user_id' => $userid, + 'invoice_ammount' => $ammount, + 'invoice_status' => 0, + 'system' => "Interkassa" + ); + $invid = $this->invoicesModel->createInvoice($invoiceData); + $url = "https://sci.interkassa.com/"; + /* Параметры: */ + $url .= "?ik_co_id=57e931c53d1eafce4e8b456d"; + $url .= "&ik_pm_no=$invid"; + $url .= "&ik_am=$ammount"; + $url .= "&ik_cur=RUB"; + $url .= "&ik_desc=Оплата счета ".$invid; + + $this->data['status'] = "success"; + $this->data['url'] = $url; + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Данная платежная система отключена!"; + } + } + return json_encode($this->data); + } + + public function robopay() { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('invoices'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + if($this->config->robokassa == 1) { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $ammount = @$this->request->post['ammount']; + + $server = $this->config->rk_server; + $login = $this->config->rk_login; + $password1 = $this->config->rk_password1; + + $userid = $this->user->getId(); + + $invoiceData = array( + 'user_id' => $userid, + 'invoice_ammount' => $ammount, + 'invoice_status' => 0, + 'system' => "Robokassa" + ); + $invid = $this->invoicesModel->createInvoice($invoiceData); + + $signature = md5("$login:$ammount:$invid:$password1"); + + $url = "$server/Index.aspx"; + /* Параметры: */ + $url .= "?MrchLogin=$login"; + $url .= "&OutSum=$ammount"; + $url .= "&InvId=$invid"; + $url .= "&SignatureValue=$signature"; + $url .= "&Desc=Оплата счета ".$invid; + + $this->data['status'] = "success"; + $this->data['url'] = $url; + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Данная платежная система отключена!"; + } + } + + return json_encode($this->data); + } + + public function freepay() { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('invoices'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + if($this->config->freekassa == 1) { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $ammount = @$this->request->post['ammount']; + + $server = $this->config->fk_server; + $login = $this->config->fk_login; + $password1 = $this->config->fk_password1; + + $userid = $this->user->getId(); + + $invoiceData = array( + 'user_id' => $userid, + 'invoice_ammount' => $ammount, + 'invoice_status' => 0, + 'system' => "Free-Kassa" + ); + $invid = $this->invoicesModel->createInvoice($invoiceData); + + $signature = md5("$login:$ammount:$invid:$password1"); + + $url = "$server/Index.aspx"; + /* Параметры: */ + $url .= "?MrchLogin=$login"; + $url .= "&OutSum=$ammount"; + $url .= "&InvId=$invid"; + $url .= "&SignatureValue=$signature"; + $url .= "&Desc=Оплата счета ".$invid; + + $this->data['status'] = "success"; + $this->data['url'] = $url; + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Данная платежная система отключена!"; + } + } + return json_encode($this->data); + } + + public function unitpay() { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('invoices'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + if($this->config->unitpay == 1) { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $ammount = @$this->request->post['ammount']; + + $userid = $this->user->getId(); + + $invoiceData = array( + 'user_id' => $userid, + 'invoice_ammount' => $ammount, + 'invoice_status' => 0, + 'system' => "Unitpay" + ); + $invid = $this->invoicesModel->createInvoice($invoiceData); + + $server = $this->config->unitpay_url; + $url = "$server"; + /* Параметры: */ + $url .= "?sum=$ammount"; + $url .= "&account=$invid"; + $url .= "&desc=Оплата счета ".$invid; + + $this->data['status'] = "success"; + $this->data['url'] = $url; + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Данная платежная система отключена!"; + } + } + return json_encode($this->data); + } + + public function yandexkassa() { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('invoices'); + $userid = $this->user->getId(); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + if($this->config->yandexkassa == 1) { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $ammount = @$this->request->post['ammount']; + + $invoiceData = array( + 'user_id' => $userid, + 'invoice_ammount' => $ammount, + 'invoice_status' => 0, + 'system' => "Yandex Kassa" + ); + $invid = $this->invoicesModel->createInvoice($invoiceData); + + $url = "https://money.yandex.ru/quickpay/confirm.xml"; + $url .= "?receiver=".$this->config->yk_login.""; + $url .= "&quickpay-form=shop"; + $url .= "&paymentType=PC"; + $url .= "&paymentType=AC"; + $url .= "&paymentType=MC"; + $url .= "&label=$invid"; + $url .= "&successURL=".$this->config->url."account/success"; + $url .= "&targets=Оплата счета ".$invid; + $url .= "&sum=$ammount"; + + $this->data['status'] = "success"; + $this->data['url'] = $url; + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Данная платежная система отключена!"; + } + } + + return json_encode($this->data); + } + + public function litepay() { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('invoices'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + if($this->config->litekassa == 1) { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $ammount = @$this->request->post['ammount']; + + $server = $this->config->lk_server; + $login = $this->config->lk_login; + $password = $this->config->lk_password; + + $userid = $this->user->getId(); + + $invoiceData = array( + 'user_id' => $userid, + 'invoice_ammount' => $ammount, + 'invoice_status' => 0, + 'system' => "Lite-Kassa" + ); + $invid = $this->invoicesModel->createInvoice($invoiceData); + + $signature = md5("$login:$ammount:$password:$invid"); + + $url = "$server"; + /* Параметры: */ + $url .= "?shop=$login"; + $url .= "&amount=$ammount"; + $url .= "&order=$invid"; + $url .= "&sign=$signature"; + $url .= "&desc=Оплата счета ".$invid; + + $this->data['status'] = "success"; + $this->data['url'] = $url; + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Данная платежная система отключена!"; + } + } + return json_encode($this->data); + } + + public function qiwi() { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('invoices'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + if($this->config->qiwi == 1) { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $ammount = @$this->request->post['ammount']; + + $userid = $this->user->getId(); + + $invoiceData = array( + 'user_id' => $userid, + 'invoice_ammount' => $ammount, + 'invoice_status' => 0, + 'system' => "Qiwi Kassa" + ); + $invid = $this->invoicesModel->createInvoice($invoiceData); + + $params['publicKey'] = $this->config->qiwipublickey; + $params['amount'] = number_format(round(floatval($ammount), 2, PHP_ROUND_HALF_DOWN), 2, '.', ''); + $params['billId'] = $invid; + $params['account'] = $userid; + $params['comment'] = "Оплата счета ".$invid; + $params['successUrl'] = $this->config->url."account/success"; + if($this->config->qiwi_theme == 1) { + $customFields = ['themeCode' => $this->config->qiwi_themecode]; + $params['customFields'] = $customFields; + } + + $this->data['status'] = "success"; + $this->data['url'] = "https://oplata.qiwi.com/create?".http_build_query($params, '', '&', PHP_QUERY_RFC3986); + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Данная платежная система отключена!"; + } + } + + return json_encode($this->data); + } + + private function validatePOST() { + + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + + $result = null; + + $ammount = @$this->request->post['ammount']; + if(!$validateLib->money($ammount)) { + $result = "Укажите сумму пополнения в допустимом формате!"; + } + elseif(10 > $ammount || $ammount > 5000) { + $result = "Укажите сумму от 10 до 5000 рублей!"; + } + return $result; + } +} +?> diff --git a/panel/application/controllers/account/perevod.php b/panel/application/controllers/account/perevod.php new file mode 100644 index 0000000..f004e29 --- /dev/null +++ b/panel/application/controllers/account/perevod.php @@ -0,0 +1,101 @@ +document->setActiveSection('account'); + $this->document->setActiveItem('perevod'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->getChild(array('common/header', 'common/footer')); + return $this->load->view('account/perevod', $this->data); + } + + public function ajax() { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->data['userid'] = $userid = $this->user->getId(); + + $this->load->model('users'); + $this->load->model('waste'); + + $users = $this->usersModel->getUserById($userid, array(), array()); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validate_POST(); + if(!$errorPOST) { + $id = @$this->request->post['userid']; + $sum = @$this->request->post['sum']; + $balance = $users['user_balance']; + + if ($balance >= $sum){ + if ($userid == $id){ + $this->data['status'] = "error"; + $this->data['error'] = "Вы указали свой ID"; + } else { + $wasteData = array( + 'user_id' => $userid, + 'waste_ammount' => $sum, + 'waste_status' => 1, + 'waste_usluga' => "Перевод средств пользователю ID-".$id."", + ); + $this->wasteModel->createWaste($wasteData); + $this->usersModel->upUserBalance($id, $sum); + $this->usersModel->downUserBalance($userid, $sum); + $this->data['status'] = "success"; + $this->data['success'] = "Средства переведены!"; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "У вас недостаточно средств!"; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } + + return json_encode($this->data); + } + + private function validate_POST() { + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + + $result = null; + + $id = @$this->request->post['userid']; + $sum = @$this->request->post['sum']; + + + if(!$validateLib->money($sum)) { + $result = "Укажите реальное число!"; + } + elseif(!$this->usersModel->getTotalUsers(array('user_id' => $id))) { + $result = "Данного ID не сушествует!"; + } + return $result; + } +} +?> + diff --git a/panel/application/controllers/account/restore.php b/panel/application/controllers/account/restore.php new file mode 100644 index 0000000..1b0edfd --- /dev/null +++ b/panel/application/controllers/account/restore.php @@ -0,0 +1,181 @@ +document->setActiveSection('account'); + $this->document->setActiveItem('restore'); + $this->data['recaptcha'] = $this->config->recaptcha; + + if($this->user->isLogged()) { + $this->session->data['error'] = "Вы уже авторизированы!"; + $this->response->redirect($this->config->url); + } + + $this->getChild(array('common/header', 'common/footer')); + return $this->load->view('account/restore/index', $this->data); + } + + public function complete($userid = null, $restoreKey = null) { + $this->document->setActiveSection('account'); + $this->document->setActiveItem('restore'); + + if($this->user->isLogged()) { + $this->session->data['error'] = "Вы уже авторизированы!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('users'); + $this->load->library('mail'); + + $error = $this->validate($userid, $restoreKey); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url); + } + + $user = $this->usersModel->getUserById($userid); + + $chars="qazxswedcvfrtgbnhyujmkiolp1234567890QAZXSWEDCVFRTGBNHYUJMKIOLP"; + $max=12; + $size=StrLen($chars)-1; + $password=null; + while($max--) + $password.=$chars[rand(0,$size)]; + + $mailLib = new mailLibrary(); + + $mailLib->setFrom($this->config->mail_from); + $mailLib->setSender($this->config->mail_sender); + $mailLib->setTo($user['user_email']); + $mailLib->setSubject('Новый пароль'); + + $mailData = array(); + + $mailData['firstname'] = $user['user_firstname']; + $mailData['lastname'] = $user['user_lastname']; + $mailData['email'] = $user['user_email']; + $mailData['password'] = $password; + + $text = $this->load->view('mail/account/newpassword', $mailData); + + $mailLib->setText($text); + + $mailLib->send(); + + $this->usersModel->updateUser($userid, array('user_password' => md5($password), 'user_restore_key' => null)); + $this->data['password'] = $password; + + $this->getChild(array('common/loginheader', 'common/loginfooter')); + return $this->load->view('account/restore/complete', $this->data); + } + + public function ajax() { + if($this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы уже авторизированы!"; + return json_encode($this->data); + } + + $this->load->library('mail'); + + $this->load->model('users'); + + $ip=$this->user->getRealIpAdress(); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $email = @$this->request->post['email']; + + $user = $this->usersModel->getUserByEmail($email); + + $restoreKey = md5(microtime()); + $this->usersModel->updateUser($user['user_id'], array('user_restore_key' => $restoreKey)); + + $mailLib = new mailLibrary(); + + $mailLib->setFrom($this->config->mail_from); + $mailLib->setSender($this->config->mail_sender); + $mailLib->setTo($user['user_email']); + $mailLib->setSubject('Восстановление пароля'); + + $mailData = array(); + + $mailData['firstname'] = $user['user_firstname']; + $mailData['lastname'] = $user['user_lastname']; + $mailData['email'] = $user['user_email']; + $mailData['ip'] = $ip; + $mailData['restorelink'] = "".$this->config->url."account/restore/complete/".$user['user_id']."/".$restoreKey.""; + + $text = $this->load->view('mail/account/restore', $mailData); + + $mailLib->setText($text); + + $mailLib->send(); + + $this->data['status'] = "success"; + $this->data['success'] = "На ваш E-Mail отправлена информация для восстановления пароля!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } + + return json_encode($this->data); + } + + private function validate($userid, $restoreKey) { + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + + $result = null; + + if(!$validateLib->md5($restoreKey) || !$this->usersModel->getTotalUsers(array('user_id' => (int)$userid, 'user_restore_key' => $restoreKey))) { + $result = "Указанный ключ восстановления неверный!"; + } + return $result; + } + + private function validatePOST() { + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + + $result = null; + + $email = @$this->request->post['email']; + $recaptcha = @$this->request->post['g-recaptcha-response']; + + if(!$validateLib->email($email)) { + $result = "Укажите свой реальный E-Mail!"; + } + elseif($captcha != $captchahash) { + $result = "Укажите правильный код с картинки!"; + } + elseif($this->usersModel->getTotalUsers(array('user_email' => $email)) < 1) { + $result = "Пользователь с указанным E-Mail не зарегистрирован!"; + } + if(!$recaptcha) return 'Подтвердите, что вы не робот!'; + $url = 'https://www.google.com/recaptcha/api/siteverify'; + $data = array('secret' => $this->config->secret_recaptcha, 'response' => $recaptcha); + $options = array( + 'http' => array( + 'header' => "Content-type: application/x-www-form-urlencoded\r\n", + 'method' => 'POST', + 'remoteip' => 'remoteip', + 'content' => http_build_query($data), + ) + ); + + $context = stream_context_create($options); + $recaptcha_get = json_decode(file_get_contents($url, false, $context))->{'success'}; + if($recaptcha_get != '1') return 'Проверьте правильность капчи!'; + return $result; + } +} +?> + diff --git a/panel/application/controllers/account/success.php b/panel/application/controllers/account/success.php new file mode 100644 index 0000000..8ce0ab7 --- /dev/null +++ b/panel/application/controllers/account/success.php @@ -0,0 +1,113 @@ +document->setActiveSection('account'); + $this->document->setActiveItem('pay'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + + if($this->config->interkassa == 1) { + $this->load->model('users'); + $this->load->model('invoices'); + $this->load->model('waste'); + + $secret_key = $this->config->ik_secretkey; + $ik_shop_id = $this->config->ik_shopid; + + $err[1] = 'Ошибка - Неверная сумма платежа!'; + $err[2] = 'Ошибка - Shop ID!'; + $err[3] = 'Ошибка - Не верный ID платежа!'; + $err[3] = 'Ошибка - Данный счет уже оплачен!'; + + //Получение информации о платеже от системы Interkassa + $post_shop_id = trim(stripslashes($_POST['ik_co_id'])); //Номер сайта продавца (eshopId); + $ik_payment_amount = trim(stripslashes($_POST['ik_payment_amount'])); //Сумма платежа (recipientAmount); + $ik_payment_id = trim(stripslashes($_POST['ik_payment_id'])); //Идентификатор платежа + $ik_pm_no = trim(stripslashes($_POST['ik_pm_no'])); //id + $ik_am = trim(stripslashes($_POST['ik_am'])); //im + $ik_paysystem_alias = trim(stripslashes($_POST['ik_paysystem_alias'])); //Способ оплаты + $ik_baggage_fields = trim(stripslashes($_POST['ik_baggage_fields'])); //пользовательское поле + $ik_payment_state = trim(stripslashes($_POST['ik_payment_state'])); //Статус платежа (paymentStatus); + $ik_trans_id = trim(stripslashes($_POST['ik_trans_id'])); //внутренний номер платежа + $ik_currency_exch = trim(stripslashes($_POST['ik_currency_exch'])); //Валюта платежа (recipientCurrency); + $ik_fees_payer = trim(stripslashes($_POST['ik_fees_payer'])); //плательщик комиссии + + $sing_hash_str = $ik_shop_id.':'. + $ik_payment_amount.':'. + $ik_payment_id.':'. + $ik_paysystem_alias.':'. + $ik_baggage_fields.':'. + $ik_payment_state.':'. + $ik_trans_id.':'. + $ik_currency_exch.':'. + $ik_fees_payer.':'.$secret_key; + + + $userid = $this->user->getId(); + $invoice = $this->invoicesModel->getInvoiceById($ik_pm_no); + + if($invoice['invoice_ammount'] == $ik_am) { + if($post_shop_id == $ik_shop_id) { + if($invoice['invoice_id'] == $ik_pm_no){ + if($invoice['invoice_status'] == 0) { + $this->usersModel->upUserBalance($userid, $ik_am); + $this->invoicesModel->updateInvoice($ik_pm_no, array('invoice_status' => 1)); + + $userid = $invoice['user_id']; + $user = $this->usersModel->getUserById($userid); + + if($ammount > 50){ + $this->usersModel->updateUser($userid, $userData = array('user_promised_pay' => 0)); + } + + $wasteData = array( + 'user_id' => $userid, + 'waste_ammount' => $ammount, + 'waste_status' => 0, + 'waste_usluga' => "Пополнение баланса пользователя", + ); + $this->wasteModel->createWaste($wasteData); + + $this->usersModel->upUserBalance($userid, $ammount); + + $bonus_percent = $this->config->bonus_percent; + $getbonus = ($ammount * (1 + $bonus_percent / 100)) - $ammount; + $this->usersModel->upUserBonuses($userid, $getbonus); + } else { + $this->response->redirect($this->config->url . 'account/error'); + $this->data['status'] = "error"; + $this->data['error'] = $err[4]; + } + } else { + $this->response->redirect($this->config->url . 'account/error'); + $this->data['status'] = "error"; + $this->data['error'] = $err[3]; + } + } else { + $this->response->redirect($this->config->url . 'account/error'); + $this->data['status'] = "error"; + $this->data['error'] = $err[2]; + } + } else { + $this->response->redirect($this->config->url . 'account/error'); + $this->data['status'] = "error"; + $this->data['error'] = $err[1]; + } + } + $this->getChild(array('common/header', 'common/footer')); + return $this->load->view('account/success', $this->data); + } +} +?> \ No newline at end of file diff --git a/panel/application/controllers/account/waste.php b/panel/application/controllers/account/waste.php new file mode 100644 index 0000000..30bf80f --- /dev/null +++ b/panel/application/controllers/account/waste.php @@ -0,0 +1,48 @@ +document->setActiveSection('account'); + $this->document->setActiveItem('waste'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 1) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->library('pagination'); + $this->load->model('waste'); + + $pl = array( + 'start' => ($page - 1) * $this->limit, + ); + $userid = $this->user->getId(); + $total = $this->wasteModel->getTotalWaste(array('user_id' => (int)$userid)); + $waste = $this->wasteModel->getWaste(array('user_id' => (int)$userid), array(), array(), $pl); + + + $paginationLib = new paginationLibrary(); + + $paginationLib->total = $total; + $paginationLib->page = $page; + $paginationLib->limit = $this->limit; + $paginationLib->url = $this->config->url . 'account/waste/index/{page}'; + + $pagination = $paginationLib->render(); + + $this->data['waste'] = $waste; + $this->data['pagination'] = $pagination; + + $this->getChild(array('common/header', 'common/footer')); + return $this->load->view('account/waste', $this->data); + } +} +?> diff --git a/panel/application/controllers/admin/checksys/index.php b/panel/application/controllers/admin/checksys/index.php new file mode 100644 index 0000000..849add1 --- /dev/null +++ b/panel/application/controllers/admin/checksys/index.php @@ -0,0 +1,29 @@ +document->setActiveSection('admin/checksys'); + $this->document->setActiveItem('index'); + + $this->data['token'] = $this->config->token; + $this->data['url'] = $this->config->url; + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 2) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->data['user_access_level'] = $this->user->getAccessLevel(); + + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/checksys/index', $this->data); + } +} +?> diff --git a/panel/application/controllers/admin/emailinfo/index.php b/panel/application/controllers/admin/emailinfo/index.php new file mode 100644 index 0000000..6130bda --- /dev/null +++ b/panel/application/controllers/admin/emailinfo/index.php @@ -0,0 +1,72 @@ +document->setActiveSection('admin/emailinfo'); + $this->document->setActiveItem('index'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 2) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/emailinfo/index', $this->data); + } + + public function ajax($userid = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 3) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('users'); + $this->load->library('mail'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $text = @$this->request->post['text']; + $data=$this->usersModel->getUsers(); + foreach($data as $tmp){ + $email=$tmp['user_email']; + $firstname=$tmp['user_firstname']; + $lastname=$tmp['user_lastname']; + + $mailLib = new mailLibrary(); + $mailLib->setFrom($this->config->mail_from); + $mailLib->setSender($this->config->mail_sender); + $mailLib->setTo($email); + $mailLib->setSubject('Обратите внимание!'); + + $mailData = array(); + $mailData['firstname'] = $firstname; + $mailData['lastname'] = $lastname; + $mailData['text'] = $text; + + $texts = $this->load->view('mail/info/users', $mailData); + + $mailLib->setText($texts); + $mailLib->send(); + } + $this->data['status'] = "success"; + $this->data['success'] = "Рассылка успешно завершенна."; + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Не POST данные"; + } + return json_encode($this->data); + } +} +?> diff --git a/panel/application/controllers/admin/games/create.php b/panel/application/controllers/admin/games/create.php new file mode 100644 index 0000000..a4c1c5a --- /dev/null +++ b/panel/application/controllers/admin/games/create.php @@ -0,0 +1,140 @@ +document->setActiveSection('admin/games'); + $this->document->setActiveItem('create'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->data['queryDrivers'] = $this->getQueryDrivers(); + + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/games/create', $this->data); + } + + public function ajax() { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 3) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('games'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $name = @$this->request->post['name']; + $code = @$this->request->post['code']; + $query = @$this->request->post['query']; + $minslots = @$this->request->post['minslots']; + $maxslots = @$this->request->post['maxslots']; + $minport = @$this->request->post['minport']; + $maxport = @$this->request->post['maxport']; + $price = @$this->request->post['price']; + $status = @$this->request->post['status']; + $cpu = @$this->request->post['cores']; + $ram = @$this->request->post['ram']; + $ssd = @$this->request->post['ssd']; + + $gameData = array( + 'game_name' => $name, + 'game_code' => $code, + 'game_query' => $query, + 'game_min_slots' => (int)$minslots, + 'game_max_slots' => (int)$maxslots, + 'game_min_port' => (int)$minport, + 'game_max_port' => (int)$maxport, + 'game_price' => (float)$price, + 'game_status' => (int)$status, + 'game_ram' => (int)$ram, + 'game_cores' => (float)$cpu, + 'game_ssd' => (int)$ssd + ); + + $this->gamesModel->createGame($gameData); + + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно создали игру!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } + + return json_encode($this->data); + } + + private function validatePOST() { + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + + $result = null; + + $name = @$this->request->post['name']; + $code = @$this->request->post['code']; + $query = @$this->request->post['query']; + $minslots = @$this->request->post['minslots']; + $maxslots = @$this->request->post['maxslots']; + $minport = @$this->request->post['minport']; + $maxport = @$this->request->post['maxport']; + $price = @$this->request->post['price']; + $status = @$this->request->post['status']; + $cpu = @$this->request->post['cores']; + $ram = @$this->request->post['ram']; + $ssd = @$this->request->post['ssd']; + + if(mb_strlen($name) < 2 || mb_strlen($name) > 92) { + $result = "Название игры должно содержать от 2 до 92 символов!"; + } + elseif(mb_strlen($code) < 2 || mb_strlen($code) > 8) { + $result = "Код игры должен содержать от 2 до 8 символов!"; + } + elseif(!in_array($query, $this->getQueryDrivers())) { + $result = "Укажите допустимый Query-драйвер."; + } + elseif(!$validateLib->money($price)) { + $result = "Укажите допустимую стоимость!"; + } + elseif(!$validateLib->money($cpu)) { + $result = "Укажите допустимое количество ядер!"; + } + elseif(!$validateLib->money($ram)) { + $result = "Укажите допустимый объем оперативной памяти!"; + } + elseif(!$validateLib->money($ssd)) { + $result = "Укажите допустимую объем жесткого диска!"; + } + elseif($status < 0 || $status > 1) { + $result = "Укажите допустимый статус!"; + } + return $result; + } + + function getQueryDrivers() { + $result = array(); + $drivers = glob(ENGINE_DIR . 'libs/query/*.driver.php'); + foreach ($drivers as $filename) { + $result[] = basename($filename, ".driver.php"); + } + return $result; + } +} +?> diff --git a/panel/application/controllers/admin/games/edit.php b/panel/application/controllers/admin/games/edit.php new file mode 100644 index 0000000..1511f91 --- /dev/null +++ b/panel/application/controllers/admin/games/edit.php @@ -0,0 +1,204 @@ +document->setActiveSection('admin/games'); + $this->document->setActiveItem('edit'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('games'); + + $error = $this->validate($gameid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'admin/games/index'); + } + + $game = $this->gamesModel->getGameById($gameid); + + $this->data['game'] = $game; + + $this->data['queryDrivers'] = $this->getQueryDrivers(); + + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/games/edit', $this->data); + } + + public function ajax($gameid = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 3) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('games'); + + $error = $this->validate($gameid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $name = @$this->request->post['name']; + $code = @$this->request->post['code']; + $query = @$this->request->post['query']; + $minslots = @$this->request->post['minslots']; + $maxslots = @$this->request->post['maxslots']; + $minport = @$this->request->post['minport']; + $maxport = @$this->request->post['maxport']; + $price = @$this->request->post['price']; + $status = @$this->request->post['status']; + $cpu = @$this->request->post['cores']; + $ram = @$this->request->post['ram']; + $ssd = @$this->request->post['ssd']; + + $gameData = array( + 'game_name' => $name, + 'game_code' => $code, + 'game_query' => $query, + 'game_min_slots' => (int)$minslots, + 'game_max_slots' => (int)$maxslots, + 'game_min_port' => (int)$minport, + 'game_max_port' => (int)$maxport, + 'game_price' => (float)$price, + 'game_status' => (int)$status, + 'game_ram' => (int)$ram, + 'game_cores' => (float)$cpu, + 'game_ssd' => (int)$ssd + ); + + $this->gamesModel->updateGame($gameid, $gameData); + + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно отредактировали информацию об игре!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } + + return json_encode($this->data); + } + + public function delete($gameid = null) { + $this->document->setActiveSection('admin'); + $this->document->setActiveItem('games'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('games'); + + $error = $this->validate($gameid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'admin/games/index'); + } + + $this->gamesModel->deleteGame($gameid); + + $this->session->data['success'] = "Вы успешно удалили игру!"; + $this->response->redirect($this->config->url . 'admin/games/index'); + return null; + } + + private function validate($gameid) { + $result = null; + + if(!$this->gamesModel->getTotalGames(array('game_id' => (int)$gameid))) { + $result = "Запрашиваемая игра не существует!"; + } + return $result; + } + + private function validatePOST() { + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + + $result = null; + + $name = @$this->request->post['name']; + $code = @$this->request->post['code']; + $query = @$this->request->post['query']; + $minslots = @$this->request->post['minslots']; + $maxslots = @$this->request->post['maxslots']; + $minport = @$this->request->post['minport']; + $maxport = @$this->request->post['maxport']; + $price = @$this->request->post['price']; + $status = @$this->request->post['status']; + $cpu = @$this->request->post['cores']; + $ram = @$this->request->post['ram']; + $ssd = @$this->request->post['ssd']; + + if(mb_strlen($name) < 2 || mb_strlen($name) > 92) { + $result = "Название игры должно содержать от 2 до 92 символов!"; + } + elseif(mb_strlen($code) < 2 || mb_strlen($code) > 8) { + $result = "Код игры должен содержать от 2 до 8 символов!"; + } + elseif(!in_array($query, $this->getQueryDrivers())) { + $result = "Укажите допустимый Query-драйвер."; + } + elseif($maxslots < $minslots) + { + $result = "Укажите допустимый интервал слотов."; + } + elseif($maxport < $minport) + { + $result = "Укажите допустимый интервал портов."; + } + elseif(!$validateLib->money($price)) { + $result = "Укажите допустимую стоимость!"; + } + elseif(!$validateLib->money($cpu)) { + $result = "Укажите допустимое количество ядер!"; + } + elseif(!$validateLib->money($ram)) { + $result = "Укажите допустимый объем оперативной памяти!"; + } + elseif(!$validateLib->money($ssd)) { + $result = "Укажите допустимую объем жесткого диска!"; + } + elseif($status < 0 || $status > 1) { + $result = "Укажите допустимый статус!"; + } + return $result; + } + + function getQueryDrivers() { + $result = array(); + $drivers = glob(ENGINE_DIR . 'libs/query/*.driver.php'); + foreach ($drivers as $filename) { + $result[] = basename($filename, ".driver.php"); + } + return $result; + } +} +?> diff --git a/panel/application/controllers/admin/games/index.php b/panel/application/controllers/admin/games/index.php new file mode 100644 index 0000000..3b1c629 --- /dev/null +++ b/panel/application/controllers/admin/games/index.php @@ -0,0 +1,47 @@ +document->setActiveSection('admin/games'); + $this->document->setActiveItem('index'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->library('pagination'); + $this->load->model('games'); + + $options = array( + 'start' => ($page - 1) * $this->limit, + 'limit' => $this->limit + ); + + $total = $this->gamesModel->getTotalGames(); + $games = $this->gamesModel->getGames(array(), array(), $options); + + $paginationUrl = '/admin/games/index/index/{page}'; + $paginationLib = new paginationLibrary(); + $paginationLib->total = $total; + $paginationLib->page = $page; + $paginationLib->limit = $this->limit; + $paginationLib->url = $paginationUrl; + $pagination = $paginationLib->render(); + + $this->data['games'] = $games; + $this->data['pagination'] = $pagination; + + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/games/index', $this->data); + } +} +?> diff --git a/panel/application/controllers/admin/index.php b/panel/application/controllers/admin/index.php new file mode 100644 index 0000000..0b588ec --- /dev/null +++ b/panel/application/controllers/admin/index.php @@ -0,0 +1,62 @@ +document->setActiveSection('admin'); + $this->document->setActiveItem('index'); + + if(!$this->user->isLogged()) { + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 2) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $getlvl = $this->user->getAccessLevel(); + $this->data['getlvl'] = $getlvl; + + $this->load->model('servers'); + $this->load->model('tickets'); + $this->load->model('users'); + $this->load->model('invoices'); + $this->load->model('waste'); + + $userid = $this->user->getId(); + + + $options = array( + 'start' => 0, + 'limit' => 50000 + ); + + $tickets = $this->ticketsModel->getTickets(array(), array('users'), array(), array()); + $this->data['tickets'] = $tickets; + + $tservers = $this->serversModel->getServers(array(), array('games', 'locations'), array(), array()); + $this->data['tservers'] = $tservers; + + $invoices = $this->invoicesModel->getInvoices(array(), array('users'), array(), $options); + $this->data['invoices'] = $invoices; + + $users = $this->usersModel->getUsers(array(), array(), $options); + $this->data['users'] = $users; + + $hostin = array( + 'waste_date_add' => 'DESC' + ); + $pl = array( + 'start' => 0, + 'limit' => 10 + ); + $waste = $this->wasteModel->getWaste(array(), array('users'), $hostin, $pl); + $this->data['waste'] = $waste; + + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/index', $this->data); + } +} +?> \ No newline at end of file diff --git a/panel/application/controllers/admin/infobox/index.php b/panel/application/controllers/admin/infobox/index.php new file mode 100644 index 0000000..68b0b5e --- /dev/null +++ b/panel/application/controllers/admin/infobox/index.php @@ -0,0 +1,53 @@ +document->setActiveSection('admin/infobox'); + $this->document->setActiveItem('index'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 2) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->library('pagination'); + $this->load->model('mail'); + + $getData = array(); + + $getSort = array( + 'status' => 'DESC', + 'inbox_date_add' => 'DESC' + ); + + $getOptions = array( + 'start' => ($page - 1) * $this->limit, + 'limit' => $this->limit + ); + + $total = $this->mailModel->getTotalInbox($getData); + $this->data['mail'] = $this->mailModel->getInboxs($getData, $getSort, $getOptions); + + $paginationUrl = '/admin/infobox/index/index/{page}'; + $paginationLib = new paginationLibrary(); + $paginationLib->total = $total; + $paginationLib->page = $page; + $paginationLib->limit = $this->limit; + $paginationLib->url = $paginationUrl; + $pagination = $paginationLib->render(); + + $this->data['pagination'] = $pagination; + + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/infobox/index', $this->data); + } +} +?> \ No newline at end of file diff --git a/panel/application/controllers/admin/infobox/send.php b/panel/application/controllers/admin/infobox/send.php new file mode 100644 index 0000000..ea05ae4 --- /dev/null +++ b/panel/application/controllers/admin/infobox/send.php @@ -0,0 +1,91 @@ +document->setActiveSection('admin/infobox'); + $this->document->setActiveItem('send'); + $this->data['url'] = $this->config->url; + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('mail'); + $this->data['mail'] = $this->mailModel->getInboxById($id); + + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/infobox/send', $this->data); + } + + public function sendMForm($id = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 3) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('mail'); + $this->load->library('mail'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + if(@$this->request->post['msg'] == ""){ + $this->data['status'] = "error"; + $this->data['error'] = "Введите текст ответа!"; + }elseif(@$this->request->post['msg'] != ""){ + $text = @$this->request->post['msg']; + $dell = @$this->request->post['dell']; + $data = $this->mailModel->getInboxById($id); + + $email = $data['user_email']; + $firstname = $data['user_firstname']; + $lastname = $data['user_lastname']; + + $mailLib = new mailLibrary(); + $mailLib->setFrom($this->config->mail_from); + $mailLib->setSender($this->config->mail_sender); + $mailLib->setTo($email); + $mailLib->setSubject('Ответ на ваше сообщение'); + + $mailData = array(); + $mailData['firstname'] = $firstname; + $mailData['lastname'] = $lastname; + $mailData['text'] = $text; + + $texts = $this->load->view('mail/infobox/user', $mailData); + + $mailLib->setText($texts); + $mailLib->send(); + + + if($dell) { + $this->mailModel->deleteInbox($id); + $this->data['status'] = "success"; + $this->data['success'] = "Сообщение отправлено, и удалено!"; + } else { + $this->mailModel->updateInbox($id, array('status' => 0)); + $this->data['status'] = "success"; + $this->data['success'] = "Сообщение отправлено!"; + } + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Не POST данные"; + } + return json_encode($this->data); + } + +} +?> \ No newline at end of file diff --git a/panel/application/controllers/admin/invoices/index.php b/panel/application/controllers/admin/invoices/index.php new file mode 100644 index 0000000..6564b50 --- /dev/null +++ b/panel/application/controllers/admin/invoices/index.php @@ -0,0 +1,59 @@ +document->setActiveSection('admin/invoices'); + $this->document->setActiveItem('index'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 2) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->library('pagination'); + $this->load->model('invoices'); + + $userid = @$this->request->get['userid']; + + $getData = array(); + + if(!empty($userid)) { + $getData['invoices.user_id'] = (int)$userid; + } + + $getOptions = array( + 'start' => ($page - 1) * $this->limit, + 'limit' => $this->limit + ); + + $total = $this->invoicesModel->getTotalInvoices($getData); + $invoices = $this->invoicesModel->getInvoices($getData, array('users'), array(), $getOptions); + + $paginationUrl = '/admin/invoices/index/index/{page}'; + if(!empty($userid)) { + $paginationUrl .= '&userid=' . $userid; + } + + $paginationLib = new paginationLibrary(); + $paginationLib->total = $total; + $paginationLib->page = $page; + $paginationLib->limit = $this->limit; + $paginationLib->url = $paginationUrl; + $pagination = $paginationLib->render(); + + $this->data['invoices'] = $invoices; + $this->data['pagination'] = $pagination; + + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/invoices/index', $this->data); + } +} +?> \ No newline at end of file diff --git a/panel/application/controllers/admin/locations/create.php b/panel/application/controllers/admin/locations/create.php new file mode 100644 index 0000000..039de65 --- /dev/null +++ b/panel/application/controllers/admin/locations/create.php @@ -0,0 +1,110 @@ +document->setActiveSection('admin/locations'); + $this->document->setActiveItem('create'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/locations/create', $this->data); + } + + public function ajax() { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 3) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('locations'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $name = @$this->request->post['name']; + $ip = @$this->request->post['ip']; + $ip2 = @$this->request->post['ip2']; + $user = @$this->request->post['user']; + $password = @$this->request->post['password']; + $password2 = @$this->request->post['password2']; + $status = @$this->request->post['status']; + + $locationData = array( + 'location_name' => $name, + 'location_ip' => $ip, + 'location_ip2' => $ip2, + 'location_user' => $user, + 'location_password' => $password, + 'location_status' => (int)$status + ); + + $this->locationsModel->createLocation($locationData); + + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно создали локацию!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } + + return json_encode($this->data); + } + + private function validatePOST() { + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + + $result = null; + + $name = @$this->request->post['name']; + $ip = @$this->request->post['ip']; + $ip2 = @$this->request->post['ip2']; + $user = @$this->request->post['user']; + $password = @$this->request->post['password']; + $password2 = @$this->request->post['password2']; + $status = @$this->request->post['status']; + + if(mb_strlen($name) < 2 || mb_strlen($name) > 32) { + $result = "Название локации должно содержать от 2 до 32 символов!"; + } + elseif(!$validateLib->ip($ip)) { + $result = "Укажите допустимый IP!"; + } + elseif(!$validateLib->ip($ip2)) { + $result = "Укажите допустимый IP!"; + } + elseif(mb_strlen($user) < 2 || mb_strlen($user) > 32) { + $result = "Имя пользователя должно содержать от 2 до 32 символов!"; + } + elseif(!$validateLib->password($password)) { + $result = "Пароль должен содержать от 6 до 32 латинских букв, цифр и знаков ,.!?_-!"; + } + elseif($password != $password2) { + $result = "Введенные вами пароли не совпадают!"; + } + elseif($status < 0 || $status > 1) { + $result = "Укажите допустимый статус!"; + } + return $result; + } +} +?> diff --git a/panel/application/controllers/admin/locations/edit.php b/panel/application/controllers/admin/locations/edit.php new file mode 100644 index 0000000..2a7717f --- /dev/null +++ b/panel/application/controllers/admin/locations/edit.php @@ -0,0 +1,171 @@ +document->setActiveSection('admin/locations'); + $this->document->setActiveItem('create'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('locations'); + + $error = $this->validate($locationid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'admin/locations/index'); + } + + $location = $this->locationsModel->getLocationById($locationid); + + $this->data['location'] = $location; + + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/locations/edit', $this->data); + } + + public function ajax($locationid = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 3) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('locations'); + + $error = $this->validate($locationid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $name = @$this->request->post['name']; + $ip = @$this->request->post['ip']; + $ip2 = @$this->request->post['ip2']; + $user = @$this->request->post['user']; + $password = @$this->request->post['password']; + $password2 = @$this->request->post['password2']; + $editpassword = @$this->request->post['editpassword']; + $status = @$this->request->post['status']; + $location_games = @$this->request->post['location_games']; + + $locationData = array( + 'location_name' => $name, + 'location_ip' => $ip, + 'location_ip2' => $ip2, + 'location_user' => $user, + 'location_status' => (int)$status, + 'location_games' => $location_games + ); + + if($editpassword) { + $locationData['location_password'] = $password; + } + + $this->locationsModel->updateLocation($locationid, $locationData); + + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно отредактировали локацию!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } + + return json_encode($this->data); + } + + public function delete($locationid = null) { + $this->document->setActiveSection('admin'); + $this->document->setActiveItem('locations'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('locations'); + + $error = $this->validate($locationid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'admin/locations/index'); + } + + $this->locationsModel->deleteLocation($locationid); + + $this->session->data['success'] = "Вы успешно удалили локацию!"; + $this->response->redirect($this->config->url . 'admin/locations/index'); + return null; + } + + private function validate($locationid) { + $result = null; + + if(!$this->locationsModel->getTotalLocations(array('location_id' => (int)$locationid))) { + $result = "Запрашиваемая локация не существует!"; + } + return $result; + } + + private function validatePOST() { + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + + $result = null; + + $name = @$this->request->post['name']; + $ip = @$this->request->post['ip']; + $user = @$this->request->post['user']; + $editpassword = @$this->request->post['editpassword']; + $password = @$this->request->post['password']; + $password2 = @$this->request->post['password2']; + $status = @$this->request->post['status']; + + if(mb_strlen($name) < 2 || mb_strlen($name) > 32) { + $result = "Название локации должно содержать от 2 до 32 символов!"; + } + elseif(!$validateLib->ip($ip)) { + $result = "Укажите допустимый IP!"; + } + elseif(mb_strlen($user) < 2 || mb_strlen($user) > 32) { + $result = "Имя пользователя должно содержать от 2 до 32 символов!"; + } + elseif($editpassword) { + if(!$validateLib->password($password)) { + $result = "Пароль должен содержать от 6 до 32 латинских букв, цифр и знаков ,.!?_-!"; + } + elseif($password != $password2) { + $result = "Введенные вами пароли не совпадают!"; + } + } + elseif($status < 0 || $status > 1) { + $result = "Укажите допустимый статус!"; + } + return $result; + } +} +?> diff --git a/panel/application/controllers/admin/locations/index.php b/panel/application/controllers/admin/locations/index.php new file mode 100644 index 0000000..7b41b52 --- /dev/null +++ b/panel/application/controllers/admin/locations/index.php @@ -0,0 +1,47 @@ +document->setActiveSection('admin/locations'); + $this->document->setActiveItem('index'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->library('pagination'); + $this->load->model('locations'); + + $options = array( + 'start' => ($page - 1) * $this->limit, + 'limit' => $this->limit + ); + + $total = $this->locationsModel->getTotalLocations(); + $locations = $this->locationsModel->getLocations(array(), array(), $options); + + $paginationUrl = '/admin/locations/index/index/{page}'; + $paginationLib = new paginationLibrary(); + $paginationLib->total = $total; + $paginationLib->page = $page; + $paginationLib->limit = $this->limit; + $paginationLib->url = $paginationUrl; + $pagination = $paginationLib->render(); + + $this->data['locations'] = $locations; + $this->data['pagination'] = $pagination; + + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/locations/index', $this->data); + } +} +?> \ No newline at end of file diff --git a/panel/application/controllers/admin/mods/create.php b/panel/application/controllers/admin/mods/create.php new file mode 100644 index 0000000..3cab8c7 --- /dev/null +++ b/panel/application/controllers/admin/mods/create.php @@ -0,0 +1,117 @@ +document->setActiveSection('admin/mods'); + $this->document->setActiveItem('create'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + $this->load->model('games'); + $options = array( + 'start' => 0, + 'limit' => $this->limit + ); + $games = $this->gamesModel->getGames(array(), array(), $options); + $this->data['games'] = $games; + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/mods/create', $this->data); + } + + public function ajax() { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 3) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('servers'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $name = @$this->request->post['name']; + $gameid = @$this->request->post['gameid']; + $arch = @$this->request->post['arch']; + $textx = @$this->request->post['textx']; + $img = @$this->request->post['img']; + $status = @$this->request->post['status']; + $price = @$this->request->post['price']; + + $uploaddir = (TMP_DIR . 'mods/'); + $apend = $_FILES['userfile']['name']; + $uploadfile = "$uploaddir$apend"; + + if($_FILES['userfile']['size'] > 1024*90*1024) { + $this->data['error'] = 'Размер файла не должен превышать 90МБ'; + $this->data['status'] = "error"; + } + if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) + $dir = "".$this->config->url."tmp/mods/".$apend.""; + + $modsData = array( + 'game_id' => $gameid, + 'mod_name' => $name, + 'mod_url' => $dir, + 'mod_status' => (int)$status, + 'mod_textx' => $textx, + 'mod_img' => $img, + 'mod_arch' => $apend, + 'mod_price' => $price + ); + $this->serversModel->createMod($modsData); + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно создали мод!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } + + return json_encode($this->data); + } + + private function validatePOST() { + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + + $result = null; + + $name = @$this->request->post['name']; + $gameid = @$this->request->post['gameid']; + $arch = @$this->request->post['arch']; + $status = @$this->request->post['status']; + $textx = @$this->request->post['textx']; + $price = @$this->request->post['price']; + + if(mb_strlen($name) < 2 || mb_strlen($name) > 32) { + $result = "Название мода должно содержать от 2 до 32 символов!"; + } + elseif(mb_strlen($textx) < 2 || mb_strlen($textx) > 500) { + $result = "Описание должно содержать от 2 до 500 символов!"; + } + elseif($status < 0 || $status > 1) { + $result = "Укажите допустимый статус!"; + } + elseif(0 > $price || $price > 5000) { + $result = "Укажите сумму от 0 до 5000 рублей!"; + } + return $result; + } +} +?> diff --git a/panel/application/controllers/admin/mods/edit.php b/panel/application/controllers/admin/mods/edit.php new file mode 100644 index 0000000..50328f1 --- /dev/null +++ b/panel/application/controllers/admin/mods/edit.php @@ -0,0 +1,162 @@ +document->setActiveSection('admin/mods'); + $this->document->setActiveItem('edit'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('servers'); + + $error = $this->validate($modid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'admin/mods/index'); + } + + $mod = $this->serversModel->getModById($modid); + + $this->data['mod'] = $mod; + $this->load->model('games'); + $options = array( + 'start' => 0, + 'limit' => $this->limit + ); + $games = $this->gamesModel->getGames(array(), array(), $options); + $this->data['games'] = $games; + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/mods/edit', $this->data); + } + + public function ajax($modid = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 3) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('servers'); + + $error = $this->validate($modid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $gameid = @$this->request->post['gameid']; + $name = @$this->request->post['name']; + $url = @$this->request->post['url']; + $status = @$this->request->post['status']; + $textx = @$this->request->post['textx']; + $img = @$this->request->post['img']; + $arch = @$this->request->post['arch']; + $price = @$this->request->post['price']; + + $modsData = array( + 'game_id' => $gameid, + 'mod_name' => $name, + 'mod_url' => $url, + 'mod_status' => (int)$status, + 'mod_textx' => $textx, + 'mod_img' => $img, + 'mod_arch' => $arch, + 'mod_price' => $price + ); + $this->serversModel->updateMod($modid, $modsData); + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно отредактировали мод!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } + + return json_encode($this->data); + } + + public function delete($modid = null) { + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('servers'); + + $error = $this->validate($modid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'admin/mods/index'); + } + + $this->serversModel->deleteMod($modid); + + $this->session->data['success'] = "Вы успешно удалили мод!"; + $this->response->redirect($this->config->url . 'admin/mods/index'); + return null; + } + + private function validate($modid) { + $result = null; + + if(!$this->serversModel->getTotalMods(array('mod_id' => (int)$modid))) { + $result = "Запрашиваемый мод не существует!"; + } + return $result; + } + + private function validatePOST() { + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + + $result = null; + + $gameid = @$this->request->post['gameid']; + $url = @$this->request->post['url']; + $arch = @$this->request->post['arch']; + $name = @$this->request->post['name']; + $status = @$this->request->post['status']; + $textx = @$this->request->post['textx']; + $img = @$this->request->post['img']; + $price = @$this->request->post['price']; + + if(mb_strlen($name) < 2 || mb_strlen($name) > 32) { + $result = "Название мода должно содержать от 2 до 32 символов!"; + } + elseif(0 > $price || $price > 5000) { + $result = "Укажите сумму от 0 до 5000 рублей!"; + } + elseif(mb_strlen($textx) < 2 || mb_strlen($textx) > 500) { + $result = "Описание должно содержать от 2 до 500 символов!"; + } + elseif($status < 0 || $status > 1) { + $result = "Укажите допустимый статус!"; + } + return $result; + } +} +?> diff --git a/panel/application/controllers/admin/mods/index.php b/panel/application/controllers/admin/mods/index.php new file mode 100644 index 0000000..35d99dc --- /dev/null +++ b/panel/application/controllers/admin/mods/index.php @@ -0,0 +1,47 @@ +document->setActiveSection('admin/mods'); + $this->document->setActiveItem('index'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->library('pagination'); + $this->load->model('servers'); + + $options = array( + 'start' => ($page - 1) * $this->limit, + 'limit' => $this->limit + ); + + $total = $this->serversModel->getTotalMods(); + $mods = $this->serversModel->getMods(array(),array('games'),array(), $options); + + $paginationUrl = '/admin/mods/index/index/{page}'; + $paginationLib = new paginationLibrary(); + $paginationLib->total = $total; + $paginationLib->page = $page; + $paginationLib->limit = $this->limit; + $paginationLib->url = $paginationUrl; + $pagination = $paginationLib->render(); + + $this->data['mods'] = $mods; + $this->data['pagination'] = $pagination; + + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/mods/index', $this->data); + } +} +?> \ No newline at end of file diff --git a/panel/application/controllers/admin/news/create.php b/panel/application/controllers/admin/news/create.php new file mode 100644 index 0000000..aa50ece --- /dev/null +++ b/panel/application/controllers/admin/news/create.php @@ -0,0 +1,79 @@ +document->setActiveSection('admin/news'); + $this->document->setActiveItem('create'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/news/create', $this->data); + } + + public function ajax($ticketid = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 3) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('news'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $name = @$this->request->post['name']; + $text = @$this->request->post['text']; + $userid = $this->user->getId(); + + $newsData = array( + 'user_id' => $userid, + 'news_title' => $name, + 'news_text' => $text + ); + $newsid = $this->newsModel->createNews($newsData); + + + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно создали новость!"; + $this->data['id'] = $newsid; + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } + + return json_encode($this->data); + } + + private function validatePOST() { + $result = null; + + $name = @$this->request->post['name']; + $text = @$this->request->post['text']; + + if(mb_strlen($name) < 6 || mb_strlen($name) > 100) { + $result = "Название новости должно содержать от 2 до 100 символов!"; + } + elseif(mb_strlen($text) < 10 || mb_strlen($text) > 1000) { + $result = "Текст новости должен содержать от 2 до 1000 символов!"; + } + return $result; + } +} diff --git a/panel/application/controllers/admin/news/edit.php b/panel/application/controllers/admin/news/edit.php new file mode 100644 index 0000000..1901d5c --- /dev/null +++ b/panel/application/controllers/admin/news/edit.php @@ -0,0 +1,135 @@ +document->setActiveSection('admin/news'); + $this->document->setActiveItem('edit'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('news'); + + $error = $this->validate($newid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'admin/news/index'); + } + + $new = $this->newsModel->getNewsById($newid); + + $this->data['new'] = $new; + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/news/edit', $this->data); + } + + public function ajax($newid = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 3) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('news'); + + $error = $this->validate($newid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $name = @$this->request->post['name']; + $text = @$this->request->post['text']; + $locationData = array( + 'news_title' => $name, + 'news_text' => $text + ); + + + $this->newsModel->updateNews($newid, $locationData); + + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно отредактировали новость!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } + + return json_encode($this->data); + } + + public function delete($newid = null) { + $this->document->setActiveSection('admin'); + $this->document->setActiveItem('locations'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('news'); + + $error = $this->validate($newid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'admin/news/index'); + } + + $this->newsModel->deleteNews($newid); + + $this->session->data['success'] = "Вы успешно удалили новость!"; + $this->response->redirect($this->config->url . 'admin/news/index'); + return null; + } + + private function validate($newid) { + $result = null; + + if(!$this->newsModel->getTotalNews(array('news_id' => (int)$newid))) { + $result = "Запрашиваемая новость не существует!"; + } + return $result; + } + + private function validatePOST() { + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + + $result = null; + + $name = @$this->request->post['name']; + $text = @$this->request->post['text']; + if(mb_strlen($name) < 2 || mb_strlen($name) > 100) { + $result = "Текст должен содержать от 2 до 100 символов!"; + } + if(mb_strlen($text) < 2 || mb_strlen($text) > 1000) { + $result = "Текст должен содержать от 2 до 1000 символов!"; + } + return $result; + } +} +?> diff --git a/panel/application/controllers/admin/news/index.php b/panel/application/controllers/admin/news/index.php new file mode 100644 index 0000000..18c2b59 --- /dev/null +++ b/panel/application/controllers/admin/news/index.php @@ -0,0 +1,49 @@ +document->setActiveSection('admin/news'); + $this->document->setActiveItem('index'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->library('pagination'); + $this->load->model('news'); + $sort = array( + 'news_date_add' => 'DESC' + ); + $options = array( + 'start' => ($page - 1) * $this->limit, + 'limit' => $this->limit + ); + + $total = $this->newsModel->getTotalNews(); + $news = $this->newsModel->getNews(array(), array('users'), $sort, $options); + + $paginationUrl = '/admin/news/index/index/{page}'; + $paginationLib = new paginationLibrary(); + $paginationLib->total = $total; + $paginationLib->page = $page; + $paginationLib->limit = $this->limit; + $paginationLib->url = $paginationUrl; + $pagination = $paginationLib->render(); + + $this->data['news'] = $news; + $this->data['pagination'] = $pagination; + + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/news/index', $this->data); + } +} +?> diff --git a/panel/application/controllers/admin/promo/create.php b/panel/application/controllers/admin/promo/create.php new file mode 100644 index 0000000..71f222f --- /dev/null +++ b/panel/application/controllers/admin/promo/create.php @@ -0,0 +1,86 @@ +document->setActiveSection('admin/promo'); + $this->document->setActiveItem('create'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/promo/create', $this->data); + } + + public function ajax() { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 3) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('promos'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $cod = @$this->request->post['cod']; + $uses = @$this->request->post['uses']; + $skidka = @$this->request->post['skidka']; + + $locationData = array( + 'cod' => $cod, + 'uses' => $uses, + 'used' => 0, + 'skidka' => (int)$skidka + ); + + $this->promosModel->createPromo($locationData); + + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно создали промо-Код!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } + + return json_encode($this->data); + } + + private function validatePOST() { + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + + $result = null; + + $cod = @$this->request->post['cod']; + $uses = @$this->request->post['uses']; + $skidka = @$this->request->post['skidka']; + + if(mb_strlen($cod) < 2 || mb_strlen($cod) > 32) { + $result = "Код должен содержать от 2 до 32 символов!"; + } + elseif(mb_strlen($uses) < 1 || mb_strlen($uses) > 10000) { + $result = "Введите количество использований от 1 до 10000!"; + } + + return $result; + } +} +?> diff --git a/panel/application/controllers/admin/promo/edit.php b/panel/application/controllers/admin/promo/edit.php new file mode 100644 index 0000000..79203e1 --- /dev/null +++ b/panel/application/controllers/admin/promo/edit.php @@ -0,0 +1,142 @@ +document->setActiveSection('admin/promo'); + $this->document->setActiveItem('edit'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('promos'); + + $error = $this->validate($promoid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'admin/promo/index'); + } + + $promo= $this->promosModel->getpromoById($promoid); + + $this->data['promo'] = $promo; + + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/promo/edit', $this->data); + } + + public function ajax($promoid = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 3) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('promos'); + + $error = $this->validate($promoid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $cod = @$this->request->post['cod']; + $uses = @$this->request->post['uses']; + $skidka = @$this->request->post['skidka']; + + $locationData = array( + 'cod' => $cod, + 'uses' => $uses, + 'skidka' => (int)$skidka + ); + + + $this->promosModel->updatepromo($promoid, $locationData); + + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно отредактировали промо-код!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } + + return json_encode($this->data); + } + + public function delete($promoid = null) { + $this->document->setActiveSection('admin'); + $this->document->setActiveItem('locations'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('promos'); + + $error = $this->validate($promoid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'admin/promo/index'); + } + + $this->promosModel->deletepromo($promoid); + + $this->session->data['success'] = "Вы успешно удалили промо-код!"; + $this->response->redirect($this->config->url . 'admin/promo/index'); + return null; + } + + private function validate($promoid) { + $result = null; + + if(!$this->promosModel->getTotalpromo(array('id' => (int)$promoid))) { + $result = "Запрашиваемый код не существует!"; + } + return $result; + } + + private function validatePOST() { + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + + $result = null; + + $cod = @$this->request->post['cod']; + $uses = @$this->request->post['uses']; + $skidka = @$this->request->post['skidka']; + + if(mb_strlen($cod) < 2 || mb_strlen($cod) > 32) { + $result = "Код должен содержать от 2 до 32 символов!"; + } + elseif(mb_strlen($uses) < 1 || mb_strlen($uses) > 10000) { + $result = "Введите количество использований от 1 до 10000!"; + } + + return $result; + } +} +?> diff --git a/panel/application/controllers/admin/promo/index.php b/panel/application/controllers/admin/promo/index.php new file mode 100644 index 0000000..6c7763e --- /dev/null +++ b/panel/application/controllers/admin/promo/index.php @@ -0,0 +1,47 @@ +document->setActiveSection('admin/promo'); + $this->document->setActiveItem('index'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->library('pagination'); + $this->load->model('promos'); + + $options = array( + 'start' => ($page - 1) * $this->limit, + 'limit' => $this->limit + ); + + $total = $this->promosModel->getTotalpromo(); + $promos = $this->promosModel->getpromo(array(), array(), $options); + + $paginationUrl = '/admin/promo/index/index/{page}'; + $paginationLib = new paginationLibrary(); + $paginationLib->total = $total; + $paginationLib->page = $page; + $paginationLib->limit = $this->limit; + $paginationLib->url = $paginationUrl; + $pagination = $paginationLib->render(); + + $this->data['promos'] = $promos; + $this->data['pagination'] = $pagination; + + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/promo/index', $this->data); + } +} +?> diff --git a/panel/application/controllers/admin/repo/create.php b/panel/application/controllers/admin/repo/create.php new file mode 100644 index 0000000..5bac0cc --- /dev/null +++ b/panel/application/controllers/admin/repo/create.php @@ -0,0 +1,104 @@ +document->setActiveSection('admin/repo'); + $this->document->setActiveItem('create'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + $this->load->model('games'); + $options = array( + 'start' => 0, + 'limit' => $this->limit + ); + $games = $this->gamesModel->getGames(array(), array(), $options); + $this->data['games'] = $games; + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/repo/create', $this->data); + } + + public function ajax() { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 3) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('servers'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $name = @$this->request->post['name']; + $gameid = @$this->request->post['gameid']; + $url = @$this->request->post['url']; + $textx = @$this->request->post['textx']; + $img = @$this->request->post['img']; + $status = @$this->request->post['status']; + $price = @$this->request->post['price']; + + $repoData = array( + 'game_id' => $gameid, + 'repo_name' => $name, + 'repo_url' => $url, + 'repo_status' => (int)$status, + 'repo_textx' => $textx, + 'repo_img' => $img, + 'repo_price' => $price + ); + $this->serversModel->createRepo($repoData); + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно добавили файл в репозиторий!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } + + return json_encode($this->data); + } + + private function validatePOST() { + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + + $result = null; + + $name = @$this->request->post['name']; + $gameid = @$this->request->post['gameid']; + $status = @$this->request->post['status']; + $textx = @$this->request->post['textx']; + $price = @$this->request->post['price']; + + if(mb_strlen($name) < 2 || mb_strlen($name) > 32) { + $result = "Название файла должно содержать от 2 до 32 символов!"; + } + elseif(mb_strlen($textx) < 2 || mb_strlen($textx) > 500) { + $result = "Описание должно содержать от 2 до 500 символов!"; + } + elseif($status < 0 || $status > 1) { + $result = "Укажите допустимый статус!"; + } + elseif(0 > $price || $price > 5000) { + $result = "Укажите сумму от 0 до 5000 рублей!"; + } + return $result; + } +} +?> diff --git a/panel/application/controllers/admin/repo/edit.php b/panel/application/controllers/admin/repo/edit.php new file mode 100644 index 0000000..b15518a --- /dev/null +++ b/panel/application/controllers/admin/repo/edit.php @@ -0,0 +1,157 @@ +document->setActiveSection('admin/repo'); + $this->document->setActiveItem('edit'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('servers'); + + $error = $this->validate($repoid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'admin/repo/index'); + } + + $repo = $this->serversModel->getRepoById($repoid); + + $this->data['repo'] = $repo; + $this->load->model('games'); + $options = array( + 'start' => 0, + 'limit' => $this->limit + ); + $games = $this->gamesModel->getGames(array(), array(), $options); + $this->data['games'] = $games; + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/repo/edit', $this->data); + } + + public function ajax($repoid = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 3) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('servers'); + + $error = $this->validate($repoid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $name = @$this->request->post['name']; + $gameid = @$this->request->post['gameid']; + $url = @$this->request->post['url']; + $textx = @$this->request->post['textx']; + $img = @$this->request->post['img']; + $status = @$this->request->post['status']; + $price = @$this->request->post['price']; + + $repoData = array( + 'game_id' => $gameid, + 'repo_name' => $name, + 'repo_url' => $url, + 'repo_status' => (int)$status, + 'repo_textx' => $textx, + 'repo_img' => $img, + 'repo_price' => $price + ); + $this->serversModel->updateRepo($repoid, $repoData); + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно отредактировали файл в репозитории!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } + + return json_encode($this->data); + } + + public function delete($repoid = null) { + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('servers'); + + $error = $this->validate($repoid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'admin/repo/index'); + } + + $this->serversModel->deleteRepo($repoid); + + $this->session->data['success'] = "Вы успешно удалили файл с репозитория!"; + $this->response->redirect($this->config->url . 'admin/repo/index'); + return null; + } + + private function validate($repoid) { + $result = null; + + if(!$this->serversModel->getTotalRepos(array('repo_id' => (int)$repoid))) { + $result = "Запрашиваемый файл не существует!"; + } + return $result; + } + + private function validatePOST() { + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + + $result = null; + + $name = @$this->request->post['name']; + $gameid = @$this->request->post['gameid']; + $status = @$this->request->post['status']; + $textx = @$this->request->post['textx']; + $price = @$this->request->post['price']; + + if(mb_strlen($name) < 2 || mb_strlen($name) > 32) { + $result = "Название файла должно содержать от 2 до 32 символов!"; + } + elseif(mb_strlen($textx) < 2 || mb_strlen($textx) > 500) { + $result = "Описание должно содержать от 2 до 500 символов!"; + } + elseif($status < 0 || $status > 1) { + $result = "Укажите допустимый статус!"; + } + elseif(0 > $price || $price > 5000) { + $result = "Укажите сумму от 0 до 5000 рублей!"; + } + return $result; + } +} +?> diff --git a/panel/application/controllers/admin/repo/index.php b/panel/application/controllers/admin/repo/index.php new file mode 100644 index 0000000..b70503a --- /dev/null +++ b/panel/application/controllers/admin/repo/index.php @@ -0,0 +1,47 @@ +document->setActiveSection('admin/repo'); + $this->document->setActiveItem('index'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->library('pagination'); + $this->load->model('servers'); + + $options = array( + 'start' => ($page - 1) * $this->limit, + 'limit' => $this->limit + ); + + $total = $this->serversModel->getTotalRepos(); + $repo = $this->serversModel->getRepos(array(),array('games'),array(), $options); + + $paginationUrl = '/admin/repo/index/index/{page}'; + $paginationLib = new paginationLibrary(); + $paginationLib->total = $total; + $paginationLib->page = $page; + $paginationLib->limit = $this->limit; + $paginationLib->url = $paginationUrl; + $pagination = $paginationLib->render(); + + $this->data['repo'] = $repo; + $this->data['pagination'] = $pagination; + + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/repo/index', $this->data); + } +} +?> \ No newline at end of file diff --git a/panel/application/controllers/admin/servers/control.php b/panel/application/controllers/admin/servers/control.php new file mode 100644 index 0000000..67e6d9a --- /dev/null +++ b/panel/application/controllers/admin/servers/control.php @@ -0,0 +1,687 @@ +document->setActiveSection('admin/servers'); + $this->document->setActiveItem('control'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 2) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->library('query'); + $this->load->model('servers'); + + $error = $this->validate($serverid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'admin/servers/index'); + } + + $server = $this->serversModel->getServerById($serverid, array('users', 'games', 'locations')); + $this->data['server'] = $server; + + if($server['server_status'] == 2) { + $queryLib = new queryLibrary($server['game_query']); + $queryLib->connect($server['location_ip'], $server['server_port']); + $query = $queryLib->getInfo(); + $queryLib->disconnect(); + + $this->data['query'] = $query; + } + + if($server['server_status'] == 1 AND $server['game_code'] == "cs" || $server['game_code'] == "css" || $server['game_code'] == "csgo") { + if($server["game_code"] == "cs") { + $fps = array("300", "500", "1100"); + $this->data["fps"] = $fps; + } + + if($server["game_code"] == "csgo") { + $tickrate = array("64", "128"); + $this->data["tickrate"] = $tickrate; + } + + if($server["game_code"] == "css") { + $tickrate = array("66", "100"); + $this->data["tickrate"] = $tickrate; + } + } + + $stats = $this->serversModel->getServerStats($serverid, "NOW() - INTERVAL 1 DAY", "NOW()"); + $this->data['stats'] = $stats; + + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/servers/control', $this->data); + } + + public function actionserver($serverid = null, $actionserver = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 2) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->library('mail'); + $this->load->library('ssh2'); + $this->load->model('servers'); + + $error = $this->validate($serverid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + $server = $this->serversModel->getServerById($serverid, array('users', 'locations', 'games')); + + if($server['server_status'] == 3) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет установка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 4) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет переустановка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 5) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет создание BackUP сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 6) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет восстанновление сервера из BackUP!"; + return json_encode($this->data); + } else if($server['server_status'] == 7) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет обновление сервера!"; + return json_encode($this->data); + } else if($actionserver == "start" || $actionserver == "stop" || $actionserver == "restart" || $actionserver == "backup" || $actionserver == "unbackup") { + if($server["server_status"] == 0) { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер заблокирован!"; + return json_encode($this->data); + } + } + + switch($actionserver) { + case "start": { + if($server["server_status"] == 1) { + $stats = $this->serversModel->getHDD($server['server_id']); + if((int)$stats < $server['game_ssd']) { + $result = $this->serversModel->action($serverid, 'start'); + if($result["status"] == "success") { + $this->serversModel->deleteTask(array('task_name' => 'enable', 'server_id' => $serverid)); + $this->serversModel->updateServer($serverid, array("server_status" => 2)); + $logData = array( + 'server_id' => $serverid, + 'reason' => 'Успешный запуск сервера', + 'status' => 1 + ); + $this->serversModel->createLog($logData); + $this->data["status"] = "success"; + $this->data["success"] = "Вы успешно запустили сервер!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = $result["description"]; + } + } else { + $this->data["status"] = "error"; + $this->data["error"] = "Вы привысили ограничение размера директории на ". round($stats - $server['game_ssd'], 2) ."МБ, запуск сервера невозможен!"; + } + } else { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер должен быть выключен!"; + } + break; + } + + case "reinstall": { + if($server["server_status"] == 1) { + $logData = array( + 'server_id' => $serverid, + 'reason' => 'Сервер успешно поставлен на переустановку!', + 'status' => 2 + ); + $this->serversModel->createLog($logData); + $this->serversModel->updateServer($serverid, array('server_status' => 4, 'server_work' => 0)); + $this->data["status"] = "success"; + $this->data["success"] = "Сервер успешно поставлен на переустановку!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер должен быть выключен!"; + } + break; + } + + case "restart": { + if($server["server_status"] == 2) { + $stats = $this->serversModel->getHDD($server['server_id']); + if((int)$stats < $server['game_ssd']) { + $result = $this->serversModel->action($serverid, 'restart'); + if($result["status"] == "success") { + $this->serversModel->deleteTask(array('task_name' => 'restart', 'server_id' => $serverid)); + $logData = array( + 'server_id' => $serverid, + 'reason' => 'Успешный перезапуск сервера', + 'status' => 1 + ); + $this->serversModel->createLog($logData); + $this->data["status"] = "success"; + $this->data["success"] = "Вы успешно перезапустили сервер!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = $result["description"]; + } + } else { + $result = $this->serversModel->action($serverid, 'stop'); + if($result['status'] == "success") { + $this->serversModel->updateServer($serverid, array('server_status' => 1)); + $this->data["status"] = "error"; + $this->data["error"] = "Вы привысили ограничение размера директории на ". round($stats - $server['game_ssd'], 2) ."МБ, перезагрузка сервера невозможна!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = $result["description"]; + } + } + } else if($server["server_status"] == 2) { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер должен быть включен!"; + } + break; + } + + case "stop": { + if($server["server_status"] == 2) { + $result = $this->serversModel->action($serverid, 'stop'); + if($result["status"] == "success") { + $this->serversModel->deleteTask(array('task_name' => 'disable', 'server_id' => $serverid)); + $this->serversModel->deleteTask(array('task_name' => 'restart', 'server_id' => $serverid)); + $this->serversModel->updateServer($serverid, array("server_status" => 1, 'server_work' => 0)); + $logData = array( + 'server_id' => $serverid, + 'reason' => 'Успешное выключение сервера', + 'status' => 1 + ); + $this->serversModel->createLog($logData); + $this->data["status"] = "success"; + $this->data["success"] = "Вы успешно выключили сервер!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = $result["description"]; + } + } else { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер должен быть вылючен!"; + } + break; + } + + case 'backup': { + if($server['server_status'] == 1) { + $stats = $this->serversModel->getHDD($server['server_id']); + if((int)$stats < $server['game_ssd']) { + $this->serversModel->deleteTask(array('task_name' => 'restart', 'server_id' => $serverid)); + $this->serversModel->deleteTask(array('task_name' => 'enable', 'server_id' => $serverid)); + $this->serversModel->deleteTask(array('task_name' => 'disable', 'server_id' => $serverid)); + $this->serversModel->updateServer($serverid, array('server_status' => 5, 'server_work' => 0)); + $logData = array( + 'server_id' => $serverid, + 'reason' => 'Успешное начало создания BackUP сервера.', + 'status' => 1 + ); + $this->serversModel->createLog($logData); + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно начали создание BackUP сервера!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = "Вы привысили ограничение размера директории на ". round($stats - $server['game_ssd'], 2) ."МБ, создание бекапа сервера невозможено!"; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Сервер должен быть выключен!"; + } + break; + } + + case 'unbackup': { + if($server['server_status'] == 1) { + if (file_exists('ssh2.sftp://'.$server['location_user'].':'.$server['location_password'].'@'.$server['location_ip'].':22/home/cp/backups/gs'.$serverid.'.tar')) { + $this->serversModel->deleteTask(array('task_name' => 'restart', 'server_id' => $serverid)); + $this->serversModel->deleteTask(array('task_name' => 'enable', 'server_id' => $serverid)); + $this->serversModel->deleteTask(array('task_name' => 'disable', 'server_id' => $serverid)); + $this->serversModel->updateServer($serverid, array('server_status' => 6, 'server_work' => 0)); + $logData = array( + 'server_id' => $serverid, + 'reason' => 'Успешное начало восстановление BackUP сервера.', + 'status' => 1 + ); + $this->serversModel->createLog($logData); + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно восстановили BackUP сервера!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = "У сервера нет BackUP!"; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Сервер должен быть выключен!"; + } + break; + } + + case 'delete_backup': { + if($server['server_status'] == 1) { + if (file_exists('ssh2.sftp://'.$server['location_user'].':'.$server['location_password'].'@'.$server['location_ip'].':22/home/cp/backups/gs'.$serverid.'.tar')) { + $result = $this->serversModel->action($serverid, 'delete_backup'); + if($result["status"] == "success") { + $logData = array( + 'server_id' => $serverid, + 'reason' => 'Успешное удаление BackUP сервера', + 'status' => 1 + ); + $this->serversModel->createLog($logData); + $this->data["status"] = "success"; + $this->data["success"] = "Вы успешно удалили BackUP сервера!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = $result["description"]; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "У сервера нет BackUP!"; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Сервер должен быть выключен!"; + } + break; + } + + case 'block': { + if($server['server_status'] == 1) { + $this->serversModel->updateServer($serverid, array('server_status' => 0)); + $this->serversModel->action($serverid, "block"); + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно заблокировали сервер!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Сервер должен быть выключен!"; + } + break; + } + case 'delete': { + if($server['server_status'] == 1) { + if($this->user->getAccessLevel() == 3){ + $mailLib = new mailLibrary(); + $mailLib->setFrom($this->config->mail_from); + $mailLib->setSender($this->config->mail_sender); + $result = $this->serversModel->action($serverid, 'delete'); + if($result['status'] == "success") { + if($server['server_mysql'] == 1 || $server['server_mysql'] == 2) { + $this->serversModel->action($serverid, "delete_mysql"); + } + $this->serversModel->deleteServer($serverid); + $this->serversModel->deleteServerStats($serverid); + $this->serversModel->deleteserverOwners($serverid); + $this->serversModel->deleteLog($serverid); + + $firewall = $this->serversModel->getFirewallsById($serverid); + + if ($firewall) { + foreach ($firewall as $item2) { + $ssh2Lib = new ssh2Library(); + $link = $ssh2Lib->connect($server['location_ip'], $server['location_user'], $server['location_password']); + + $ssh2Lib->execute($link, "iptables -D INPUT -s ".$item2['server_ip']." -p udp -d ".$server['location_ip']." --dport ".$server['server_port']." -j DROP;"); + $ssh2Lib->execute($link, "iptables -D INPUT -s ".$item2['server_ip']." -p tcp -d ".$server['location_ip']." --dport ".$server['server_port']." -j DROP;"); + + $ssh2Lib->disconnect($link); + + $this->serversModel->deleteFirewallDB($item2['firewall_id']); + } + } + + $mailLib->setTo($server['user_email']); + $mailLib->setSubject("Удаление сервера администратором #$serverid"); + + $mailData = array(); + $mailData['firstname'] = $server['user_firstname']; + $mailData['lastname'] = $server['user_lastname']; + $mailData['serverid'] = $serverid; + + $text = $this->load->view('mail/servers/deleted', $mailData); + + $mailLib->setText($text); + $mailLib->send(); + + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно удалили сервер!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = $result['description']; + } + } else { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Сервер должен быть выключен!"; + } + break; + } + case 'unblock': { + if($server['server_status'] == 0) { + $this->serversModel->updateServer($serverid, array('server_status' => 1)); + $this->serversModel->action($serverid, "updatepassm"); + $this->serversModel->action($serverid, "updatepass"); + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно разблокировали сервер!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Сервер должен быть заблокирован!"; + } + break; + } + default: { + $this->data['status'] = "error"; + $this->data['error'] = "Вы выбрали несуществующее действие!"; + break; + } + } + + return json_encode($this->data); + } + + public function settingStart($serverid = null) { + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'news/index'); + } + if($this->user->getAccessLevel() < 2) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('servers'); + + $server = $this->serversModel->getServerById($serverid, array('games', 'locations')); + + $error = $this->validate($serverid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + if($server['server_status'] == 3) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет установка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 4) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет переустановка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 5) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет создание BackUP сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 6) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет восстанновление сервера из BackUP!"; + return json_encode($this->data); + } else if($server['server_status'] == 7) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет обновление сервера!"; + return json_encode($this->data); + } else if($server["server_status"] == 0) { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер заблокирован!"; + return json_encode($this->data); + } + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + if($server['server_status'] == 1){ + if($server["game_code"] == "cs" || $server["game_code"] == "css" || $server["game_code"] == "csgo" || $server["game_query"] == "samp") { + $rcon_password = @$this->request->post['rcon_password']; + if(mb_strlen($rcon_password) < 2 || mb_strlen($rcon_password) > 18) { + $this->data["status"] = "error"; + $this->data["error"] = "RCON Пароль должен содержать от 2 до 18 символов!"; + return json_encode($this->data); + } + $this->serversModel->updateServer($serverid, array('rcon_password' => $rcon_password)); + + if($server["game_code"] == "cs" || $server["game_code"] == "css" || $server["game_code"] == "csgo") { + $vac = @$this->request->post['vac']; + if(!in_array($vac, array("0", "1"))) { + $this->data["status"] = "error"; + $this->data["error"] = "Статус античита VAC указан неверно!"; + return json_encode($this->data); + } + $this->serversModel->updateServer($serverid, array('server_vac' => $vac)); + + $fastdl = @$this->request->post['fastdl']; + if(!in_array($fastdl, array("0", "1"))) { + $this->data["status"] = "error"; + $this->data["error"] = "Статус FastDL указан неверно!"; + return json_encode($this->data); + } + $this->serversModel->updateServer($serverid, array('fastdl_status' => $fastdl)); + + if($server["game_code"] == "cs") { + $fps = @$this->request->post['fps']; + if(!in_array($fps, array("300", "500", "1100"))) { + $this->data["status"] = "error"; + $this->data["error"] = "Параметр FPS указан неверно!"; + return json_encode($this->data); + } else { + $this->serversModel->updateServer($serverid, array('server_fps' => $fps)); + } + } + + if($server["game_code"] == "csgo") { + $tickrate = @$this->request->post['tickrate']; + if(!in_array($tickrate, array("64", "128"))) { + $this->data["status"] = "error"; + $this->data["error"] = "Параметр Tickrate указан неверно!"; + return json_encode($this->data); + } else { + $this->serversModel->updateServer($serverid, array('server_tickrate' => $tickrate)); + } + } + + if($server["game_code"] == "css") { + $tickrate = @$this->request->post['tickrate']; + if(!in_array($tickrate, array("66", "100"))) { + $this->data["status"] = "error"; + $this->data["error"] = "Параметр Tickrate указан неверно!"; + return json_encode($this->data); + } else { + $this->serversModel->updateServer($serverid, array('server_tickrate' => $tickrate)); + } + } + } + + $this->data["status"] = "success"; + $this->data["success"] = "Параметры запуска успешно изменены!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = "Не для данной игры!"; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Сервер должен быть выключен!"; + } + } + return json_encode($this->data); + } + + private function validate($serverid) { + $result = null; + + if(!$this->serversModel->getTotalServers(array('server_id' => (int)$serverid))) { + $result = "Запрашиваемый сервер не существует!"; + } + return $result; + } + + private function validatePOST() { + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + + $result = null; + + $slots = @$this->request->post['slots']; + $editpassword = @$this->request->post['editpassword']; + $password = @$this->request->post['password']; + $password2 = @$this->request->post['password2']; + + if($editpassword) { + if(!$validateLib->password($password)) { + $result = "Пароль должен содержать от 6 до 32 латинских букв, цифр и знаков ,.!?_-!"; + } + elseif($password != $password2) { + $result = "Введенные вами пароли не совпадают!"; + } + } + return $result; + } + + public function mysqlhostin($serverid = null, $mysqlhostin = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 0) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('servers'); + + $error = $this->validate($serverid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + $server = $this->serversModel->getServerById($serverid); + switch($mysqlhostin) { + case 'mysqlon': { + if($server['server_mysql'] == 2) { + $this->serversModel->updateServer($serverid, array('server_mysql' => 1)); + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно включили базу данных gs$serverid!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = "База данных и так включена либо вы ее еще не создали!"; + } + break; + } + case 'mysqloff': { + if($server['server_mysql'] == 1) { + $this->serversModel->updateServer($serverid, array('server_mysql' => 2)); + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно выключили базу данных gs$serverid!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = "База данных и так выключена!"; + } + break; + } + case 'mysqlcr': { + if($server['server_mysql'] == 0) { + $result = $this->serversModel->action($serverid, 'create_mysql'); + if($result["status"] == "success") { + $this->serversModel->updateServer($serverid, array('server_mysql' => 2)); + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно создали базу данных gs$serverid!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = $result["description"]; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "База данных и так создана!"; + } + break; + } + default: { + $this->data['status'] = "error"; + $this->data['error'] = "Вы выбрали несуществующее действие!"; + break; + } + } + + return json_encode($this->data); + } + + public function getData($serverid = null) { + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 2) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('servers'); + $this->load->library('query'); + + $error = $this->validate($serverid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'servers/index'); + } + + $server = $this->serversModel->getServerById($serverid, array('games', 'locations')); + + if($server['server_status'] == 2) { + $queryLib = new queryLibrary($server['game_query']); + $queryLib->connect($server['location_ip'], $server['server_port']); + $query = $queryLib->getInfo(); + $queryLib->disconnect(); + + $sysload = $this->serversModel->getServerSystemLoad($serverid); + $ssd = round($sysload['ssd']); + $ssd_all = $server['game_ssd']; + $this->data['ssd'] = (int)(($ssd * 100) / $ssd_all); + $this->data['cpu'] = $sysload['cpu'] > 100 ? 100 : round($sysload['cpu']); + $this->data['ram'] = $sysload['ram'] > 100 ? 100 : round($sysload['ram']); + $this->data['players'] = $query['players']; + } else if($server['server_status'] == 3 || $server['server_status'] == 4) { + $this->data['ssd'] = 'N/A'; + $this->data['cpu'] = 'N/A'; + $this->data['ram'] = 'N/A'; + $this->data['players'] = 'N/A'; + } else { + $ssd = $this->serversModel->getHDD($serverid); + $ssd = round($ssd); + $ssd_all = $server['game_ssd']; + $this->data['ssd'] = (int)(($ssd * 100) / $ssd_all); + $this->data['cpu'] = 0; + $this->data['ram'] = 0; + $this->data['players'] = 0; + } + + return json_encode($this->data); + } +} +?> \ No newline at end of file diff --git a/panel/application/controllers/admin/servers/index.php b/panel/application/controllers/admin/servers/index.php new file mode 100644 index 0000000..bfb45b1 --- /dev/null +++ b/panel/application/controllers/admin/servers/index.php @@ -0,0 +1,234 @@ +document->setActiveSection('admin/servers'); + $this->document->setActiveItem('index'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 2) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->library('pagination'); + $this->load->model('servers'); + + $userid = @$this->request->get['userid']; + $gameid = @$this->request->get['gameid']; + $locationid = @$this->request->get['locationid']; + + $getData = array(); + + if(!empty($userid)) { + $getData['servers.user_id'] = (int)$userid; + } + if(!empty($gameid)) { + $getData['servers.game_id'] = (int)$gameid; + } + if(!empty($locationid)) { + $getData['servers.location_id'] = (int)$locationid; + } + + $getOptions = array( + 'start' => ($page - 1) * $this->limit, + 'limit' => $this->limit + ); + + + $total = $this->serversModel->getTotalServers($getData); + $servers = $this->serversModel->getServers($getData, array('games', 'locations'), array(), $getOptions); + + $paginationUrl = '/admin/servers/index/index/{page}'; + if(!empty($userid)) { + $paginationUrl .= '&userid=' . $userid; + } + if(!empty($gameid)) { + $paginationUrl .= '&gameid=' . $gameid; + } + if(!empty($locationid)) { + $paginationUrl .= '&locationid=' . $locationid; + } + + $paginationLib = new paginationLibrary(); + $paginationLib->total = $total; + $paginationLib->page = $page; + $paginationLib->limit = $this->limit; + $paginationLib->url = $paginationUrl; + $pagination = $paginationLib->render(); + + $this->data['servers'] = $servers; + $this->data['pagination'] = $pagination; + + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/servers/index', $this->data); + } + + public function action($serverid = null, $action = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 2) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('servers'); + $this->load->model('serverLog'); + + $error = $this->validate($serverid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + $server = $this->serversModel->getServerById($serverid, array('users', 'locations', 'games')); + + if($server['server_status'] == 3) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет установка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 4) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет переустановка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 5) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет создание BackUP сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 6) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет восстанновление сервера из BackUP!"; + return json_encode($this->data); + } else if($server['server_status'] == 7) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет обновление сервера!"; + return json_encode($this->data); + } else if($server["server_status"] == 0) { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер заблокирован!"; + return json_encode($this->data); + } + + switch($action) { + case "start": { + if($server["server_status"] == 1) { + $stats = $this->serversModel->getHDD($server['server_id']); + if((int)$stats < $server['game_ssd']) { + $result = $this->serversModel->action($serverid, 'start'); + if($result["status"] == "success") { + $this->serversModel->deleteTask(array('task_name' => 'enable', 'server_id' => $serverid)); + $this->serversModel->updateServer($serverid, array("server_status" => 2)); + $logData = array( + 'server_id' => $serverid, + 'reason' => 'Успешный запуск сервера', + 'status' => 1 + ); + $this->serversModel->createLog($logData); + $this->data["status"] = "success"; + $this->data["success"] = "Вы успешно запустили сервер!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = $result["description"]; + } + } else { + $this->data["status"] = "error"; + $this->data["error"] = "Вы привысили ограничение размера директории на ". round($stats - $server['game_ssd'], 2) ."МБ, запуск сервера невозможен!"; + } + } else { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер должен быть выключен!"; + } + break; + } + + case "restart": { + if($server["server_status"] == 2) { + $stats = $this->serversModel->getHDD($server['server_id']); + if((int)$stats < $server['game_ssd']) { + $result = $this->serversModel->action($serverid, 'restart'); + if($result["status"] == "success") { + $this->serversModel->deleteTask(array('task_name' => 'restart', 'server_id' => $serverid)); + $logData = array( + 'server_id' => $serverid, + 'reason' => 'Успешный перезапуск сервера', + 'status' => 1 + ); + $this->serversModel->createLog($logData); + $this->data["status"] = "success"; + $this->data["success"] = "Вы успешно перезапустили сервер!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = $result["description"]; + } + } else { + $result = $this->serversModel->action($serverid, 'stop'); + if($result['status'] == "success") { + $this->serversModel->updateServer($serverid, array('server_status' => 1)); + $this->data["status"] = "error"; + $this->data["error"] = "Вы привысили ограничение размера директории на ". round($stats - $server['game_ssd'], 2) ."МБ, перезагрузка сервера невозможна!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = $result["description"]; + } + } + } else if($server["server_status"] == 2) { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер должен быть включен!"; + } + break; + } + + case "stop": { + if($server["server_status"] == 2) { + $result = $this->serversModel->action($serverid, 'stop'); + if($result["status"] == "success") { + $this->serversModel->deleteTask(array('task_name' => 'disable', 'server_id' => $serverid)); + $this->serversModel->deleteTask(array('task_name' => 'restart', 'server_id' => $serverid)); + $this->serversModel->updateServer($serverid, array("server_status" => 1)); + $logData = array( + 'server_id' => $serverid, + 'reason' => 'Успешное выключение сервера', + 'status' => 1 + ); + $this->serversModel->createLog($logData); + $this->data["status"] = "success"; + $this->data["success"] = "Вы успешно выключили сервер!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = $result["description"]; + } + } else { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер должен быть вылючен!"; + } + break; + } + } + + return json_encode($this->data); + } + + private function validate($serverid) { + $result = null; + + $userid = $this->user->getId(); + + if(!$this->serversModel->getTotalServers(array('server_id' => (int)$serverid, 'user_id' => (int)$userid))) { + $result = "Запрашиваемый сервер не существует или у ват нету доступа!"; + } + return $result; + } +} +?> diff --git a/panel/application/controllers/admin/settings.php b/panel/application/controllers/admin/settings.php new file mode 100644 index 0000000..e40de64 --- /dev/null +++ b/panel/application/controllers/admin/settings.php @@ -0,0 +1,119 @@ +document->setActiveSection('admin/settings'); + $this->document->setActiveItem('index'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $userid = $this->user->getId(); + $this->load->model('users'); + + require(APPLICATION_DIR . 'config.php'); + $this->data['settings'] = $config; + unset($config); + + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/settings', $this->data); + } + + public function ajax() { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 3) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $userid = $this->user->getId(); + $this->load->model('users'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + + + $file = file_get_contents(APPLICATION_DIR . 'config.php'); + $file = str_replace(",", "", $file); + + $file = str_replace("', "", $file); + + $file = explode("\n",$file); + + $file2 = array(); + foreach($file as $line){ + if($line !== ''){ + $file2[] = $line; + } + } + unset($line); + $file = $file2; + unset($file2); + + $post = array(); + foreach($this->request->post as $post_string => $post_value){ + $post[$post_string] = $post_value; + if($post_string !== 'close'){ + $post['close'] = 'off'; + } + } + + foreach($post as $string => $value) { + for ($i = 0; $i < count($file); $i++) { + if (strpos($file[$i], $string) !== FALSE) { + $search_line = $file[$i]; + $file[$i] = "'".$string."' => '".$value."'"; + break; + } + } + if($search_line == null) { + $file[] = "'".$string."' => '".$value."'"; + } + unset($search_line); + } + + + + foreach($file as $line => $line2){ + if($line < count($file)-1 and $file[$line] != "\n"){ + $file[$line] = $line2.','; + } + } + + $file = implode("\n", $file); + $file = preg_replace('/([\r\n]){2,}/s', '\1', $file); + + $file2 = ''; + + file_put_contents(APPLICATION_DIR.'config.php', $file2); + + $this->data['status'] = "success"; + $this->data['success'] = "Настройки сохранены!"; + } + + return json_encode($this->data); + } + +} +?> diff --git a/panel/application/controllers/admin/statistics/index.php b/panel/application/controllers/admin/statistics/index.php new file mode 100644 index 0000000..ed93d08 --- /dev/null +++ b/panel/application/controllers/admin/statistics/index.php @@ -0,0 +1,76 @@ +document->setActiveSection('admin/statistics'); + $this->document->setActiveItem('index'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 2) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $userid = $this->user->getId(); + $this->load->model('users'); + + $this->getChild(array('common/admheader', 'common/footer')); + + + $this->load->model('invoices'); + $this->load->model('servers'); + $get_invoices = $this->invoicesModel->getStatisticsInvStatsById(); + $get_registers = $this->usersModel->getStatisticsRegistersById(); + $get_players = $this->serversModel->getStatisticsPlayers(); + $get_loads = $this->serversModel->getStatisticsLoad(); + + $charts = 'var invoices = [ '; + foreach($get_invoices as $item){ + $charts .= '['.(strtotime($item['invoice_date_add']))*1000 .', '.$item['SUM(`invoice_ammount`)'].'], '; + } + $charts .= '];'; + + $charts .= 'var registers = [ '; + foreach($get_registers as $item){ + $charts .= '['.(strtotime($item['mydate']))*1000 .', '.(int)$item['count(user_id)'].'], '; + } + $charts .= '];'; + + $charts .= 'var players = [ '; + foreach($get_players as $item){ + $charts .= '['.(strtotime($item['mydate']))*1000 .', '.(int)$item['sum(`server_stats_players`)'].'], '; + } + $charts .= '];'; + + $charts .= 'var loads1 = [ '; + foreach($get_loads as $item){ + $charts .= '['.(strtotime($item['mydate']))*1000 .', '.(int)$item['sum(`server_stats_cpu`)'].'], '; + } + $charts .= '];'; + + $charts .= 'var loads2 = [ '; + foreach($get_loads as $item){ + $charts .= '['.(strtotime($item['mydate']))*1000 .', '.(int)$item['sum(`server_stats_hdd`)'].'], '; + } + $charts .= '];'; + + $charts .= 'var loads3 = [ '; + foreach($get_loads as $item){ + $charts .= '['.(strtotime($item['mydate']))*1000 .', '.(int)$item['sum(`server_stats_ram`)'].'], '; + } + $charts .= '];'; + + $this->data['charts'] = $charts; + + + return $this->load->view('admin/statistics/index', $this->data); + } +} +?> diff --git a/panel/application/controllers/admin/ticketcategory/create.php b/panel/application/controllers/admin/ticketcategory/create.php new file mode 100644 index 0000000..68c5019 --- /dev/null +++ b/panel/application/controllers/admin/ticketcategory/create.php @@ -0,0 +1,81 @@ +document->setActiveSection('admin/ticketcategory'); + $this->document->setActiveItem('create'); + $this->data['url'] = $this->config->url; + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/ticketcategory/create', $this->data); + } + + public function ajax() { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 3) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('ticketsCategory'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $name = @$this->request->post['name']; + $status = @$this->request->post['status']; + + $adapData = array( + 'category_name' => $name, + 'category_status' => $status + ); + + $this->ticketsCategoryModel->createTicketCategory($adapData); + + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно создали категорию!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } + + return json_encode($this->data); + } + + private function validatePOST() { + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + + $result = null; + + $name = @$this->request->post['name']; + $status = @$this->request->post['status']; + + if(mb_strlen($name) < 2 || mb_strlen($name) > 32) { + $result = "Название категории должно содержать от 2 до 32 символов!"; + } + elseif($status < 0 || $status > 1) { + $result = "Укажите допустимый статус!"; + } + return $result; + } +} +?> \ No newline at end of file diff --git a/panel/application/controllers/admin/ticketcategory/edit.php b/panel/application/controllers/admin/ticketcategory/edit.php new file mode 100644 index 0000000..08c48a0 --- /dev/null +++ b/panel/application/controllers/admin/ticketcategory/edit.php @@ -0,0 +1,138 @@ +document->setActiveSection('admin/ticketcategory'); + $this->document->setActiveItem('edit'); + $this->data['url'] = $this->config->url; + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('ticketsCategory'); + + $error = $this->validate($categoryid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'admin/ticketcategory/index'); + } + + $category = $this->ticketsCategoryModel->getTicketCategoryById($categoryid); + + $this->data['category'] = $category; + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/ticketcategory/edit', $this->data); + } + + public function ajax($categoryid = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 3) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('ticketsCategory'); + + $error = $this->validate($categoryid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $name = @$this->request->post['name']; + $status = @$this->request->post['status']; + + $adapData = array( + 'category_name' => $name, + 'category_status' => (int)$status + ); + + + $this->ticketsCategoryModel->updateTicketCategory($categoryid, $adapData); + + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно отредактировали категорию!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } + + return json_encode($this->data); + } + + public function delete($categoryid = null) { + $this->document->setActiveSection('admin'); + $this->document->setActiveItem('tickets'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('ticketsCategory'); + + $error = $this->validate($categoryid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'admin/ticketcategory/index'); + } + + $this->ticketsCategoryModel->deleteTicketCategory($categoryid); + + $this->session->data['success'] = "Вы успешно удалили дополнение!"; + $this->response->redirect($this->config->url . 'admin/ticketcategory/index'); + return null; + } + + private function validate($categoryid) { + $result = null; + $this->load->model('ticketsCategory'); + if(!$this->ticketsCategoryModel->getTotalTicketsCategory(array('category_id' => (int)$categoryid))) { + $result = "Запрашиваемая категория не существует!"; + } + return $result; + } + + private function validatePOST() { + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + + $result = null; + + $name = @$this->request->post['name']; + $status = @$this->request->post['status']; + + if(mb_strlen($name) < 2 || mb_strlen($name) > 32) { + $result = "Название категории должно содержать от 2 до 32 символов!"; + } + elseif($status < 0 || $status > 1) { + $result = "Укажите допустимый статус!"; + } + return $result; + } +} +?> \ No newline at end of file diff --git a/panel/application/controllers/admin/ticketcategory/index.php b/panel/application/controllers/admin/ticketcategory/index.php new file mode 100644 index 0000000..bb5b79f --- /dev/null +++ b/panel/application/controllers/admin/ticketcategory/index.php @@ -0,0 +1,48 @@ +document->setActiveSection('admin/ticketcategory'); + $this->document->setActiveItem('index'); + $this->data['url'] = $this->config->url; + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->library('pagination'); + $this->load->model('ticketsCategory'); + + $options = array( + 'start' => ($page - 1) * $this->limit, + 'limit' => $this->limit + ); + + $total = $this->ticketsCategoryModel->getTotalTicketsCategory(); + $category = $this->ticketsCategoryModel->getTicketsCategory(array(),array(),array(), $options); + + $paginationUrl = '/admin/ticketcategory/index/index/{page}'; + $paginationLib = new paginationLibrary(); + $paginationLib->total = $total; + $paginationLib->page = $page; + $paginationLib->limit = $this->limit; + $paginationLib->url = $paginationUrl; + $pagination = $paginationLib->render(); + + $this->data['category'] = $category; + $this->data['pagination'] = $pagination; + + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/ticketcategory/index', $this->data); + } +} +?> \ No newline at end of file diff --git a/panel/application/controllers/admin/tickets/create.php b/panel/application/controllers/admin/tickets/create.php new file mode 100644 index 0000000..8330b40 --- /dev/null +++ b/panel/application/controllers/admin/tickets/create.php @@ -0,0 +1,93 @@ +document->setActiveSection('admin/tickets'); + $this->document->setActiveItem('create'); + $this->data['url'] = $this->config->url; + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 2) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + $this->load->model('users'); + $userid = $this->user->getId(); + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/tickets/create', $this->data); + } + + public function ajax($ticketid = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('tickets'); + $this->load->model('ticketsMessages'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $name = @$this->request->post['name']; + $text = @$this->request->post['text']; + $pid = @$this->request->post['pid']; + $userid = $this->user->getId(); + + $ticketData = array( + 'user_id' => $pid, + 'ticket_name' => $name, + 'ticket_status' => 2 + ); + $ticketid = $this->ticketsModel->createTicket($ticketData); + + $messageData = array( + 'ticket_id' => $ticketid, + 'user_id' => $userid, + 'ticket_message' => $text + ); + $this->ticketsMessagesModel->createTicketMessage($messageData); + + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно отправили сообщение пользователю!"; + $this->data['id'] = $ticketid; + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } + + return json_encode($this->data); + } + + private function validatePOST() { + $result = null; + + $name = @$this->request->post['name']; + $pid = @$this->request->post['pid']; + $text = @$this->request->post['text']; + + if(mb_strlen($name) < 6 || mb_strlen($name) > 32) { + $result = "Название тикета должно содержать от 6 до 32 символов!"; + } + elseif(mb_strlen($pid) < 1 || mb_strlen($pid) > 10) { + $result = "ID клиента должен быть от 1 до 10 символов!"; + } + elseif(mb_strlen($text) < 1 || mb_strlen($text) > 350) { + $result = "Текст тикета должен содержать от 1 до 350 символов!"; + } + return $result; + } +} \ No newline at end of file diff --git a/panel/application/controllers/admin/tickets/index.php b/panel/application/controllers/admin/tickets/index.php new file mode 100644 index 0000000..5b906fe --- /dev/null +++ b/panel/application/controllers/admin/tickets/index.php @@ -0,0 +1,74 @@ +document->setActiveSection('admin/tickets'); + $this->document->setActiveItem('index'); + $this->data['url'] = $this->config->url; + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 2) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->library('pagination'); + $this->load->model('tickets'); + $this->load->model('users'); + $userid = $this->user->getId(); + + $userid = @$this->request->get['userid']; + $status = @$this->request->get['status']; + + $getData = array(); + + if(!empty($userid)) { + $getData['tickets.user_id'] = (int)$userid; + } + if(!empty($status)) { + $getData['tickets.ticket_status'] = (int)$status; + } + + $getSort = array( + 'ticket_status' => 'DESC', + 'ticket_date_add' => 'DESC' + ); + + $getOptions = array( + 'start' => ($page - 1) * $this->limit, + 'limit' => $this->limit + ); + + $total = $this->ticketsModel->getTotalTickets($getData); + $tickets = $this->ticketsModel->getTickets($getData, array('users','tickets_category'), $getSort, $getOptions); + + $paginationUrl = '/admin/tickets/index/index/{page}'; + if(!empty($userid)) { + $paginationUrl .= '&userid=' . $userid; + } + if(!empty($status)) { + $paginationUrl .= '&status=' . $status; + } + + $paginationLib = new paginationLibrary(); + $paginationLib->total = $total; + $paginationLib->page = $page; + $paginationLib->limit = $this->limit; + $paginationLib->url = $paginationUrl; + $pagination = $paginationLib->render(); + + $this->data['tickets'] = $tickets; + $this->data['pagination'] = $pagination; + + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/tickets/index', $this->data); + } +} +?> \ No newline at end of file diff --git a/panel/application/controllers/admin/tickets/view.php b/panel/application/controllers/admin/tickets/view.php new file mode 100644 index 0000000..a3f6a22 --- /dev/null +++ b/panel/application/controllers/admin/tickets/view.php @@ -0,0 +1,254 @@ +document->setActiveSection('admin/tickets'); + $this->document->setActiveItem('view'); + $this->data['url'] = $this->config->url; + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 2) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('tickets'); + $this->load->model('users'); + + $error = $this->validate($ticketid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'admin/tickets/index'); + } + + $ticket = $this->ticketsModel->getTicketById($ticketid, array('users')); + $this->data['ticket'] = $ticket; + $this->data['user_img'] = $this->user->getUser_img(); + + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/tickets/view', $this->data); + } + + public function ajax($ticketid = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 2) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('tickets'); + $this->load->model('ticketsMessages'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST($ticketid); + if(!$errorPOST) { + $userid = $this->user->getId(); + $text = @$this->request->post['text']; + $ticket = $this->ticketsModel->getTicketById($ticketid, array('users')); + if($ticket['ticket_status'] != 0) { + $messageData = array( + 'ticket_id' => $ticketid, + 'user_id' => $userid, + 'ticket_message' => $text + ); + $this->ticketsModel->updateTicket($ticketid, array('ticket_status' => 2)); + $this->ticketsMessagesModel->createTicketMessage($messageData); + + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно отправили сообщение!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Данный запрос закрыт, оставить новое сообщение невозможно!"; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } + return json_encode($this->data); + } + + public function action($ticketid = null, $action = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 0) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + $this->load->model('tickets'); + $this->load->model('ticketsMessages'); + switch($action) { + case 'closed': { + $this->ticketsModel->updateTicket($ticketid, array('ticket_status' => 0)); + + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно закрыли запрос!"; + break; + } + default: { + $this->data['status'] = "error"; + $this->data['error'] = "Вы выбрали несуществующее действие!"; + break; + } + } + return json_encode($this->data); + } + + public function uploadFile($ticketid = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 2) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('tickets'); + $this->load->model('ticketsMessages'); + $this->load->model('users'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $uploaddir = "tmp/tickets_img/"; + $apend=date('YmdHis').rand(100,1000).'.jpg'; + $uploadfile = "$uploaddir$apend"; + + if(move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) { + if($_FILES['userfile']['type'] == 'image/gif' || $_FILES['userfile']['type'] == 'image/jpeg' || $_FILES['userfile']['type'] == 'image/png') { + if($_FILES['userfile']['size'] != 0 and $_FILES['userfile']['size'] <= 5120000) { + $size = getimagesize($uploadfile); + if ($size[0] < 2560 && $size[1] < 1440) { + if(round(($_FILES['userfile']['size'] / 1024), 2) > 1500.00) { + $message = 'Изображение: ' . $apend . '
Размер: ' . round(($_FILES['userfile']['size'] / 1024), 2) . 'КБ
Открыть'; + } else { + $message = ''; + } + $userid = $this->user->getId(); + $messageData = array( + 'ticket_id' => $ticketid, + 'user_id' => $userid, + 'ticket_message' => $message + ); + $this->ticketsModel->updateTicket($ticketid, array('ticket_status' => 1)); + $this->ticketsMessagesModel->createTicketMessage($messageData); + $this->data['status'] = 'success'; + $this->data['success'] = 'Изображение загружено!'; + } else { + $this->data['error'] = 'Загружаемое изображение превышает допустимые нормы!'; + $this->data['status'] = "error"; + unlink($uploadfile); + } + } else { + $this->data['error'] = 'Размер изображения не должено превышать 5120Кб'; + $this->data['status'] = "error"; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Можно загружать только изображения в форматах jpg, jpeg и png"; + } + } else { + $this->data['error'] = 'Изображение не загружено!'; + $this->data['status'] = "error"; + } + } + return json_encode($this->data); + } + + public function getMessagess() { + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 2) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $this->load->model('tickets'); + $this->load->model('ticketsMessages'); + + $id = $this->request->post['tid']; + + $url = $this->config->url; + $messages = $this->ticketsMessagesModel->getTicketsMessages(array('ticket_id' => $id), array('users')); + + foreach($messages as $item) { + $item['ticket_message'] = preg_replace("#(https?|ftp)://\S+[^\s.,>)\];'\"!?]#",'\\0', $item['ticket_message']); + if($item['user_access_level'] == '1') { + echo '
+
+
+ Pic +
+
+ '. $item['user_firstname'] .' '. $item['user_lastname'] .' + '. date("d.m.Y в H:i", strtotime($item['ticket_message_date_add'])) .' +
+
+
'. nl2br($item['ticket_message']) .' +
'; + } + + if($item['user_access_level'] >= '2') { + echo '
+
+
+ Pic +
+
+ '. $item['user_firstname'] .' '. $item['user_lastname'] .' + '. date("d.m.Y в H:i", strtotime($item['ticket_message_date_add'])) .' +
+
+
'. nl2br($item['ticket_message']) .'
+
'; + } + } + } + } + + + private function validate($ticketid) { + $result = null; + + if(!$this->ticketsModel->getTotalTickets(array('ticket_id' => (int)$ticketid))) { + $result = "Запрашиваемый тикет не существует!"; + } + return $result; + } + + private function validatePOST($ticketid) { + $result = null; + $userid = $this->user->getId(); + $text = @$this->request->post['text']; + $closeticket = @$this->request->post['closeticket']; + + if(!$closeticket) { + if (5 <= $this->ticketsModel->spam($userid)) { + $result = 'Пожалуйста, подождите 10 секунд.'; + } + else if(mb_strlen($text) < 1 || mb_strlen($text) > 350) { + $result = "Текст сообщения должен содержать от 1 до 350 символов."; + } + } + return $result; + } +} \ No newline at end of file diff --git a/panel/application/controllers/admin/users/edit.php b/panel/application/controllers/admin/users/edit.php new file mode 100644 index 0000000..24ce1a7 --- /dev/null +++ b/panel/application/controllers/admin/users/edit.php @@ -0,0 +1,196 @@ +data['url'] = $this->config->url; + $this->document->setActiveSection('admin/users'); + $this->document->setActiveItem('edit'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 2) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('users'); + $this->load->model('servers'); + + $error = $this->validate($userid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'admin/users/index'); + } + + $user = $this->usersModel->getUserById($userid); + + $this->data['user'] = $user; + $servers = $this->serversModel->getServers(array('user_id' => (int)$userid), array('games', 'locations'), array(), array()); + $visitors = $this->usersModel->getAuthLog($userid); + $this->data['servers'] = $servers; + $this->data['visitors'] = $visitors; + $this->data['user_img'] = $this->user->getUser_img(); + $this->data['user_access_level'] = $this->user->getAccessLevel(); + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/users/edit', $this->data); + } + + public function ajax($userid = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 3) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('users'); + + $error = $this->validate($userid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $lastname = @$this->request->post['lastname']; + $firstname = @$this->request->post['firstname']; + $email = @$this->request->post['email']; + $status = @$this->request->post['status']; + $balance = @$this->request->post['balance']; + $vk_id = @$this->request->post['vk_id']; + $test_server = @$this->request->post['test_server']; + $user_activate = @$this->request->post['user_activate']; + $accesslevel = @$this->request->post['accesslevel']; + $editpassword = @$this->request->post['editpassword']; + $password = @$this->request->post['password']; + + if (@$firstname) { + $firstname = @strtoupper($firstname[0]) . substr($firstname, 1); + } + + if (@$lastname) { + $lastname = @strtoupper($lastname[0]) . substr($lastname, 1); + } + + $userData = array( + 'user_firstname' => $firstname, + 'user_lastname' => $lastname, + 'user_email' => $email, + 'user_status' => (int)$status, + 'user_balance' => (float)$balance, + 'user_vk_id' => (float)$vk_id, + 'test_server' => (float)$test_server, + 'user_access_level' => (float)$accesslevel, + 'user_activate' => (float)$user_activate, + ); + + if($editpassword) { + $userData['user_password'] = md5($password); + } + + $this->usersModel->updateUser($userid, $userData); + + $this->data['status'] = "success"; + $this->data['success'] = "Изменения сохранены!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } + + return json_encode($this->data); + } + + public function delete($user_id = null) { + $this->document->setActiveSection('admin'); + $this->document->setActiveItem('users'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('users'); + + $this->usersModel->deleteUser($user_id); + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно удалили пользователя!"; + return json_encode($this->data); + } + + private function validate($userid) { + $result = null; + + if(!$this->usersModel->getTotalUsers(array('user_id' => (int)$userid))) { + $result = "Запрашиваемый пользователь не существует!"; + } + return $result; + } + + private function validatePOST() { + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + + $result = null; + + $lastname = @$this->request->post['lastname']; + $firstname = @$this->request->post['firstname']; + $status = @$this->request->post['status']; + $balance = @$this->request->post['balance']; + $accesslevel = @$this->request->post['accesslevel']; + $editpassword = @$this->request->post['editpassword']; + $password = @$this->request->post['password']; + $password2 = @$this->request->post['password2']; + + if (@$firstname) { + $firstname = @strtoupper($firstname[0]) . substr($firstname, 1); + } + + if (@$lastname) { + $lastname = @strtoupper($lastname[0]) . substr($lastname, 1); + } + + if(!$validateLib->check_for_number($lastname)) { + $result = "Укажите свою реальную фамилию!"; + } + elseif(!$validateLib->check_for_number($firstname)) { + $result = "Укажите свое реальное имя!"; + } + elseif(!$validateLib->userstatus($status)) { + $result = "Укажите допустимый статус!"; + } + elseif(!$validateLib->money($balance)) { + $result = "Укажите допустимый баланс!"; + } + elseif(!$validateLib->accesslevel($accesslevel)) { + $result = "Укажите допустимый уровень доступа!"; + } + elseif($editpassword) { + if(!$validateLib->password($password)) { + $result = "Пароль должен содержать от 6 до 32 латинских букв, цифр и знаков ,.!?_-!"; + } + elseif($password != $password2) { + $result = "Введенные вами пароли не совпадают!"; + } + } + return $result; + } +} +?> diff --git a/panel/application/controllers/admin/users/index.php b/panel/application/controllers/admin/users/index.php new file mode 100644 index 0000000..7337a06 --- /dev/null +++ b/panel/application/controllers/admin/users/index.php @@ -0,0 +1,232 @@ +document->setActiveSection('admin/users'); + $this->document->setActiveItem('index'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 2) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->library('pagination'); + $this->load->model('users'); + + $getOptions = array( + 'start' => ($page - 1) * $this->limit, + 'limit' => $this->limit + ); + + $total = $this->usersModel->getTotalUsers(); + $users = $this->usersModel->getUsers(array(), array(), $getOptions); + + $paginationUrl = '/admin/users/index/index/{page}'; + + $paginationLib = new paginationLibrary(); + $paginationLib->total = $total; + $paginationLib->page = $page; + $paginationLib->limit = $this->limit; + $paginationLib->url = $paginationUrl; + $pagination = $paginationLib->render(); + + $this->data['users'] = $users; + $this->data['pagination'] = $pagination; + $this->data['user_access_level'] = $this->user->getAccessLevel(); + + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/users/index', $this->data); + } + + + + public function ajax() { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 3) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('users'); + $this->load->model('news'); + $users = $this->usersModel->getUsers(array(), array(), array()); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $minsum = @$this->request->post['minsum']; + $maxsum = @$this->request->post['maxsum']; + $typesum = @$this->request->post['typesum']; + $oneuser = @$this->request->post['oneuser']; + $oneuserID = @$this->request->post['oneuserID']; + $createnews = @$this->request->post['createnews']; + + if($typesum) { + if($oneuser) { + $rsum = rand($minsum, $maxsum); + + $this->usersModel->upUserBalance($oneuserID, $rsum); + + $this->data['status'] = "info"; + $this->data['info'] = "".$rsum." - Реальные деньги выданы пользователю!"; + } else { + if($createnews) { + foreach($users as $item) { + if($item['user_status'] == 1) { + $userid = $item['user_id']; + $rsum = rand($minsum, $maxsum); + $this->usersModel->upUserBalance($oneuserID, $rsum); + } + } + if(empty($users)) { + $this->data['status'] = "error"; + $this->data['error'] = "Критическая ошибка"; + } + + $today = date("Y-m-d H:i"); + + $name = "Выдача бонусных монет всем"; + $text = "Сегодня ".$today." администрацией была проведена раздача реальных денег, их получили все активированные пользователи! "; + $category = "1"; + $img_preview = "1"; + $userid = $this->user->getId(); + + $newsData = array( + 'user_id' => $userid, + 'news_title' => $name, + 'news_text' => $text, + 'category_id' => $category, + 'place' => $place + ); + $this->newsModel->createNews($newsData); + + + $this->data['status'] = "success"; + $this->data['success'] = "Реальные деньги выданы!"; + } else { + foreach($users as $item) { + if($item['user_status'] == 1) { + $userid = $item['user_id']; + $rsum = rand($minsum, $maxsum); + $this->usersModel->upUserBalance($oneuserID, $rsum); + } + } + if(empty($users)) { + $this->data['status'] = "error"; + $this->data['error'] = "Критическая ошибка"; + } + $this->data['status'] = "success"; + $this->data['success'] = "Реальные деньги выданы!"; + } + } + } else { + if($oneuser) { + $rsum = rand($minsum, $maxsum); + $this->usersModel->upUserRMoney($oneuserID, $rsum); + + $this->data['status'] = "info"; + $this->data['info'] = "".$rsum." - Бонусные монеты выданы пользователю!"; + } else { + if($createnews) { + foreach($users as $item) { + if($item['user_status'] == 1) { + $userid = $item['user_id']; + $rsum = rand($minsum, $maxsum); + $this->usersModel->upUserRMoney($userid, $rsum); + } + } + if(empty($users)) { + $this->data['status'] = "error"; + $this->data['error'] = "Критическая ошибка"; + } + + + $today = date("Y-m-d H:i"); + + $name = "Выдача бонусных монет всем"; + $text = "Сегодня ".$today." администрацией была проведена раздача бонусных монет, их получили все активированные пользователи! "; + $category = "1"; + $place = "1"; + $userid = $this->user->getId(); + + $newsData = array( + 'user_id' => $userid, + 'news_title' => $name, + 'news_text' => $text, + 'category_id' => $category, + 'place' => $place + ); + $this->newsModel->createNews($newsData); + + $this->data['status'] = "success"; + $this->data['success'] = "Бонусные монеты выданы!"; + } else { + foreach($users as $item) { + if($item['user_status'] == 1) { + $userid = $item['user_id']; + $rsum = rand($minsum, $maxsum); + $this->usersModel->upUserRMoney($userid, $rsum); + } + } + if(empty($users)) { + $this->data['status'] = "error"; + $this->data['error'] = "Критическая ошибка"; + } + + $this->data['status'] = "success"; + $this->data['success'] = "Бонусные монеты выданы!"; + } + } + } + // Сюда можно логирование + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } + + return json_encode($this->data); + } + + private function validatePOST() { + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + + $result = null; + + $minsum = @$this->request->post['minsum']; + $maxsum = @$this->request->post['maxsum']; + $oneuser = @$this->request->post['oneuser']; + $oneuserID = @$this->request->post['oneuserID']; + + if(!$validateLib->money($maxsum)) { + $result = "Укажите сумму в допустимом формате!"; + } + elseif(1 > $minsum || $minsum > 5000) { + $result = "Укажите сумму от 1 до 5000"; + } + + if($oneuser) { + if(!$this->usersModel->getTotalUsers(array('user_id' => (int)$oneuserID))) { + $result = "Запрашиваемый пользователь не существует!"; + } + } + + return $result; + } +} +?> diff --git a/panel/application/controllers/admin/waste/index.php b/panel/application/controllers/admin/waste/index.php new file mode 100644 index 0000000..fdc2502 --- /dev/null +++ b/panel/application/controllers/admin/waste/index.php @@ -0,0 +1,61 @@ +document->setActiveSection('admin/waste'); + $this->document->setActiveItem('index'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 2) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->library('pagination'); + $this->load->model('waste'); + + $userid = @$this->request->get['userid']; + + $getData = array(); + + if(!empty($userid)) { + $getData['waste.user_id'] = (int)$userid; + } + + $getOptions = array( + 'start' => ($page - 1) * $this->limit, + 'limit' => $this->limit + ); + + $total = $this->wasteModel->getTotalWaste($getData); + $waste = $this->wasteModel->getWaste($getData, array('users'), array(), $getOptions); + $wastes = $this->wasteModel->getWaste(array(), array('users'), array(), array()); + + $paginationUrl = '/admin/waste/index/index/{page}'; + if(!empty($userid)) { + $paginationUrl .= '&userid=' . $userid; + } + + $paginationLib = new paginationLibrary(); + $paginationLib->total = $total; + $paginationLib->page = $page; + $paginationLib->limit = $this->limit; + $paginationLib->url = $paginationUrl; + $pagination = $paginationLib->render(); + + $this->data['waste'] = $waste; + $this->data['wastes'] = $wastes; + $this->data['pagination'] = $pagination; + + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/waste/index', $this->data); + } +} +?> \ No newline at end of file diff --git a/panel/application/controllers/admin/webhost/control.php b/panel/application/controllers/admin/webhost/control.php new file mode 100644 index 0000000..78f284f --- /dev/null +++ b/panel/application/controllers/admin/webhost/control.php @@ -0,0 +1,185 @@ +document->setActiveSection('admin/webhost'); + $this->document->setActiveItem('control'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 2) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('webhost'); + + $error = $this->validate($webid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'admin/webhost/index'); + } + + $webhost = $this->webhostModel->getWebhostById($webid, array('users','web_tarifs','web_locations')); + $this->data['webhost'] = $webhost; + + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/webhost/control', $this->data); + } + + public function ajax($webid = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 2) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + $this->load->model('webhost'); + + $error = $this->validate($webid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + $webhost = $this->webhostModel->getWebhostById($webid, array('users', 'web_tarifs')); + if($webhost['web_status'] == 0) { + $this->data['status'] = "error"; + $this->data['error'] = "Веб-хостинг заблокирован!"; + return json_encode($this->data); + } + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $editpassword = @$this->request->post['editpassword']; + $password = @$this->request->post['password']; + if($editpassword) { + $result = $this->webhostModel->updatepassUser($webid, $password); + if($result["status"] == "success") { + $this->webhostModel->updateWebhost($webid, array('web_password' => $password)); + $this->data['status'] = "success"; + $this->data['success'] = "Пароль доступа успешно изменен!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = $result["description"]; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Ошибка!"; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } + + return json_encode($this->data); + } + + public function action($webid = null, $action = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 2) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + $this->load->model('webhost'); + + $error = $this->validate($webid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + $webhost = $this->webhostModel->getWebhostById($webid, array('users', 'web_tarifs')); + + switch($action) { + case 'block': { + $result = $this->webhostModel->blockWebhost($webid); + if($result["status"] == "success") { + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно заблокировали веб-хостинг!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = $result["description"]; + } + break; + } + case 'unblock': { + $result = $this->webhostModel->unblockWebhost($webid); + if($result["status"] == "success") { + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно разблокировали веб-хостинг!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = $result["description"]; + } + break; + } + case 'detele_web': { + $result = $this->webhostModel->deleteWebhost($webid); + if($result["status"] == "success") { + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно удалили веб-хостинг!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = $result["description"]; + } + break; + } + default: { + $this->data['status'] = "error"; + $this->data['error'] = "Вы выбрали несуществующее действие!"; + break; + } + } + + return json_encode($this->data); + } + + private function validate($webid) { + $result = null; + + if(!$this->webhostModel->getTotalWebhosts(array('web_id' => (int)$webid))) { + $result = "Запрашиваемый веб-хостинг не существует!"; + } + return $result; + } + + private function validatePOST() { + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + + $result = null; + + $editpassword = @$this->request->post['editpassword']; + $password = @$this->request->post['password']; + $password2 = @$this->request->post['password2']; + + if($editpassword) { + if(!$validateLib->password_web($password)) { + $result = "Пароль должен содержать от 8 до 32 латинских букв, цифр и знаков ,.!?_-!"; + } + elseif($password != $password2) { + $result = "Введенные вами пароли не совпадают!"; + } + } + return $result; + } +} +?> diff --git a/panel/application/controllers/admin/webhost/index.php b/panel/application/controllers/admin/webhost/index.php new file mode 100644 index 0000000..fafd509 --- /dev/null +++ b/panel/application/controllers/admin/webhost/index.php @@ -0,0 +1,74 @@ +document->setActiveSection('admin/webhost'); + $this->document->setActiveItem('index'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 2) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->library('pagination'); + $this->load->model('webhost'); + + $userid = $this->user->getId(); + $userid = @$this->request->get['userid']; + $tarifid = @$this->request->get['tarifid']; + $locationid = @$this->request->get['locationid']; + + $getData = array(); + + if(!empty($userid)) { + $getData['webhost.user_id'] = (int)$userid; + } + if(!empty($tarifid)) { + $getData['webhost.tarif_id'] = (int)$tarifid; + } + if(!empty($locationid)) { + $getData['webhost.location_id'] = (int)$locationid; + } + + $getOptions = array( + 'start' => ($page - 1) * $this->limit, + 'limit' => $this->limit + ); + + $total = $this->webhostModel->getTotalWebhosts($getData); + $webhosts = $this->webhostModel->getWebhosts($getData, array('web_tarifs', 'web_locations'), array(), $getOptions); + + $paginationUrl = '/admin/webhost/index/index/{page}'; + if(!empty($userid)) { + $paginationUrl .= '&userid=' . $userid; + } + if(!empty($tarifid)) { + $paginationUrl .= '&tarifid=' . $tarifid; + } + if(!empty($locationid)) { + $paginationUrl .= '&locationid=' . $locationid; + } + + $paginationLib = new paginationLibrary(); + $paginationLib->total = $total; + $paginationLib->page = $page; + $paginationLib->limit = $this->limit; + $paginationLib->url = $paginationUrl; + $pagination = $paginationLib->render(); + + $this->data['webhosts'] = $webhosts; + $this->data['pagination'] = $pagination; + + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/webhost/index', $this->data); + } +} +?> diff --git a/panel/application/controllers/admin/weblocations/create.php b/panel/application/controllers/admin/weblocations/create.php new file mode 100644 index 0000000..2488c07 --- /dev/null +++ b/panel/application/controllers/admin/weblocations/create.php @@ -0,0 +1,116 @@ +document->setActiveSection('admin/weblocations'); + $this->document->setActiveItem('create'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/weblocations/create', $this->data); + } + + public function ajax() { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 3) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('webLocations'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $name = @$this->request->post['name']; + $ip = @$this->request->post['ip']; + $url = @$this->request->post['url']; + $ns_servers = @$this->request->post['ns_servers']; + $user = @$this->request->post['user']; + $password = @$this->request->post['password']; + $password2 = @$this->request->post['password2']; + $status = @$this->request->post['status']; + + $locationData = array( + 'location_name' => $name, + 'location_ip' => $ip, + 'location_url' => $url, + 'location_user' => $user, + 'location_password' => $password, + 'ns_servers' => $ns_servers, + 'location_status' => (int)$status + ); + + $this->webLocationsModel->createLocation($locationData); + + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно создали локацию!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } + + return json_encode($this->data); + } + + private function validatePOST() { + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + + $result = null; + + $name = @$this->request->post['name']; + $ip = @$this->request->post['ip']; + $url = @$this->request->post['url']; + $user = @$this->request->post['user']; + $ns_servers = @$this->request->post['ns_servers']; + $password = @$this->request->post['password']; + $password2 = @$this->request->post['password2']; + $status = @$this->request->post['status']; + + if(mb_strlen($name) < 2 || mb_strlen($name) > 32) { + $result = "Название локации должно содержать от 2 до 32 символов!"; + } + elseif(mb_strlen($ns_servers) < 2 || mb_strlen($ns_servers) > 78) { + $result = "NS Сервера локации должны содержать от 2 до 78 символов!"; + } + elseif(!$validateLib->ip($ip)) { + $result = "Укажите допустимый IP!"; + } + elseif(mb_strlen($url) < 2 || mb_strlen($url) > 32) { + $result = "Домен должен содержать от 2 до 32 символов!"; + } + elseif(mb_strlen($user) < 2 || mb_strlen($user) > 32) { + $result = "Имя пользователя должно содержать от 2 до 32 символов!"; + } + elseif(!$validateLib->password($password)) { + $result = "Пароль должен содержать от 6 до 32 латинских букв, цифр и знаков ,.!?_-!"; + } + elseif($password != $password2) { + $result = "Введенные вами пароли не совпадают!"; + } + elseif($status < 0 || $status > 1) { + $result = "Укажите допустимый статус!"; + } + return $result; + } +} +?> diff --git a/panel/application/controllers/admin/weblocations/edit.php b/panel/application/controllers/admin/weblocations/edit.php new file mode 100644 index 0000000..9d24bdd --- /dev/null +++ b/panel/application/controllers/admin/weblocations/edit.php @@ -0,0 +1,180 @@ +document->setActiveSection('admin/weblocations'); + $this->document->setActiveItem('edit'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('webLocations'); + + $error = $this->validate($locationid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'admin/weblocations/index'); + } + + $location = $this->webLocationsModel->getLocationById($locationid); + + $this->data['location'] = $location; + + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/weblocations/edit', $this->data); + } + + public function ajax($locationid = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 3) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('webLocations'); + + $error = $this->validate($locationid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $name = @$this->request->post['name']; + $ip = @$this->request->post['ip']; + $url = @$this->request->post['url']; + $user = @$this->request->post['user']; + $ns_servers = @$this->request->post['ns_servers']; + $password = @$this->request->post['password']; + $password2 = @$this->request->post['password2']; + $editpassword = @$this->request->post['editpassword']; + $status = @$this->request->post['status']; + $location_tarifs = @$this->request->post['location_tarifs']; + + $locationData = array( + 'location_name' => $name, + 'location_ip' => $ip, + 'location_url' => $url, + 'ns_servers' => $ns_servers, + 'location_user' => $user, + 'location_status' => (int)$status, + 'location_tarifs' => $location_tarifs + ); + + if($editpassword) { + $locationData['location_password'] = $password; + } + + $this->webLocationsModel->updateLocation($locationid, $locationData); + + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно отредактировали локацию!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } + + return json_encode($this->data); + } + + public function delete($locationid = null) { + $this->document->setActiveSection('admin'); + $this->document->setActiveItem('weblocations'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('webLocations'); + + $error = $this->validate($locationid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'admin/weblocations/index'); + } + + $this->webLocationsModel->deleteLocation($locationid); + + $this->session->data['success'] = "Вы успешно удалили локацию!"; + $this->response->redirect($this->config->url . 'admin/weblocations/index'); + return null; + } + + private function validate($locationid) { + $result = null; + + if(!$this->webLocationsModel->getTotalLocations(array('location_id' => (int)$locationid))) { + $result = "Запрашиваемая локация не существует!"; + } + return $result; + } + + private function validatePOST() { + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + + $result = null; + + $name = @$this->request->post['name']; + $ip = @$this->request->post['ip']; + $url = @$this->request->post['url']; + $user = @$this->request->post['user']; + $ns_servers = @$this->request->post['ns_servers']; + $password = @$this->request->post['password']; + $password2 = @$this->request->post['password2']; + $status = @$this->request->post['status']; + + if(mb_strlen($name) < 2 || mb_strlen($name) > 32) { + $result = "Название локации должно содержать от 2 до 32 символов!"; + } + elseif(mb_strlen($ns_servers) < 2 || mb_strlen($ns_servers) > 78) { + $result = "NS Сервера локации должны содержать от 2 до 78 символов!"; + } + elseif(!$validateLib->ip($ip)) { + $result = "Укажите допустимый IP!"; + } + elseif(mb_strlen($url) < 2 || mb_strlen($url) > 32) { + $result = "Домен должен содержать от 2 до 32 символов!"; + } + elseif(mb_strlen($user) < 2 || mb_strlen($user) > 32) { + $result = "Имя пользователя должно содержать от 2 до 32 символов!"; + } + elseif($editpassword) { + if(!$validateLib->password($password)) { + $result = "Пароль должен содержать от 6 до 32 латинских букв, цифр и знаков ,.!?_-!"; + } + elseif($password != $password2) { + $result = "Введенные вами пароли не совпадают!"; + } + } + elseif($status < 0 || $status > 1) { + $result = "Укажите допустимый статус!"; + } + return $result; + } +} +?> diff --git a/panel/application/controllers/admin/weblocations/index.php b/panel/application/controllers/admin/weblocations/index.php new file mode 100644 index 0000000..5dc9cdf --- /dev/null +++ b/panel/application/controllers/admin/weblocations/index.php @@ -0,0 +1,47 @@ +document->setActiveSection('admin/weblocations'); + $this->document->setActiveItem('index'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->library('pagination'); + $this->load->model('webLocations'); + + $options = array( + 'start' => ($page - 1) * $this->limit, + 'limit' => $this->limit + ); + + $total = $this->webLocationsModel->getTotalLocations(); + $locations = $this->webLocationsModel->getLocations(array(), array(), $options); + + $paginationUrl = '/admin/weblocations/index/index/{page}'; + $paginationLib = new paginationLibrary(); + $paginationLib->total = $total; + $paginationLib->page = $page; + $paginationLib->limit = $this->limit; + $paginationLib->url = $paginationUrl; + $pagination = $paginationLib->render(); + + $this->data['locations'] = $locations; + $this->data['pagination'] = $pagination; + + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/weblocations/index', $this->data); + } +} +?> \ No newline at end of file diff --git a/panel/application/controllers/admin/webtarifs/create.php b/panel/application/controllers/admin/webtarifs/create.php new file mode 100644 index 0000000..64a1f15 --- /dev/null +++ b/panel/application/controllers/admin/webtarifs/create.php @@ -0,0 +1,93 @@ +document->setActiveSection('admin/webtarifs'); + $this->document->setActiveItem('create'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/webtarifs/create', $this->data); + } + + public function ajax() { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 3) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('webhostTarifs'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $name = @$this->request->post['name']; + $package = @$this->request->post['package']; + $price = @$this->request->post['price']; + $status = @$this->request->post['status']; + + $tarifData = array( + 'tarif_name' => $name, + 'package' => $package, + 'tarif_price' => (float)$price, + 'tarif_status' => (int)$status + ); + + $this->webhostTarifsModel->createTarif($tarifData); + + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно создали тариф!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } + + return json_encode($this->data); + } + + private function validatePOST() { + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + + $result = null; + + $name = @$this->request->post['name']; + $package = @$this->request->post['package']; + $price = @$this->request->post['price']; + $status = @$this->request->post['status']; + + if(mb_strlen($name) < 2 || mb_strlen($name) > 32) { + $result = "Название тарифа должно содержать от 2 до 32 символов!"; + } + elseif(mb_strlen($package) < 1 || mb_strlen($package) > 32) { + $result = "Название пакета должно содержать от 2 до 32 символов!"; + } + elseif(!$validateLib->money($price)) { + $result = "Укажите допустимую стоимость!"; + } + elseif($status < 0 || $status > 1) { + $result = "Укажите допустимый статус!"; + } + return $result; + } +} +?> diff --git a/panel/application/controllers/admin/webtarifs/edit.php b/panel/application/controllers/admin/webtarifs/edit.php new file mode 100644 index 0000000..f144339 --- /dev/null +++ b/panel/application/controllers/admin/webtarifs/edit.php @@ -0,0 +1,149 @@ +document->setActiveSection('admin/webtarifs'); + $this->document->setActiveItem('edit'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('webhostTarifs'); + + $error = $this->validate($tarifid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'admin/webtarifs/index'); + } + + $tarif = $this->webhostTarifsModel->getTarifById($tarifid); + + $this->data['tarif'] = $tarif; + + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/webtarifs/edit', $this->data); + } + + public function ajax($tarifid = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 3) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('webhostTarifs'); + + $error = $this->validate($tarifid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $name = @$this->request->post['name']; + $package = @$this->request->post['package']; + $price = @$this->request->post['price']; + $status = @$this->request->post['status']; + + $tarifData = array( + 'tarif_name' => $name, + 'package' => $package, + 'tarif_price' => (float)$price, + 'tarif_status' => (int)$status + ); + + $this->webhostTarifsModel->updateTarif($tarifid, $tarifData); + + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно отредактировали тариф!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } + + return json_encode($this->data); + } + + public function delete($tarifid = null) { + $this->document->setActiveSection('admin'); + $this->document->setActiveItem('tarifid'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('webhostTarifs'); + + $error = $this->validate($tarifid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'admin/tarifid/index'); + } + + $this->webhostTarifsModel->deleteTarif($tarifid); + + $this->session->data['success'] = "Вы успешно удалили тариф!"; + $this->response->redirect($this->config->url . 'admin/tarifid/index'); + return null; + } + + private function validate($tarifid) { + $result = null; + + if(!$this->webhostTarifsModel->getTotalTarifs(array('tarif_id' => (int)$tarifid))) { + $result = "Запрашиваеммый тариф не существует!"; + } + return $result; + } + + private function validatePOST() { + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + + $result = null; + + $name = @$this->request->post['name']; + $package = @$this->request->post['package']; + $price = @$this->request->post['price']; + $status = @$this->request->post['status']; + + if(mb_strlen($name) < 2 || mb_strlen($name) > 32) { + $result = "Название тарифа должно содержать от 2 до 32 символов!"; + } + elseif(mb_strlen($package) < 1 || mb_strlen($package) > 32) { + $result = "Название пакета должно содержать от 2 до 32 символов!"; + } + elseif(!$validateLib->money($price)) { + $result = "Укажите допустимую стоимость!"; + } + elseif($status < 0 || $status > 1) { + $result = "Укажите допустимый статус!"; + } + return $result; + } +} +?> diff --git a/panel/application/controllers/admin/webtarifs/index.php b/panel/application/controllers/admin/webtarifs/index.php new file mode 100644 index 0000000..544c815 --- /dev/null +++ b/panel/application/controllers/admin/webtarifs/index.php @@ -0,0 +1,47 @@ +document->setActiveSection('admin/webtarifs'); + $this->document->setActiveItem('index'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 3) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->library('pagination'); + $this->load->model('webhostTarifs'); + + $options = array( + 'start' => ($page - 1) * $this->limit, + 'limit' => $this->limit + ); + + $total = $this->webhostTarifsModel->getTotalTarifs(); + $tarifs = $this->webhostTarifsModel->getTarifs(array(), array(), $options); + + $paginationUrl = '/admin/webtarifs/index/index/{page}'; + $paginationLib = new paginationLibrary(); + $paginationLib->total = $total; + $paginationLib->page = $page; + $paginationLib->limit = $this->limit; + $paginationLib->url = $paginationUrl; + $pagination = $paginationLib->render(); + + $this->data['tarifs'] = $tarifs; + $this->data['pagination'] = $pagination; + + $this->getChild(array('common/admheader', 'common/footer')); + return $this->load->view('admin/webtarifs/index', $this->data); + } +} +?> \ No newline at end of file diff --git a/panel/application/controllers/common/admheader.php b/panel/application/controllers/common/admheader.php new file mode 100644 index 0000000..daa4f46 --- /dev/null +++ b/panel/application/controllers/common/admheader.php @@ -0,0 +1,89 @@ +data['activesection'] = $this->document->getActiveSection(); + $this->data['activeitem'] = $this->document->getActiveItem(); + $this->data['title'] = $this->config->title; + $this->data['description'] = $this->config->description; + $this->data['keywords'] = $this->config->keywords; + $this->data['logo'] = $this->config->logo; + $this->data['url'] = $this->config->url; + $this->data['webhost'] = $this->config->webhost; + $this->data['public'] = $this->config->public; + $this->data['oplata_status'] = $this->config->oplata_status; + $this->data['oplatahostinpl'] = $this->config->oplatahostinpl; + $this->data['status_hostinpl'] = $this->config->status_hostinpl; + + if($this->user->isLogged()) { + $this->data['logged'] = true; + $this->data['user_email'] = $this->user->getEmail(); + $this->data['user_firstname'] = $this->user->getFirstname(); + $this->data['user_lastname'] = $this->user->getLastname(); + $this->data['user_balance'] = $this->user->getBalance(); + $this->data['user_access_level'] = $this->user->getAccessLevel(); + $this->data['user_img'] = $this->user->getUser_img(); + } else { + $this->data['logged'] = false; + $this->data['user_access_level'] = 0; + } + + $logged = $this->data['logged']; + $this->data['logged'] = $logged; + if(isset($this->session->data['error'])) { + $this->data['error'] = $this->session->data['error']; + unset($this->session->data['error']); + } + + if(isset($this->session->data['warning'])) { + $this->data['warning'] = $this->session->data['warning']; + unset($this->session->data['warning']); + } + + if(isset($this->session->data['success'])) { + $this->data['success'] = $this->session->data['success']; + unset($this->session->data['success']); + } + + + $this->load->model('tickets'); + $this->load->model('ticketsMessages'); + $this->load->model('users'); + $userid = $this->user->getId(); + + $sort = array( + 'ticket_status' => 'DESC', + 'ticket_date_add' => 'DESC' + ); + + $tickets = $this->ticketsModel->getTickets(array('user_id' => (int)$userid), array(), $sort, array()); + + $this->data['tickets'] = $tickets; + $visitors = $this->usersModel->getAuthLog($userid); + $this->data['visitors'] = $visitors; + + $offline = $this->config->offline; + + if($offline == 1){ + if($this->user->getAccessLevel() == 1) { + $result = $this->config->offline_res; + header ("Location: /offline?result=".$result.""); + return; + } + if($this->user->getAccessLevel() == 2) { + $result = $this->config->offline_res; + header ("Location: /offline?result=".$result.""); + return; + } + if($this->user->getAccessLevel() == 3) { + return $this->load->view('common/admheader', $this->data); + } + } else{ + return $this->load->view('common/admheader', $this->data); + } + } +} +?> diff --git a/panel/application/controllers/common/footer.php b/panel/application/controllers/common/footer.php new file mode 100644 index 0000000..15117c3 --- /dev/null +++ b/panel/application/controllers/common/footer.php @@ -0,0 +1,76 @@ +data['title'] = $this->config->title; + $this->data['description'] = $this->config->description; + $this->data['public'] = $this->config->public; + + return $this->load->view('common/footer', $this->data); + } + + public function getstatus($action) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $userid = $this->user->getId(); + + $this->load->model('users'); + + switch($action) { + case 'online': { + $LastTime = time() - 105; + + $online = 0; + foreach($this->usersModel->getUsers() as $line) { + if ($line['user_online_date'] > $LastTime) { + $online++; + } + } + + $this->usersModel->updateUser($userid, array('user_online_date'=> time())); + $this->data['status'] = "online"; + $this->data['online'] = "USERID ".$userid." ".$this->user->getFirstname()." UPD-DATE ".date("Y-m-d H:i:s")." | ".$LastTime." LVL ".$this->user->getAccessLevel()." ST.OK"; + $this->data['online_usr'] = $online; + break; + } + case 'online_sup': { + $LastTime = time() - 105; + + $online_sup = 0; + foreach($this->usersModel->getUsers() as $line) { + if($line['user_access_level'] > 1) { + if ($line['user_online_date'] > $LastTime) { + $online_sup++; + } + } + } + + if($online_sup > 0) { + $this->data['sup_status'] = "Online"; + } else { + $this->data['sup_status'] = "Offline"; + } + break; + } + default: { + $this->data['status'] = "error"; + $this->data['error'] = "Вы выбрали несуществующее действие!"; + break; + } + } + return json_encode($this->data); + } +} +?> diff --git a/panel/application/controllers/common/header.php b/panel/application/controllers/common/header.php new file mode 100644 index 0000000..9a7d41b --- /dev/null +++ b/panel/application/controllers/common/header.php @@ -0,0 +1,90 @@ +data['title'] = $this->config->title; + $this->data['description'] = $this->config->description; + $this->data['keywords'] = $this->config->keywords; + $this->data['activesection'] = $this->document->getActiveSection(); + $this->data['activeitem'] = $this->document->getActiveItem(); + $this->data['logo'] = $this->config->logo; + $this->data['url'] = $this->config->url; + $this->data['public'] = $this->config->public; + $this->data['webhost'] = $this->config->webhost; + $this->data['oplata_status'] = $this->config->oplata_status; + $this->data['oplatahostinpl'] = $this->config->oplatahostinpl; + $this->data['status_hostinpl'] = $this->config->status_hostinpl; + + if($this->user->isLogged()) { + $this->data['logged'] = true; + $this->data['user_email'] = $this->user->getEmail(); + $this->data['user_firstname'] = $this->user->getFirstname(); + $this->data['user_lastname'] = $this->user->getLastname(); + $this->data['user_balance'] = $this->user->getBalance(); + $this->data['user_access_level'] = $this->user->getAccessLevel(); + $this->data['user_img'] = $this->user->getUser_img(); + } else { + $this->data['logged'] = false; + $this->data['user_access_level'] = 0; + } + + $logged = $this->data['logged']; + $this->data['logged'] = $logged; + if(isset($this->session->data['error'])) { + $this->data['error'] = $this->session->data['error']; + unset($this->session->data['error']); + } + + if(isset($this->session->data['warning'])) { + $this->data['warning'] = $this->session->data['warning']; + unset($this->session->data['warning']); + } + + if(isset($this->session->data['success'])) { + $this->data['success'] = $this->session->data['success']; + unset($this->session->data['success']); + } + + + $this->load->model('tickets'); + $this->load->model('ticketsMessages'); + $this->load->model('users'); + $userid = $this->user->getId(); + + $sort = array( + 'ticket_status' => 'DESC', + 'ticket_date_add' => 'DESC' + ); + + $tickets = $this->ticketsModel->getTickets(array('user_id' => (int)$userid), array(), $sort, array()); + + $this->data['tickets'] = $tickets; + $visitors = $this->usersModel->getAuthLog($userid); + $this->data['visitors'] = $visitors; + + $offline = $this->config->offline; + + if($offline == 1){ + if($this->user->getAccessLevel() == 1) { + $result = $this->config->offline_res; + header ("Location: /offline?result=".$result.""); + return; + } + if($this->user->getAccessLevel() == 2) { + $result = $this->config->offline_res; + header ("Location: /offline?result=".$result.""); + return; + } + if($this->user->getAccessLevel() == 3) { + return $this->load->view('common/header', $this->data); + } + } else{ + return $this->load->view('common/header', $this->data); + } + + } +} +?> diff --git a/panel/application/controllers/common/loginfooter.php b/panel/application/controllers/common/loginfooter.php new file mode 100644 index 0000000..51ee9dd --- /dev/null +++ b/panel/application/controllers/common/loginfooter.php @@ -0,0 +1,11 @@ +load->view('common/loginfooter', $this->data); + } +} +?> diff --git a/panel/application/controllers/common/loginheader.php b/panel/application/controllers/common/loginheader.php new file mode 100644 index 0000000..58df094 --- /dev/null +++ b/panel/application/controllers/common/loginheader.php @@ -0,0 +1,300 @@ +data['title'] = $this->config->title; + $this->data['description'] = $this->config->description; + $this->data['keywords'] = $this->config->keywords; + $this->data['logo'] = $this->config->logo; + $this->data['public'] = $this->config->public; + $this->data['count'] = $this->config->count; + $this->data['vk_id'] = $this->config->vk_id; + $this->data['vk_stat'] = $this->config->vk_stat; + $this->data['recaptcha'] = $this->config->recaptcha; + $this->data['captcha_enable'] = $this->config->captcha_enable; + + if(isset($this->session->data['error'])) { + $this->data['error'] = $this->session->data['error']; + unset($this->session->data['error']); + } + + if(isset($this->session->data['warning'])) { + $this->data['warning'] = $this->session->data['warning']; + unset($this->session->data['warning']); + } + + if(isset($this->session->data['success'])) { + $this->data['success'] = $this->session->data['success']; + unset($this->session->data['success']); + } + $this->load->model('users'); + $userid = $this->user->getId(); + + $user = $this->usersModel->getUserById(isset($_GET['ref']) ? (int)$_GET['ref'] : 0, array(), array(), array()); + $this->data['user'] = $user; + + return $this->load->view('common/loginheader', $this->data); + } + + public function ajax() { + if($this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы уже авторизированы!"; + return json_encode($this->data); + } + $this->load->library('mail'); + $this->load->model('users'); + $this->load->model('waste'); + + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $lastname = @$this->request->get['lastname']; + $firstname = @$this->request->get['firstname']; + $email = @$this->request->get['email']; + $password = @$this->request->get['password']; + $ref = @$this->request->get['ref']; + + if (@$firstname) { + $firstname = @strtoupper($firstname[0]) . substr($firstname, 1); + } + + if (@$lastname) { + $lastname = @strtoupper($lastname[0]) . substr($lastname, 1); + } + + if ($this->config->register) { + $random = md5(uniqid(rand(), true)); + $user_activate = 0; + } + else { + $random = 0; + $user_activate = 1; + } + + $random = md5(uniqid(rand(),true)); + + $userData = array( + 'user_email' => $email, + 'user_password' => md5($password), + 'user_firstname' => $firstname, + 'user_lastname' => $lastname, + 'user_status' => 1, + 'user_balance' => 0, + 'user_access_level' => 1, + 'rmoney' => 0, + 'user_activate' => $this->config->register, + 'key_activate' => $random + ); + $userid = $this->usersModel->createUser($userData); + if($userid != $ref) { + if($ref != 0) { + $this->usersModel->upUserBalance($ref, 0.25); + $this->usersModel->upUserRMoney($ref, 0.25); + $userData = array( + 'ref' => $ref + ); + $this->usersModel->updateUser($userid, $userData); + + $wasteData = array( + 'user_id' => $ref, + 'waste_ammount' => 0.25, + 'waste_status' => 0, + 'waste_usluga' => "Бонус за приглашенного реферала ID-$userid" + ); + $this->wasteModel->createWaste($wasteData); + } + } + $mailLib = new mailLibrary(); + + $mailLib->setFrom($this->config->mail_from); + $mailLib->setSender($this->config->mail_sender); + $mailLib->setTo($email); + $mailLib->setSubject('Регистрация аккаунта'); + + $mailData = array(); + + $mailData['firstname'] = $firstname; + $mailData['lastname'] = $lastname; + $mailData['email'] = $email; + $mailData['password'] = $password; + $mailData['key'] = $random; + $mailData['url'] = $this->config->url; + $mailData['title'] = $this->config->title; + + if ($this->config->register) { + $text = $this->load->view('mail/account/register', $mailData); + } + else { + $text = $this->load->view('mail/account/register_activate', $mailData); + } + + $mailLib->setText($text); + $mailLib->send(); + + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно зарегистрировались!"; + $this->data['user_activate'] = $user_activate; + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + + return json_encode($this->data); + } + + private function validatePOST() { + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + + $result = null; + + $lastname = @$this->request->get['lastname']; + $firstname = @$this->request->get['firstname']; + $email = @$this->request->get['email']; + $password = @$this->request->get['password']; + $password2 = @$this->request->get['password2']; + $recaptcha = @$this->request->get['g-recaptcha-response']; + + if (@$firstname) { + $firstname = @strtoupper($firstname[0]) . substr($firstname, 1); + } + + if (@$lastname) { + $lastname = @strtoupper($lastname[0]) . substr($lastname, 1); + } + + if(!$validateLib->check_for_number($lastname)) { + $result = "Укажите свою реальную фамилию!"; + } + elseif(!$validateLib->check_for_number($firstname)) { + $result = "Укажите свое реальное имя!"; + } + elseif(!$validateLib->email($email)) { + $result = "Укажите свой реальный E-Mail!"; + } + elseif(!$validateLib->password($password)) { + $result = "Пароль должен содержать от 6 до 32 латинских букв, цифр и знаков ,.!?_-!"; + } + elseif($password != $password2) { + $result = "Введенные вами пароли не совпадают!"; + } + elseif($captcha != $captchahash) { + $result = "Укажите правильный код с картинки! Попробуйте нажать на картинку, чтобы обновить ее."; + } + elseif($this->usersModel->getTotalUsers(array('user_email' => $email))) { + $result = "Указанный E-Mail уже зарегистрирован!"; + } + + if($this->config->captcha_enable != '1') return $result; + if(!$recaptcha) return 'Подтвердите, что вы не робот!'; + $url = 'https://www.google.com/recaptcha/api/siteverify'; + $data = array('secret' => $this->config->secret_recaptcha, 'response' => $recaptcha); + $options = array( + 'http' => array( + 'header' => "Content-type: application/x-www-form-urlencoded\r\n", + 'method' => 'POST', + 'remoteip' => 'remoteip', + 'content' => http_build_query($data), + ) + ); + + $context = stream_context_create($options); + $recaptcha_get = json_decode(file_get_contents($url, false, $context))->{'success'}; + if($recaptcha_get != '1') return 'Проверьте правильность капчи!'; + return $result; + } + + public function ajax_infobox() { + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOSTInfo(); + if(!$errorPOST) { + if(@$this->request->post['msg'] == ""){ + $this->data['status'] = "error"; + $this->data['error'] = "Введите команду!"; + }elseif(@$this->request->post['msg'] != ""){ + $this->load->model('mail'); + $firstname = @$this->request->post['firstname']; + $lastname = @$this->request->post['lastname']; + $email = @$this->request->post['email']; + $subject = @$this->request->post['subject']; + $msg = @$this->request->post['msg']; + $msgData = array( + 'user_email' => $email, + 'user_firstname' => $firstname, + 'user_lastname' => $lastname, + 'category' => $subject, + 'text' => $msg, + 'status' => 1 + ); + + $msg_id = $this->mailModel->createInbox($msgData); + + $this->data['status'] = "success"; + $this->data['success'] = "Ваше письмо отправлено! Номер IN".$msg_id.""; + } + + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } + + return json_encode($this->data); + } + + private function validatePOSTInfo() { + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + + $result = null; + + $firstname = @$this->request->post['firstname']; + $lastname = @$this->request->post['lastname']; + $email = @strtolower($this->request->post['email']); + $subject = @$this->request->post['subject']; + $msg = @$this->request->post['msg']; + $recaptcha = @$this->request->post['g-recaptcha-response']; + + if (@$firstname) { + $firstname = @strtoupper($firstname[0]) . substr($firstname, 1); + } + + if (@$lastname) { + $lastname = @strtoupper($lastname[0]) . substr($lastname, 1); + } + + if(!$validateLib->check_for_number($lastname)) { + $result = "Укажите свою реальную фамилию!"; + } + elseif(!$validateLib->check_for_number($firstname)) { + $result = "Укажите свое реальное имя!"; + } + elseif(!$validateLib->email($email)) { + $result = "Укажите свой реальный E-Mail!"; + } + + if($this->config->captcha_enable != '1') return $result; + if(!$recaptcha) return 'Подтвердите, что вы не робот!'; + $url = 'https://www.google.com/recaptcha/api/siteverify'; + $data = array('secret' => $this->config->secret_recaptcha, 'response' => $recaptcha); + $options = array( + 'http' => array( + 'header' => "Content-type: application/x-www-form-urlencoded\r\n", + 'method' => 'POST', + 'remoteip' => 'remoteip', + 'content' => http_build_query($data), + ) + ); + + $context = stream_context_create($options); + $recaptcha_get = json_decode(file_get_contents($url, false, $context))->{'success'}; + if($recaptcha_get != '1') return 'Проверьте правильность капчи!'; + return $result; + } +} +?> diff --git a/panel/application/controllers/common/main.php b/panel/application/controllers/common/main.php new file mode 100644 index 0000000..cc5953b --- /dev/null +++ b/panel/application/controllers/common/main.php @@ -0,0 +1,64 @@ +data['title'] = $this->config->title; +$this->data['description'] = $this->config->description; +$this->data['keywords'] = $this->config->keywords; +$this->data['logo'] = $this->config->logo; +$this->data['url'] = $this->config->url; +$this->data['public'] = $this->config->public; +$this->data['oplata_status'] = $this->config->oplata_status; +$this->data['oplatahostinpl'] = $this->config->oplatahostinpl; +$this->data['status_hostinpl'] = $this->config->status_hostinpl; + +if($this->user->isLogged()) { + $this->data['logged'] = true; + $this->data['user_email'] = $this->user->getEmail(); + $this->data['user_firstname'] = $this->user->getFirstname(); + $this->data['user_lastname'] = $this->user->getLastname(); + $this->data['user_balance'] = $this->user->getBalance(); + $this->data['user_access_level'] = $this->user->getAccessLevel(); + $this->data['user_img'] = $this->user->getUser_img(); +} else { + $this->data['logged'] = false; + $this->data['user_access_level'] = 0; +} + +$logged = $this->data['logged']; +$this->data['logged'] = $logged; +if(isset($this->session->data['error'])) { + $this->data['error'] = $this->session->data['error']; + unset($this->session->data['error']); +} + +if(isset($this->session->data['warning'])) { + $this->data['warning'] = $this->session->data['warning']; + unset($this->session->data['warning']); +} + +if(isset($this->session->data['success'])) { + $this->data['success'] = $this->session->data['success']; + unset($this->session->data['success']); +} + + +$this->load->model('tickets'); +$this->load->model('ticketsMessages'); +$this->load->model('users'); +$userid = $this->user->getId(); + +$sort = array( + 'ticket_status' => 'DESC', + 'ticket_date_add' => 'DESC' +); + +$tickets = $this->ticketsModel->getTickets(array('user_id' => (int)$userid), array(), $sort, array()); + +$this->data['tickets'] = $tickets; +$visitors = $this->usersModel->getAuthLog($userid); +$this->data['visitors'] = $visitors; + +$offline = $this->config->offline; +?> diff --git a/panel/application/controllers/contacts/index.php b/panel/application/controllers/contacts/index.php new file mode 100644 index 0000000..bc2f84d --- /dev/null +++ b/panel/application/controllers/contacts/index.php @@ -0,0 +1,31 @@ +document->setActiveSection('contacts'); + $this->document->setActiveItem('index'); + $this->data['url'] = $this->config->url; + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + + $this->load->model('users'); + $users = $this->usersModel->getUsers(array(), array(), array()); + $this->data['users'] = $users; + + $this->getChild(array('common/header', 'common/footer')); + return $this->load->view('contacts/index', $this->data); + } +} +?> diff --git a/panel/application/controllers/main/acc.php b/panel/application/controllers/main/acc.php new file mode 100644 index 0000000..63d478f --- /dev/null +++ b/panel/application/controllers/main/acc.php @@ -0,0 +1,428 @@ +data['vk_id'] = $this->config->vk_id; + $this->data['url'] = $this->config->url; + + if(!$this->user->isLogged()) { + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->data['logged'] = true; + $this->data['user_email'] = $this->user->getEmail(); + $this->data['user_id'] = $this->user->getId(); + $this->data['user_firstname'] = $this->user->getFirstname(); + $this->data['user_lastname'] = $this->user->getLastname(); + $this->data['user_balance'] = $this->user->getBalance(); + $this->data['user_img'] = $this->user->getUser_img(); + $this->data['user_balance'] = $this->user->getBalance(); + + $this->load->model('waste'); + $this->load->model('tickets'); + $this->load->model('users'); + $this->load->model('servers'); + + $userid = $this->user->getId(); + + $waste = $this->wasteModel->getWaste(array('user_id' => (int)$userid), array(), array('waste_date_add' => 'DESC'), array('start' => 0,'limit' => 10)); + $this->data['waste'] = $waste; + + $this->data['user'] = array('firstname' => $this->user->getFirstname(), 'lastname' => $this->user->getLastname(), 'user_email' => $this->user->getEmail()); + $users = $this->usersModel->getUserById($userid, array(), array(), array()); + $this->data['users'] = $users; + + $userg = $this->usersModel->getUsers(array('servers'), array(), array()); + $this->data['userg'] = $userg; + + $visitors = $this->usersModel->getAuthLog($userid); + $this->data['visitors'] = $visitors; + + $auths = $this->usersModel->getAuths(array('user_id' => $userid), array(), array('auth_id' => 'DESC')); + $this->data['auths'] = $auths; + + $servers = $this->serversModel->getServers(array('user_id' => (int)$userid), array('games', 'locations'), array(), array()); + $this->data['servers'] = $servers; + + $tickets = $this->ticketsModel->getTickets(array('user_id' => (int)$userid), array(), array(), array()); + $this->data['tickets'] = $tickets; + + $row['date'] = strtotime($users['user_date_reg']); + $now = time(); + $seconds = $now - $row['date']; + $days = floor($seconds / (24*60*60)); + $this->data['user_date_reg'] = $days; + $res = $this->pluralForm($days, 'день', 'дней', 'дня'); + $this->data['user_date'] = $res; + + $this->getChild(array('common/header', 'common/footer')); + return $this->load->view('main/acc', $this->data); + } + + public function action($action = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $userid = $this->user->getId(); + + $this->load->model('users'); + $this->load->model('waste'); + + switch($action) { + case 'setVk': { + if($this->request->post['auth']){ + $Uid = $this->request->post['response']['session']['user']['id']; + + if($this->usersModel->getTotalUsers(array('user_vk_id' => $Uid))) { + $this->data['status'] = "error"; + $this->data['error'] = "Данный профиль уже привязан к другому аккаунту!"; + } else { + if (!$this->user->getUser_vk_id()) { + $this->usersModel->updateUser($userid, array('user_vk_id' => $Uid)); + + $this->data['status'] = "success"; + $this->data['success'] = "Профиль привязан!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Данный аккаунт уже привязан!"; + } + } + return json_encode($this->data); + } + + if($this->request->post['auth_vk']) { + if($user = @file_get_contents("https://api.vk.com/method/users.get?uids={$this->session->data['auth_vk']}&fields=uid,first_name,last_name,screen_name,sex,bdate,photo_big")) + $this->data['user'] = json_decode($user, true); + } + break; + } + case 'unsetVk': { + if ($this->user->getUser_vk_id()) { + $this->usersModel->updateUser($userid, array('user_vk_id' => 0)); + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно отвязали VK!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = "На данный момент у Вас не привязан VK!"; + } + break; + } + case 'closeSession': { + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $auth_id = $this->request->post['auth_id']; + $auths = $this->usersModel->getAuths(array('auth_id' => $auth_id, 'user_id' => $userid)); + if(empty($auths)) { + $this->data['status'] = "error"; + $this->data['error'] = "Сеанс не найден!"; + } else { + $auth = $auths[0]; + + if($auth['auth_key'] != @$_COOKIE['uid']) { + $this->usersModel->deleteAuth($auth['auth_id']); + + $this->data['status'] = "success"; + $this->data['success'] = "Сеанс успешно завершён!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не можете завершить текущий сеанс!"; + } + } + } + break; + } + default: { + $this->data['status'] = "error"; + $this->data['error'] = "Вы выбрали несуществующее действие!"; + break; + } + } + + return json_encode($this->data); + } + + public function ajax() { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('users'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $lastname = @$this->request->post['lastname']; + $firstname = @$this->request->post['firstname']; + $editpassword = @$this->request->post['editpassword']; + $password = @$this->request->post['password']; + + $userid = $this->user->getId(); + + if (@$firstname) { + $firstname = @strtoupper($firstname[0]) . substr($firstname, 1); + } + + if (@$lastname) { + $lastname = @strtoupper($lastname[0]) . substr($lastname, 1); + } + + $userData = array( + 'user_firstname' => $firstname, + 'user_lastname' => $lastname + ); + + if($editpassword) { + $userData['user_password'] = md5($password); + } + + $this->usersModel->updateUser($userid, $userData); + + $this->data['status'] = "success"; + $this->data['success'] = "Изменения сохранены!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } + + return json_encode($this->data); + } + + public function change_email() { + if (!$this->user->isLogged()) { + $this->data['status'] = 'error'; + $this->data['error'] = 'Вы не авторизированы!'; + return json_encode($this->data); + } + + if ($this->user->getAccessLevel() < 1) { + $this->data['status'] = 'error'; + $this->data['error'] = 'У вас нет доступа к данному разделу!'; + return json_encode($this->data); + } + + if ($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST_email = $this->validatePOST_email(); + + if (!$errorPOST_email) { + $email = @$this->request->post['email']; + $userid = $this->user->getId(); + $this->load->model('users'); + + if ($this->usersModel->getTotalUsers(array('user_email' => $email))) { + $this->data['status'] = 'error'; + $this->data['error'] = 'Указанный E-Mail уже используется!'; + return json_encode($this->data); + } + + $random = md5(uniqid(rand(), true)); + $this->usersModel->updateUser($userid, array('user_new_email' => $email . '|' . $random)); + $user = $this->usersModel->getUserById($userid); + + $this->load->library('mail'); + + $mailLib = new mailLibrary(); + $mailLib->setFrom($this->config->mail_from); + $mailLib->setSender($this->config->mail_sender); + $mailLib->setTo($user['user_email']); + $mailLib->setSubject("Смена E-Mail"); + $mailData = array(); + $mailData['firstname'] = $user['user_firstname']; + $mailData['lastname'] = $user['user_lastname']; + $mailData['email'] = $user['user_email']; + $mailData['new_email'] = $email; + $mailData['userid'] = $userid; + $mailData['key'] = $random; + $mailData['url'] = $this->config->url; + $mailData['title'] = $this->config->title; + $text = $this->load->view('mail/account/change_email', $mailData); + + $mailLib->setText($text); + $mailLib->send(); + + $this->data['status'] = 'success'; + $this->data['success'] = 'На текущий E-Mail \'' . $user['user_email'] . '\' Отправлена инструкция с дальнейшими действиями!'; + } + else { + $this->data['status'] = 'error'; + $this->data['error'] = $errorPOST_email; + } + } + + return json_encode($this->data); + } + + public function change_email_verifity($userid = null, $key = null) + { + if (!$userid || !$key) { + $this->session->data['error'] = 'Ошибка! Повторите действие.'; + $this->response->redirect('/main/index'); + return null; + } + + $this->load->model('users'); + $user = @$this->usersModel->getUserById($userid); + if ($user && (@explode('|', $user['user_new_email'])[1] == $key)) { + if ($this->usersModel->getTotalUsers(array('user_email' => @explode('|', $user['user_new_email'])[0]))) { + exit('Указанный E-Mail уже используется!'); + } + + $this->usersModel->updateUser($userid, array('user_new_email' => null, 'user_email' => @explode('|', $user['user_new_email'])[0])); + $this->session->data['success'] = 'E-Mail Сменен!'; + } else { + $this->session->data['error'] = 'Ошибка! Повторите действие.'; + } + + $this->response->redirect('/account/login'); + } + + public function img() { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('users'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $uploaddir = 'tmp/avatar/'; + $apend=date('YmdHis').rand(100,1000).'.jpg'; + $uploadfile = "$uploaddir$apend"; + + if(move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) { + if($_FILES['userfile']['type'] == 'image/gif' || $_FILES['userfile']['type'] == 'image/jpeg' || $_FILES['userfile']['type'] == 'image/png') { + if($_FILES['userfile']['size'] != 0 and $_FILES['userfile']['size'] <= 512000) { + $size = getimagesize($uploadfile); + if ($size[0] <= 512 && $size[1] <= 512) { + $userid = $this->user->getId(); + $this->usersModel->updateUser($userid, array('user_img' => $uploadfile)); + $this->data['status'] = "success"; + $this->data['success'] = "Аватар успешно был загружен!"; + } else { + $this->data['error'] = 'Загружаемое изображение превышает допустимые нормы!'; + $this->data['status'] = "error"; + unlink($uploadfile); + } + } else { + $this->data['error'] = 'Размер изображения не должено превышать 512Кб'; + $this->data['status'] = "error"; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Можно загружать только изображения в форматах jpg, jpeg и png"; + } + } else { + $this->data['error'] = 'Изображение не загружено!'; + $this->data['status'] = "error"; + } + } + return json_encode($this->data); + } + + private function validatePOST() { + + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + + $result = null; + + $lastname = @$this->request->post['lastname']; + $firstname = @$this->request->post['firstname']; + $editpassword = @$this->request->post['editpassword']; + $password = @$this->request->post['password']; + $password2 = @$this->request->post['password2']; + + if (@$firstname) { + $firstname = @strtoupper($firstname[0]) . substr($firstname, 1); + } + + if (@$lastname) { + $lastname = @strtoupper($lastname[0]) . substr($lastname, 1); + } + + if(!$validateLib->check_for_number($lastname)) { + $result = "Укажите свою реальную фамилию!"; + } + elseif(!$validateLib->check_for_number($firstname)) { + $result = "Укажите свое реальное имя!"; + } + elseif($editpassword) { + if(!$validateLib->password($password)) { + $result = "Пароль должен содержать от 6 до 32 латинских букв, цифр и знаков ,.!?_-!"; + } + elseif($password != $password2) { + $result = "Введенные вами пароли не совпадают!"; + } + } + return $result; + } + + private function validatePOST_email() + { + $this->load->library('validate'); + $validateLib = new validateLibrary(); + $result = NULL; + $email = @$this->request->post['email']; + + if (!$validateLib->email($email)) { + $result = 'Укажите свой реальный E-Mail!'; + } + + return $result; + } + + private function validatePOST_VK() { + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + + $result = null; + + $id = @strtolower($this->request->post['id']); + + if($this->usersModel->getTotalUsers(array('user_vk_id' => $id))) { + $result = "Указанный ID-".$id." уже привязан!"; + } + + return $result; + } + + public function pluralForm($n, $form1, $form2,$form5) { + $n = abs($n) % 100; + $n1 = $n % 10; + if ($n1 >= 5 && $n1 <= 4) return $form2; + if ($n >= 10 && $n <= 20) return $form2; + if ($n1 >= 2 && $n1 <= 4) return $form5; + if ($n1 == 1) return $form1; + if ($n == 0) return $form2; + } +} +?> \ No newline at end of file diff --git a/panel/application/controllers/main/cron.php b/panel/application/controllers/main/cron.php new file mode 100644 index 0000000..1afe4f0 --- /dev/null +++ b/panel/application/controllers/main/cron.php @@ -0,0 +1,661 @@ +request->get['token']; + if($this->config->token != $token) { + return "Access Denied"; + } + + $this->load->library('mail'); + $this->load->library('ssh2'); + $this->load->model('webhost'); + $this->load->model('servers'); + $this->load->model('invoices'); + + $mailLib = new mailLibrary(); + $mailLib->setFrom($this->config->mail_from); + $mailLib->setSender($this->config->mail_sender); + + $servers = $this->serversModel->getServers(array(), array('users')); + $webhosts = $this->webhostModel->getWebhosts(array(), array('users')); + + $datenow = date_create('now'); + + foreach($servers as $item) { + $operation = false; + $serverid = $item['server_id']; + $dateend = date_create($item['server_date_end']); + $diff = date_diff($datenow, $dateend); + + if($diff->invert) { + if($diff->days >= 1) { + if($this->serversModel->action($serverid, 'delete')["status"] != "success") { + $operation = true; + echo "Игровой сервер: gs" . $serverid . " - удаление не удалось.". PHP_EOL; + } + + if(!$operation) { + if($item['server_mysql'] == 1 || $item['server_mysql'] == 2) { + $this->serversModel->action($serverid, "delete_mysql"); + } + $this->serversModel->deleteServer($serverid); + $this->serversModel->deleteServerStats($serverid); + $this->serversModel->deleteserverOwners($serverid); + $this->serversModel->deleteLog($serverid); + + $firewall = $this->serversModel->getFirewallsById($serverid); + + if ($firewall) { + foreach ($firewall as $item2) { + $ssh2Lib = new ssh2Library(); + $link = $ssh2Lib->connect($item['location_ip'], $item['location_user'], $item['location_password']); + + $ssh2Lib->execute($link, "iptables -D INPUT -s ".$item2['server_ip']." -p udp -d ".$item['location_ip']." --dport ".$item['server_port']." -j DROP;"); + $ssh2Lib->execute($link, "iptables -D INPUT -s ".$item2['server_ip']." -p tcp -d ".$item['location_ip']." --dport ".$item['server_port']." -j DROP;"); + + $ssh2Lib->disconnect($link); + + $this->serversModel->deleteFirewallDB($item2['firewall_id']); + } + } + + $mailLib->setTo($item['user_email']); + $mailLib->setSubject("Удаление сервера #$serverid"); + + $mailData = array(); + $mailData['firstname'] = $item['user_firstname']; + $mailData['lastname'] = $item['user_lastname']; + $mailData['serverid'] = $serverid; + + $text = $this->load->view('mail/servers/deleted', $mailData); + + $mailLib->setText($text); + $mailLib->send(); + + echo "Игровой сервер: gs" . $serverid . " - удален.". PHP_EOL; + } + } else if($item['server_status'] != 0) { + if($this->serversModel->action($serverid, "stop")["status"] == "success") { + $this->serversModel->updateServer($serverid, array('server_status' => 0)); + $this->serversModel->action($serverid, "block"); + } else { + $operation = true; + echo "Игровой сервер: gs" . $serverid . " - блокировка не удалась.". PHP_EOL; + } + + if(!$operation) { + $mailLib->setTo($item['user_email']); + $mailLib->setSubject("Блокировка сервера #$serverid"); + + $mailData = array(); + $mailData['firstname'] = $item['user_firstname']; + $mailData['lastname'] = $item['user_lastname']; + $mailData['serverid'] = $serverid; + + $text = $this->load->view('mail/servers/lock', $mailData); + + $mailLib->setText($text); + $mailLib->send(); + + echo "Игровой сервер: gs" . $serverid . " - заблокирован.". PHP_EOL; + } + } + } else { + if($diff->days < 3) { + $mailLib->setTo($item['user_email']); + $mailLib->setSubject("Завершение оплаченного периода сервера #$serverid"); + + $mailData = array(); + $mailData['firstname'] = $item['user_firstname']; + $mailData['lastname'] = $item['user_lastname']; + $mailData['serverid'] = $serverid; + $mailData['days'] = $diff->days; + + $text = $this->load->view('mail/servers/needPay', $mailData); + + $mailLib->setText($text); + $mailLib->send(); + + echo "Игровой сервер: gs" . $serverid . " - отправлено уведомление.". PHP_EOL; + } + } + } + + foreach($webhosts as $item) { + $operation = false; + $webid = $item['web_id']; + $dateend = date_create($item['web_date_end']); + $diff = date_diff($datenow, $dateend); + + if($diff->invert) { + if($diff->days >= 3) { + $this->webhostModel->unblockWebhost($webid); + $this->webhostModel->deleteWebhost($webid); + + $mailLib->setTo($item['user_email']); + $mailLib->setSubject("Удаление веб-хостинга #$webid"); + + $mailData = array(); + $mailData['firstname'] = $item['user_firstname']; + $mailData['lastname'] = $item['user_lastname']; + $mailData['webid'] = $webid; + + $text = $this->load->view('mail/webhost/deleted', $mailData); + + $mailLib->setText($text); + $mailLib->send(); + + echo "Веб-хостинг: ws" . $webid . " - удален.". PHP_EOL; + } else if($item['web_status'] != 0) { + $this->webhostModel->blockWebhost($webid); + + $mailLib->setTo($item['user_email']); + $mailLib->setSubject("Блокировка веб-хостинга #$webid"); + + $mailData = array(); + $mailData['firstname'] = $item['user_firstname']; + $mailData['lastname'] = $item['user_lastname']; + $mailData['webid'] = $webid; + + $text = $this->load->view('mail/webhost/lock', $mailData); + + $mailLib->setText($text); + $mailLib->send(); + + echo "Веб-хостинг: ws" . $webid . " - заблокирован.". PHP_EOL; + } + } else { + if($diff->days < 3) { + $mailLib->setTo($item['user_email']); + $mailLib->setSubject("Завершение оплаченного периода веб-хостинга #$webid"); + + $mailData = array(); + $mailData['firstname'] = $item['user_firstname']; + $mailData['lastname'] = $item['user_lastname']; + $mailData['webid'] = $webid; + $mailData['days'] = $diff->days; + + $text = $this->load->view('mail/webhost/needPay', $mailData); + + $mailLib->setText($text); + $mailLib->send(); + + echo "Веб-хостинг: ws" . $webid . " - отправлено уведомление.". PHP_EOL; + } + } + } + + $invoices = $this->invoicesModel->getInvoices(array('invoice_status' => 0), array(), array(), array()); + foreach($invoices as $item) { + $this->invoicesModel->deleteInvoice($item['invoice_id']); + } + return null; + } + + public function gameServers() { + $token = @$this->request->get['token']; + if($this->config->token != $token) { + return "Access Denied"; + } + + $this->load->model('servers'); + $servers = $this->serversModel->getServers(array(), array('games', 'users', 'locations')); + + foreach($servers as $item) { + $serverid = $item['server_id']; + if($item['server_status'] == 3 AND $item['server_work'] == 1) { + $this->serversModel->updateServer($serverid, array('server_work' => 0)); + $result = $this->serversModel->action($serverid, "install"); + if($result['status'] == "success") { + echo "Игровой сервер: gs" . $serverid . " - успешная установка.". PHP_EOL; + $logData = array( + 'server_id' => $serverid, + 'reason' => 'Успешная установка сервера.', + 'status' => 1 + ); + $this->serversModel->createLog($logData); + } else { + echo "Игровой сервер: gs" . $serverid . " - неудачная установка.". PHP_EOL; + } + } + if($item['server_status'] == 4 AND $item['server_work'] == 1) { + $this->serversModel->updateServer($serverid, array('server_work' => 0)); + $result = $this->serversModel->action($serverid, "reinstall"); + if($result['status'] == "success") { + echo "Игровой сервер: gs" . $serverid . " - успешная переустановка.". PHP_EOL; + $logData = array( + 'server_id' => $serverid, + 'reason' => 'Успешная переустановка сервера.', + 'status' => 1 + ); + $this->serversModel->createLog($logData); + } else { + echo "Игровой сервер: gs" . $serverid . " - неудачная переустановка.". PHP_EOL; + } + } + if($item['server_status'] == 5 AND $item['server_work'] == 1) { + $this->serversModel->updateServer($serverid, array('server_work' => 0)); + $result = $this->serversModel->action($serverid, 'createbackup'); + if($result['status'] == "success") { + echo "Игровой сервер: gs" . $serverid . " - успешный бекап сервера.". PHP_EOL; + $logData = array( + 'server_id' => $serverid, + 'reason' => 'Успешное создание BackUP.', + 'status' => 1 + ); + $this->serversModel->createLog($logData); + } else { + echo "Игровой сервер: gs" . $serverid . " - неудачный бекап сервера.". PHP_EOL; + } + } + if($item['server_status'] == 6 AND $item['server_work'] == 1) { + $this->serversModel->updateServer($serverid, array('server_work' => 0)); + $result = $this->serversModel->action($serverid, "installbackup"); + if($result['status'] == "success") { + echo "Игровой сервер: gs" . $serverid . " - успешное восстановление из бекапа.". PHP_EOL; + $logData = array( + 'server_id' => $serverid, + 'reason' => 'Успешное восстановление из BackUP.', + 'status' => 1 + ); + $this->serversModel->createLog($logData); + } else { + echo "Игровой сервер: gs" . $serverid . " - неудачное восстановление из бекапа.". PHP_EOL; + } + } + if($item['server_status'] == 7 AND $item['server_work'] == 1) { + if($item['game_code'] == 'mine' || $item['game_code'] == 'mcpe') { + $this->serversModel->updateServer($serverid, array('server_work' => 0)); + $result = $this->serversModel->action($serverid, 'sendcommand', array('command' => 'installNewCore')); + if($result['status'] == "success") { + echo "Игровой сервер: gs" . $serverid . " - успешная смена ядра.". PHP_EOL; + $logData = array( + 'server_id' => $serverid, + 'reason' => 'Успешная смена ядра.', + 'status' => 1 + ); + $this->serversModel->createLog($logData); + } else { + echo "Игровой сервер: gs" . $serverid . " - неудачная смена ядра.". PHP_EOL; + } + } else if($item['game_code'] == 'cs') { + $this->serversModel->updateServer($serverid, array('server_work' => 0)); + $result = $this->serversModel->action($serverid, 'sendcommand', array('command' => 'installNewBuild')); + if($result['status'] == "success") { + echo "Игровой сервер: gs" . $serverid . " - успешная смена билда.". PHP_EOL; + $logData = array( + 'server_id' => $serverid, + 'reason' => 'Успешная смена билда.', + 'status' => 1 + ); + $this->serversModel->createLog($logData); + } else { + echo "Игровой сервер: gs" . $serverid . " - неудачная смена билда.". PHP_EOL; + } + } + } + } + return null; + } + + public function updateStatsLocations() { + $token = @$this->request->get['token']; + if($this->config->token != $token) { + return "Access Denied"; + } + + $this->load->model('locations'); + $locations = $this->locationsModel->getLocations(array()); + + foreach($locations as $item) { + $today = date("Y-m-d H:i:s"); + if($item['location_status'] == 1) { + $this->load->library('ssh2'); + $ssh2Lib = new ssh2Library(); + $link = $ssh2Lib->connect($item['location_ip'], $item['location_user'], $item['location_password']); + + $cpu = (int) $ssh2Lib->execute($link, 'echo $[100-$(vmstat 1 2|tail -1|awk \'{print $15}\')]'); + + $hdd_used = (int) $ssh2Lib->execute($link, 'df -h -B 1M $HOME | grep dev | awk \'{print $3}\''); + $hdd_all = (int) $ssh2Lib->execute($link, 'df -h -B 1M $HOME | grep dev | awk \'{print $2}\''); + + $ram_all = (int) $ssh2Lib->execute($link, 'cat /proc/meminfo | grep MemTotal | awk \'{print $2}\''); + $ram_free = (int) $ssh2Lib->execute($link, 'cat /proc/meminfo | grep MemAvailable | awk \'{print $2}\''); + $ram_used = (int) $ram_all - (int) $ram_free; + + $swap_all = (int) $ssh2Lib->execute($link, 'cat /proc/meminfo | grep SwapTotal | awk \'{print $2}\''); + $swap_free = (int) $ssh2Lib->execute($link, 'cat /proc/meminfo | grep SwapFree | awk \'{print $2}\''); + $swap_used = (int) $swap_all - (int) $swap_free; + + $ssh2Lib->disconnect($link); + + $cpu = $cpu > 100 ? 100 : round($cpu); + $ram_used = round($ram_used * 0.000977, 0); + $ram_all = round($ram_all * 0.000977, 0); + $swap_used = round($swap_used * 0.000977, 0); + $swap_all = round($swap_all * 0.000977, 0); + + $hdd_end = (($hdd_used * 100) / $hdd_all); + $hdd_end = $hdd_end > 100 ? 100 : round($hdd_end); + + $ram_swap_save = ((($ram_used + $swap_used) * 100) / ($ram_all + $swap_all)); + $ram_swap_save = $ram_swap_save > 100 ? 100 : round($ram_swap_save); + + $locationData = array( + 'location_cpu' => $cpu, + 'location_ram' => $ram_swap_save, + 'location_hdd' => $hdd_end, + 'location_upd' => $today + ); + $this->locationsModel->updateLocation($item['location_id'], $locationData); + + echo "Статистика игровой локации #". $item['location_id'] ." успешно обновлена (CPU: ".$cpu."%, RAM: ".$ram_swap_save."%, SSD: ".$hdd_end."%)" . PHP_EOL; + } else { + $locationData = array( + 'location_cpu' => 0, + 'location_ram' => 0, + 'location_hdd' => 0, + 'location_upd' => $today + ); + $this->locationsModel->updateLocation($item['location_id'], $locationData); + } + } + return null; + } + + public function updateStats() { + $this->load->library('query'); + $this->load->model('servers'); + + $token = @$this->request->get['token']; + if($this->config->token != $token) { + return "Access Denied"; + } + + $servers = $this->serversModel->getServers(array(), array('games', 'locations')); + + $this->serversModel->clearServersStats(); + + foreach($servers as $item) { + $serverid = $item['server_id']; + + if($item['server_status'] == 2) { + $queryLib = new queryLibrary($item['game_query']); + $queryLib->connect($item['location_ip'], $item['server_port']); + $query = $queryLib->getInfo(); + $queryLib->disconnect(); + + $sysload = $this->serversModel->getServerSystemLoad($serverid); + $ssd = round($sysload['ssd']); + $ssd_all = $item['game_ssd']; + $ssd_end = (int)(($ssd * 100) / $ssd_all); + $cpu = $sysload['cpu'] > 100 ? 100 : round($sysload['cpu']); + $ram = $sysload['ram'] > 100 ? 100 : round($sysload['ram']); + + $this->serversModel->createServerStats(array( + 'server_id' => $serverid, + 'server_stats_players' => $query['players'], + 'server_stats_cpu' => $cpu, + 'server_stats_ram' => $ram, + 'server_stats_hdd' => $ssd_end + )); + echo "Статистика игрового сервера gs" . $serverid . " успешно сохранена (CPU: ".$cpu."%, RAM: ".$ram."%, SSD: ".$ssd_end."%)" . PHP_EOL; + } + + if($item['server_status'] == 1) { + $ssd = $this->serversModel->getHDD($serverid); + $ssd = round($ssd); + $ssd_all = $item['game_ssd']; + $ssd_end = (int)(($ssd * 100) / $ssd_all); + + $this->serversModel->createServerStats(array( + 'server_id' => $serverid, + 'server_stats_players' => 0, + 'server_stats_cpu' => 0, + 'server_stats_ram' => 0, + 'server_stats_hdd' => $ssd_end + )); + echo "Статистика игрового сервера gs" . $serverid . " успешно сохранена (CPU: 0%, RAM: 0%, SSD: ".$ssd_end."%)" . PHP_EOL; + } + } + return null; + } + + public function stopServers() { + $token = @$this->request->get['token']; + if($this->config->token != $token) { + return "Access Denied"; + } + + $this->load->model('servers'); + + $servers = $this->serversModel->getServers(array(), array('games', 'locations')); + + foreach($servers as $item) { + $serverid = $item['server_id']; + + if($item['server_status'] == 2) { + $hdd = $this->serversModel->getHDD($serverid); + $hdd = round($hdd); + if($hdd > $item['game_ssd']){ + $connect = $this->serversModel->action($serverid, 'stop'); + if($connect['status'] == "success") { + $this->serversModel->deleteTask(array('task_name' => 'restart', 'server_id' => $serverid)); + $this->serversModel->deleteTask(array('task_name' => 'enable', 'server_id' => $serverid)); + $this->serversModel->deleteTask(array('task_name' => 'disable', 'server_id' => $serverid)); + $this->serversModel->updateServer($serverid, array('server_status' => 1)); + $logData = array( + 'server_id' => $serverid, + 'reason' => "Остановка сервера: OVERLOAD-ssd = ".$hdd."/".$item['game_ssd']."МБ", + 'status' => 1 + ); + $this->serversModel->createLog($logData); + echo "Остановка сервера: OVERLOAD-ssd = ".$hdd."/".$item['game_ssd']."МБ" . PHP_EOL; + } else { + echo "Ошибка остановки сервера gs$item[server_id]" . PHP_EOL; + } + } + + } + } + return null; + } + + public function stopServersQuery() { + $token = @$this->request->get['token']; + if($this->config->token != $token) { + return "Access Denied"; + } + + $this->load->library('query'); + $this->load->model('servers'); + + $servers = $this->serversModel->getServers(array(), array('games', 'locations')); + + foreach($servers as $item) { + $serverid = $item['server_id']; + + if($item['server_status'] == 2) { + $queryLib = new queryLibrary($item['game_query']); + $queryLib->connect($item['location_ip'], $item['server_port']); + $query = $queryLib->getInfo(); + $queryLib->disconnect(); + + if($query['players'] > ($item['server_slots']+1)){ + $connect = $this->serversModel->action($serverid, 'stop'); + if($connect['status'] == "success") { + $this->serversModel->deleteTask(array('task_name' => 'restart', 'server_id' => $serverid)); + $this->serversModel->deleteTask(array('task_name' => 'enable', 'server_id' => $serverid)); + $this->serversModel->deleteTask(array('task_name' => 'disable', 'server_id' => $serverid)); + $this->serversModel->updateServer($serverid, array('server_status' => 1)); + $logData = array( + 'server_id' => $serverid, + 'reason' => "Остановка сервера: Чрезмерное кол.во игроков на сервере, игроков ".$query['players']." слотов ".$item['server_slots']."", + 'status' => 1 + ); + $this->serversModel->createLog($logData); + echo "Остановка сервера: Чрезмерное кол.во игроков на сервере, игроков ".$query['players']." слотов ".$item['server_slots']."" . PHP_EOL; + } else { + echo "Ошибка остановки сервера gs$item[server_id]" . PHP_EOL; + } + } + } + } + return null; + } + + public function serverReloader() { + $token = @$this->request->get['token']; + if($this->config->token != $token) { + return "Access Denied"; + } + + $this->load->model('servers'); + $this->load->model('locations'); + + $locations = $this->locationsModel->getLocations(array()); + + foreach($locations as $location) { + echo PHP_EOL . 'Локация ('.$location['location_id'].') '.$location['location_name'].'' . PHP_EOL; + $servers = $this->serversModel->getServers(array('server_status' => '2', 'location_id' => $location['location_id'])); + if($servers){ + foreach($servers as $item) { + $serverid = $item['server_id']; + $result_status = $this->serversModel->action($serverid, 'server_status'); + + if($result_status == 1) { + $result = $this->serversModel->action($serverid, 'restart'); + if($result["status"] == "success") { + $logData = array( + 'server_id' => $serverid, + 'reason' => 'Сервер был восcтановлен после падения', + 'status' => 1 + ); + $this->serversModel->createLog($logData); + echo "Игровой сервер gs$item[server_id] - Поднят.". PHP_EOL; + } + } + } + } + } + return null; + } + + private $deletedTasks = array(); + + public function tasks() { + $token = @$this->request->get['token']; + if($this->config->token != $token) { + return "Access Denied"; + } + + $this->load->model('servers'); + $tasks = $this->serversModel->getTasks(array(), array('servers')); + $datenow = date_create('now'); + + foreach($tasks as $item) { + $serverid = $item['server_id']; + + if(!in_array($item['task_name'], $this->deletedTasks)) { + if(strtotime($item['task_lead_time']) <= strtotime(date("Y-m-d H:i:s"))) { + if($item['task_name'] == "enable") { + if($item['server_status'] == 1) { + $result = $this->serversModel->action($serverid, "start"); + if($result["status"] == "success") { + $this->serversModel->updateServer($serverid, array("server_status" => 2)); + array_push($this->deletedTasks, 'enable'); + $logData = array( + 'server_id' => $serverid, + 'reason' => '[Планировщик] Успешный запуск сервера', + 'status' => 1 + ); + $this->serversModel->createLog($logData); + echo 'Задача ' . $item['task_name'] . ' для сервера #' . $item['server_id'] . ' выполнена!' . PHP_EOL; + } + } + $this->serversModel->deleteTask(array('task_id' => $item['task_id'])); + } else if($item['task_name'] == "disable") { + if($item['server_status'] == 2) { + $result = $this->serversModel->action($serverid, "stop"); + if($result["status"] == "success") { + $this->serversModel->updateServer($serverid, array("server_status" => 1)); + array_push($this->deletedTasks, 'disable'); + array_push($this->deletedTasks, 'restart'); + array_push($this->deletedTasks, 'enable'); + $logData = array( + 'server_id' => $serverid, + 'reason' => '[Планировщик] Успешное выключение сервера', + 'status' => 1 + ); + $this->serversModel->createLog($logData); + echo 'Задача ' . $item['task_name'] . ' для сервера #' . $item['server_id'] . ' выполнена!' . PHP_EOL; + } + } + $this->serversModel->deleteTask(array('task_id' => $item['task_id'])); + } else if($item['task_name'] == "restart") { + if($item['server_status'] == 2) { + $result = $this->serversModel->action($serverid, "restart"); + if($result["status"] == "success") { + array_push($this->deletedTasks, 'enable'); + $logData = array( + 'server_id' => $serverid, + 'reason' => '[Планировщик] Успешный перезапуск сервера', + 'status' => 1 + ); + $this->serversModel->createLog($logData); + echo 'Задача ' . $item['task_name'] . ' для сервера #' . $item['server_id'] . ' выполнена!' . PHP_EOL; + } + } + if($item['task_type'] == 'single') { + $this->serversModel->deleteTask(array('task_id' => $item['task_id'])); + } else { + if($item['task_time'] == '15min') { + $lead_time = date('Y-m-d H:i:s', strtotime("+15 minutes")); + } else if($item['task_time'] == '30min') { + $lead_time = date('Y-m-d H:i:s', strtotime("+30 minutes")); + } else if($item['task_time'] == '1hour') { + $lead_time = date('Y-m-d H:i:s', strtotime("+1 hour")); + } else if($item['task_time'] == '12hours') { + $lead_time = date('Y-m-d H:i:s', strtotime("+12 hours")); + } else if($item['task_time'] == '24hours') { + $lead_time = date('Y-m-d H:i:s', strtotime("+1 day")); + } + $this->serversModel->updateTask($item['task_id'], array('task_lead_time' => $lead_time)); + } + } + } + } + } + return null; + } + + public function clearLogs() { + $token = @$this->request->get['token']; + if($this->config->token != $token) { + return "Access Denied"; + } + + $this->load->model('servers'); + + $serverLogs = $this->serversModel->getLogs(); + + $datenow = date_create('now'); + + foreach($serverLogs as $item) { + $diff = date_diff($datenow, date_create($item['date'])); + + if($diff->invert) { + if($diff->days >= 7) { + $this->serversModel->deleteLog($item['log_id']); + } + } + } + + return null; + } +} +?> diff --git a/panel/application/controllers/main/index.php b/panel/application/controllers/main/index.php new file mode 100644 index 0000000..625e5da --- /dev/null +++ b/panel/application/controllers/main/index.php @@ -0,0 +1,51 @@ +document->setActiveSection('main'); + $this->document->setActiveItem('index'); + $this->data['public'] = $this->config->public; + + if(!$this->user->isLogged()) { + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->library('pagination'); + $this->load->model('news'); + + $sort = array( + 'news_date_add' => 'DESC' + ); + + $options = array( + 'start' => ($page - 1) * $this->limit, + 'limit' => $this->limit + ); + + $total = $this->newsModel->getTotalNews(); + $news = $this->newsModel->getNews(array(), array(), $sort, $options); + + $paginationLib = new paginationLibrary(); + + $paginationLib->total = $total; + $paginationLib->page = $page; + $paginationLib->limit = $this->limit; + $paginationLib->url = $this->config->url . 'news/index/index/{page}'; + + $pagination = $paginationLib->render(); + $this->data['news'] = $news; + $this->data['pagination'] = $pagination; + + $this->getChild(array('common/header', 'common/footer')); + return $this->load->view('main/index', $this->data); + } +} +?> \ No newline at end of file diff --git a/panel/application/controllers/news/index.php b/panel/application/controllers/news/index.php new file mode 100644 index 0000000..e8dcf06 --- /dev/null +++ b/panel/application/controllers/news/index.php @@ -0,0 +1,53 @@ +document->setActiveSection('news'); + $this->document->setActiveItem('index'); + $this->data['vk_id'] = $this->config->vk_id; + $this->data['url'] = $this->config->url; + if(!$this->user->isLogged()) { + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->library('pagination'); + $this->load->model('news'); + $userid = $this->user->getId(); + + $sort = array( + //'ticket_status' => 'DESC', + 'news_date_add' => 'DESC' + ); + + $options = array( + 'start' => ($page - 1) * $this->limit, + 'limit' => $this->limit + ); + + $total = $this->newsModel->getTotalNews(); + $news = $this->newsModel->getNews(array(), array(), $sort, $options); + + $paginationLib = new paginationLibrary(); + + $paginationLib->total = $total; + $paginationLib->page = $page; + $paginationLib->limit = $this->limit; + $paginationLib->url = $this->config->url . 'news/index/index/{page}'; + + $pagination = $paginationLib->render(); + $this->data['news'] = $news; + $this->data['pagination'] = $pagination; + + $this->getChild(array('common/header', 'common/footer')); + return $this->load->view('news/index', $this->data); + } +} +?> diff --git a/panel/application/controllers/news/view.php b/panel/application/controllers/news/view.php new file mode 100644 index 0000000..b8250e5 --- /dev/null +++ b/panel/application/controllers/news/view.php @@ -0,0 +1,96 @@ +data['vk_id'] = $this->config->vk_id; + $this->data['url'] = $this->config->url; + if(!$this->user->isLogged()) { + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('news'); + $this->load->model('newsMessages'); + + $error = $this->validate($newid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'news/index'); + } + + $userid = $this->user->getId(); + + $new = $this->newsModel->getNewsById($newid, array('users')); + $messages = $this->newsMessagesModel->getNewsMessages(array('news_id' => $newid), array('users')); + $this->data['new'] = $new; + $this->data['messages'] = $messages; + $this->data['user_img'] = $this->user->getUser_img(); + + $nq = $new['look']+1; + $this->newsModel->updateNews($newid, array('look' => $nq)); + + $this->getChild(array('common/header', 'common/footer')); + return $this->load->view('news/view', $this->data); + } + + public function ajax($newid = null) { + $this->load->model('news'); + $this->load->model('newsMessages'); + + $error = $this->validate($newid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST($newid); + if(!$errorPOST) { + $text = @$this->request->post['text']; + + $userid = $this->user->getId(); + + $messageData = array( + 'news_id' => $newid, + 'user_id' => $userid, + 'news_message' => $text + ); + $this->newsMessagesModel->createNewsMessage($messageData); + + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно создали коментарий!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } + + return json_encode($this->data); + } + private function validate($newid) { + $result = null; + if(!$this->newsModel->getTotalNews(array('news_id' => (int)$newid))) { + $result = "Запрашиваемая новость не существует!"; + } + return $result; + } + + private function validatePOST($newid) { + $result = null; + + $text = @$this->request->post['text']; + if(mb_strlen($text) < 10 || mb_strlen($text) > 128) { + $result = "Текст коментариф должен содержать от 10 до 128 символов."; + } + return $result; + } + +} +?> diff --git a/panel/application/controllers/offline/index.php b/panel/application/controllers/offline/index.php new file mode 100644 index 0000000..f74120c --- /dev/null +++ b/panel/application/controllers/offline/index.php @@ -0,0 +1,14 @@ +data['result'] = $this->request->get['result']; + $this->data['public'] = $this->config->public; + + return $this->load->view('offline/index', $this->data); + } +} +?> \ No newline at end of file diff --git a/panel/application/controllers/result/anypay.php b/panel/application/controllers/result/anypay.php new file mode 100644 index 0000000..6105db0 --- /dev/null +++ b/panel/application/controllers/result/anypay.php @@ -0,0 +1,70 @@ +load->model('users'); + $this->load->model('invoices'); + $this->load->model('waste'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $ammount = $this->request->post['amount']; + $invid = $this->request->post['pay_id']; + $signature = $this->request->post['sign']; + + $invoice = $this->invoicesModel->getInvoiceById($invid); + $userid = $invoice['user_id']; + $user = $this->usersModel->getUserById($userid); + + if($ammount > 50){ + $this->usersModel->updateUser($userid, $userData = array('user_promised_pay' => 0)); + } + + $wasteData = array( + 'user_id' => $userid, + 'waste_ammount' => $ammount, + 'waste_status' => 0, + 'waste_usluga' => "Пополнение баланса пользователя", + ); + $this->wasteModel->createWaste($wasteData); + + $this->usersModel->upUserBalance($userid, $ammount); + + $bonus_percent = $this->config->bonus_percent; + $getbonus = ($ammount * (1 + $bonus_percent / 100)) - $ammount; + $this->usersModel->upUserBonuses($userid, $getbonus); + + $this->invoicesModel->updateInvoice($invid, array('invoice_status' => 1)); + return "OK$invid\n"; + } else { + return "Error: $errorPOST"; + } + } else { + return "Error: Invalid request!"; + } + } + + private function validatePOST() { + $result = null; + + $ammount = $this->request->post['amount']; + $invid = $this->request->post['pay_id']; + $signature = $this->request->post['sign']; + + $login = $this->config->anypay_login; + $password = $this->config->anypay_password; + + if(!$this->invoicesModel->getTotalInvoices(array('invoice_id' => (int)$invid))) { + $result = "Invalid invoice!"; + } + elseif(strtoupper($signature) != strtoupper(md5("$login:$ammount:$invid:$password"))) { + $result = "Invalid signature!"; + } + return $result; + } +} +?> diff --git a/panel/application/controllers/result/enot.php b/panel/application/controllers/result/enot.php new file mode 100644 index 0000000..4fd918e --- /dev/null +++ b/panel/application/controllers/result/enot.php @@ -0,0 +1,70 @@ +load->model('users'); + $this->load->model('invoices'); + $this->load->model('waste'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $ammount = $this->request->post['amount']; + $invid = $this->request->post['merchant_id']; + $signature = $this->request->post['sign_2']; + + $invoice = $this->invoicesModel->getInvoiceById($invid); + $userid = $invoice['user_id']; + $user = $this->usersModel->getUserById($userid); + + if($ammount > 50){ + $this->usersModel->updateUser($userid, $userData = array('user_promised_pay' => 0)); + } + + $wasteData = array( + 'user_id' => $userid, + 'waste_ammount' => $ammount, + 'waste_status' => 0, + 'waste_usluga' => "Пополнение баланса пользователя", + ); + $this->wasteModel->createWaste($wasteData); + + $this->usersModel->upUserBalance($userid, $ammount); + + $bonus_percent = $this->config->bonus_percent; + $getbonus = ($ammount * (1 + $bonus_percent / 100)) - $ammount; + $this->usersModel->upUserBonuses($userid, $getbonus); + + $this->invoicesModel->updateInvoice($invid, array('invoice_status' => 1)); + return "OK$invid\n"; + } else { + return "Error: $errorPOST"; + } + } else { + return "Error: Invalid request!"; + } + } + + private function validatePOST() { + $result = null; + + $ammount = $this->request->post['amount']; + $invid = $this->request->post['merchant_id']; + $signature = $this->request->post['sign_2']; + + $login = $this->config->enot_login; + $password2 = $this->config->enot_password2; + + if(!$this->invoicesModel->getTotalInvoices(array('invoice_id' => (int)$invid))) { + $result = "Invalid invoice!"; + } + elseif(strtoupper($signature) != strtoupper(md5("$login:$ammount:$password2:$invid"))) { + $result = "Invalid signature!"; + } + return $result; + } +} +?> diff --git a/panel/application/controllers/result/freekassa.php b/panel/application/controllers/result/freekassa.php new file mode 100644 index 0000000..59202ac --- /dev/null +++ b/panel/application/controllers/result/freekassa.php @@ -0,0 +1,69 @@ +load->model('users'); + $this->load->model('invoices'); + $this->load->model('waste'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $ammount = $this->request->post['OutSum']; + $invid = $this->request->post['InvId']; + $signature = $this->request->post['SignatureValue']; + + $invoice = $this->invoicesModel->getInvoiceById($invid); + $userid = $invoice['user_id']; + + if($ammount > 50){ + $this->usersModel->updateUser($userid, $userData = array('user_promised_pay' => 0)); + } + + $wasteData = array( + 'user_id' => $userid, + 'waste_ammount' => $ammount, + 'waste_status' => 0, + 'waste_usluga' => "Пополнение баланса пользователя", + ); + $this->wasteModel->createWaste($wasteData); + + $this->usersModel->upUserBalance($userid, $ammount); + + $bonus_percent = $this->config->bonus_percent; + $getbonus = ($ammount * (1 + $bonus_percent / 100)) - $ammount; + $this->usersModel->upUserBonuses($userid, $getbonus); + + $this->invoicesModel->updateInvoice($invid, array('invoice_status' => 1)); + return "OK$invid\n"; + } else { + return "Error: $errorPOST"; + } + } else { + return "Error: Invalid request!"; + } + } + + private function validatePOST() { + $result = null; + + $ammount = $this->request->post['OutSum']; + $invid = $this->request->post['InvId']; + $signature = $this->request->post['SignatureValue']; + + $password2 = $this->config->fk_password2; + + if(!$this->invoicesModel->getTotalInvoices(array('invoice_id' => (int)$invid))) { + $result = "Invalid invoice!"; + } + elseif(strtoupper($signature) != strtoupper(md5("$ammount:$invid:$password2"))) { + + $result = "Invalid signature!"; + } + return $result; + } +} +?> diff --git a/panel/application/controllers/result/litekassa.php b/panel/application/controllers/result/litekassa.php new file mode 100644 index 0000000..c4a32da --- /dev/null +++ b/panel/application/controllers/result/litekassa.php @@ -0,0 +1,70 @@ +load->model('users'); + $this->load->model('invoices'); + $this->load->model('waste'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $ammount = $this->request->post['AMOUNT']; + $invid = $this->request->post['ORDER_ID']; + $signature = $this->request->post['SIGN']; + + $invoice = $this->invoicesModel->getInvoiceById($invid); + $userid = $invoice['user_id']; + + if($ammount > 50){ + $this->usersModel->updateUser($userid, $userData = array('user_promised_pay' => 0)); + } + + $wasteData = array( + 'user_id' => $userid, + 'waste_ammount' => $ammount, + 'waste_status' => 0, + 'waste_usluga' => "Пополнение баланса пользователя", + ); + $this->wasteModel->createWaste($wasteData); + + $this->usersModel->upUserBalance($userid, $ammount); + + $bonus_percent = $this->config->bonus_percent; + $getbonus = ($ammount * (1 + $bonus_percent / 100)) - $ammount; + $this->usersModel->upUserBonuses($userid, $getbonus); + + $this->invoicesModel->updateInvoice($invid, array('invoice_status' => 1)); + return "OK$invid\n"; + } else { + return "Error: $errorPOST"; + } + } else { + return "Error: Invalid request!"; + } + } + + private function validatePOST() { + $result = null; + + $ammount = $this->request->post['AMOUNT']; + $invid = $this->request->post['ORDER_ID']; + $signature = $this->request->post['SIGN']; + + $password = $this->config->lk_password; + $login = $this->config->lk_login; + + if(!$this->invoicesModel->getTotalInvoices(array('invoice_id' => (int)$invid))) { + $result = "Invalid invoice!"; + } + elseif(strtoupper($signature) != strtoupper(md5("$login:$ammount:$password:$invid"))) { + + $result = "Invalid signature!"; + } + return $result; + } +} +?> diff --git a/panel/application/controllers/result/qiwi.php b/panel/application/controllers/result/qiwi.php new file mode 100644 index 0000000..43b702b --- /dev/null +++ b/panel/application/controllers/result/qiwi.php @@ -0,0 +1,98 @@ +load->model('users'); + $this->load->model('invoices'); + $this->load->model('waste'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $jsonPaymentData = json_decode(file_get_contents('php://input'), true); + $ammount = $jsonPaymentData['bill']['amount']['value']; + $invid = $jsonPaymentData['bill']['billId']; + $signature = $jsonPaymentData['bill']['siteId']; + + $invoice = $this->invoicesModel->getInvoiceById($invid); + $userid = $invoice['user_id']; + $user = $this->usersModel->getUserById($userid); + + if($ammount > 50){ + $this->usersModel->updateUser($userid, $userData = array('user_promised_pay' => 0)); + } + + $wasteData = array( + 'user_id' => $userid, + 'waste_ammount' => $ammount, + 'waste_status' => 0, + 'waste_usluga' => "Пополнение баланса пользователя", + ); + $this->wasteModel->createWaste($wasteData); + + $this->usersModel->upUserBalance($userid, $ammount); + + $bonus_percent = $this->config->bonus_percent; + $getbonus = ($ammount * (1 + $bonus_percent / 100)) - $ammount; + $this->usersModel->upUserBonuses($userid, $getbonus); + + $this->invoicesModel->updateInvoice($invid, array('invoice_status' => 1)); + return "OK$invid\n"; + } else { + return "Error: $errorPOST"; + } + } else { + return "Error: Invalid request!"; + } + } + + private function checkNotificationSignature($signature, array $notificationBody, $merchantSecret) { + $notificationBody = array_replace_recursive( + [ + 'bill' => [ + 'billId' => null, + 'amount' => [ + 'value' => null, + 'currency' => null, + ], + 'siteId' => null, + 'status' => ['value' => null], + ], + ], + $notificationBody + ); + + $processedNotificationData = [ + 'billId' => (string) $notificationBody['bill']['billId'], + 'amount.value' => number_format(round(floatval($notificationBody['bill']['amount']['value']), 2, PHP_ROUND_HALF_DOWN), 2, '.', ''), + 'amount.currency' => (string) $notificationBody['bill']['amount']['currency'], + 'siteId' => (string) $notificationBody['bill']['siteId'], + 'status' => (string) $notificationBody['bill']['status']['value'], + ]; + ksort($processedNotificationData); + $processedNotificationDataKeys = join('|', $processedNotificationData); + $hash = hash_hmac('SHA256', $processedNotificationDataKeys, $merchantSecret); + + return $hash === $signature; + } + + private function validatePOST() { + $result = null; + + $jsonPaymentData = json_decode(file_get_contents('php://input'), true); + $invid = $jsonPaymentData['bill']['billId']; + $signature = array_key_exists('HTTP_X_API_SIGNATURE_SHA256', $_SERVER) ? stripslashes($this->request->server['HTTP_X_API_SIGNATURE_SHA256']) : ''; + + if(!$this->invoicesModel->getTotalInvoices(array('invoice_id' => (int)$invid))) { + $result = "Invalid invoice!"; + }elseif(!$this->checkNotificationSignature($signature, $jsonPaymentData, $this->config->qiwisecretkey)) { + $result = "Invalid signature!"; + } + + return $result; + } +} +?> diff --git a/panel/application/controllers/result/robokassa.php b/panel/application/controllers/result/robokassa.php new file mode 100644 index 0000000..4b5f1ad --- /dev/null +++ b/panel/application/controllers/result/robokassa.php @@ -0,0 +1,69 @@ +load->model('users'); + $this->load->model('invoices'); + $this->load->model('waste'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $ammount = $this->request->post['OutSum']; + $invid = $this->request->post['InvId']; + $signature = $this->request->post['SignatureValue']; + + $invoice = $this->invoicesModel->getInvoiceById($invid); + $userid = $invoice['user_id']; + + if($ammount > 50){ + $this->usersModel->updateUser($userid, $userData = array('user_promised_pay' => 0)); + } + + $wasteData = array( + 'user_id' => $userid, + 'waste_ammount' => $ammount, + 'waste_status' => 0, + 'waste_usluga' => "Пополнение баланса пользователя", + ); + $this->wasteModel->createWaste($wasteData); + + $this->usersModel->upUserBalance($userid, $ammount); + + $bonus_percent = $this->config->bonus_percent; + $getbonus = ($ammount * (1 + $bonus_percent / 100)) - $ammount; + $this->usersModel->upUserBonuses($userid, $getbonus); + + $this->invoicesModel->updateInvoice($invid, array('invoice_status' => 1)); + return "OK$invid\n"; + } else { + return "Error: $errorPOST"; + } + } else { + return "Error: Invalid request!"; + } + } + + private function validatePOST() { + $result = null; + + $ammount = $this->request->post['OutSum']; + $invid = $this->request->post['InvId']; + $signature = $this->request->post['SignatureValue']; + + $password2 = $this->config->rk_password2; + + if(!$this->invoicesModel->getTotalInvoices(array('invoice_id' => (int)$invid))) { + $result = "Invalid invoice!"; + } + elseif(strtoupper($signature) != strtoupper(md5("$ammount:$invid:$password2"))) { + + $result = "Invalid signature!"; + } + return $result; + } +} +?> diff --git a/panel/application/controllers/result/unitpay.php b/panel/application/controllers/result/unitpay.php new file mode 100644 index 0000000..fd8db88 --- /dev/null +++ b/panel/application/controllers/result/unitpay.php @@ -0,0 +1,105 @@ +load->model('users'); + $this->load->model('invoices'); + $this->load->model('waste'); + + error_reporting(0); + function md5sign($params, $secretKey) { + ksort($params); + unset($params['sign']); + + return md5(join(null, $params).$secretKey); + } + + function responseError($message) { + $error = array( + "jsonrpc" => "2.0", + "error" => array( + "code" => -32000, + "message" => $message + ), + 'id' => 1 + ); + echo json_encode($error); exit(); + } + + function responseSuccess($message) { + $success = array( + "jsonrpc" => "2.0", + "result" => array( + "message" => $message + ), + 'id' => 1 + ); + echo json_encode($success); exit(); + } + + $secretKey = $this->config->unitpay_secret; + $method = $_GET['method']; + $params = $_GET['params']; + + if ($params['sign'] != md5($params, $secretKey)) { + responseError("Не соответсвие MD5 хешей"); + } + + switch($method) { + case 'check': + if (!$this->link = @mysqli_connect($this->config->db_hostname, $this->config->db_username, $this->config->db_password, $this->config->database)) { + die('Ошибка: Не удалось соединиться с сервером базы данных!'); + } + break; + case 'pay': + if (!$this->link = @mysqli_connect($this->config->db_hostname, $this->config->db_username, $this->config->db_password, $this->config->database)) { + die('Ошибка: Не удалось соединиться с сервером базы данных!'); + } + + $invid = $_GET['params']['account']; + + if(!$this->invoicesModel->getTotalInvoices(array('invoice_id' => (int)$invid))) { + responseError("Invalid invoice!"); + } + + $ammount = $_GET['params']['sum']; + + $invoice = $this->invoicesModel->getInvoiceById($invid); + $userid = $invoice['user_id']; + $user = $this->usersModel->getUserById($userid); + + if($invoice['invoice_ammount'] == $ammount){ + if($ammount > 50){ + $this->usersModel->updateUser($userid, $userData = array('user_promised_pay' => 0)); + } + + $wasteData = array( + 'user_id' => $userid, + 'waste_ammount' => $ammount, + 'waste_status' => 0, + 'waste_usluga' => "Пополнение баланса пользователя", + ); + $this->wasteModel->createWaste($wasteData); + + $this->usersModel->upUserBalance($userid, $ammount); + + $bonus_percent = $this->config->bonus_percent; + $getbonus = ($ammount * (1 + $bonus_percent / 100)) - $ammount; + $this->usersModel->upUserBonuses($userid, $getbonus); + + $this->invoicesModel->updateInvoice($invid, array('invoice_status' => 1)); + } + break; + case 'error': + responseError("Ошибка,{$params['errorMessage']}"); exit; + break; + default: + responseError("Только: check, pay"); exit; + } + responseSuccess("Успех"); + } +} +?> diff --git a/panel/application/controllers/result/yandexkassa.php b/panel/application/controllers/result/yandexkassa.php new file mode 100644 index 0000000..7043365 --- /dev/null +++ b/panel/application/controllers/result/yandexkassa.php @@ -0,0 +1,78 @@ +load->model('users'); + $this->load->model('invoices'); + $this->load->model('waste'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $ammount = $this->request->post['amount']; + $invid = $this->request->post['label']; + + $invoice = $this->invoicesModel->getInvoiceById($invid); + $userid = $invoice['user_id']; + + if($ammount > 50){ + $this->usersModel->updateUser($userid, $userData = array('user_promised_pay' => 0)); + } + + $wasteData = array( + 'user_id' => $userid, + 'waste_ammount' => $ammount, + 'waste_status' => 0, + 'waste_usluga' => "Пополнение баланса пользователя", + ); + $this->wasteModel->createWaste($wasteData); + + $this->usersModel->upUserBalance($userid, $ammount); + + $bonus_percent = $this->config->bonus_percent; + $getbonus = ($ammount * (1 + $bonus_percent / 100)) - $ammount; + $this->usersModel->upUserBonuses($userid, $getbonus); + + $this->invoicesModel->updateInvoice($invid, array('invoice_status' => 1)); + return "OK$invid\n"; + } else { + return "Error: $errorPOST"; + } + } else { + return "Error: Invalid request!"; + } + } + + private function validatePOST() { + $result = null; + + $ammount = $this->request->post['amount']; + $invoiceid = $this->request->post['label']; + $signature = $this->request->post['sha1_hash']; + $notification_type = $this->request->post['notification_type']; + $operation_id = $this->request->post['operation_id']; + $amount = $this->request->post['amount']; + $currency = $this->request->post['currency']; + $datetime = $this->request->post['datetime']; + $sender = $this->request->post['sender']; + $codepro = $this->request->post['codepro']; + $unaccepted = $this->request->post['unaccepted']; + + $password = $this->config->yk_password1; + + if(!$this->invoicesModel->getTotalInvoices(array('invoice_id' => (int)$invoiceid))) { + $result = "Invalid invoice!"; + }elseif($signature != sha1($notification_type.'&'.$operation_id.'&'.$amount.'&'.$currency.'&'.$datetime.'&'.$sender.'&'.$codepro.'&'.$password.'&'.$invoiceid)) { + $result = "Invalid signature!"; + }elseif($codepro === true) { + $result = "Invalid codepro!"; + }elseif($unaccepted === true) { + $result = "Invalid unaccepted!"; + } + return $result; + } +} +?> diff --git a/panel/application/controllers/servers/autoinstall.php b/panel/application/controllers/servers/autoinstall.php new file mode 100644 index 0000000..fc59659 --- /dev/null +++ b/panel/application/controllers/servers/autoinstall.php @@ -0,0 +1,260 @@ +document->setActiveSection('servers'); + $this->document->setActiveItem('autoinstall'); + $this->data['activesection'] = $this->document->getActiveSection(); + $this->data['activeitem'] = $this->document->getActiveItem(); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('servers'); + $this->load->model('users'); + + $error = $this->validate($serverid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'servers/index'); + } + + $userid = $this->user->getId(); + + $server = $this->serversModel->getServerById($serverid, array('games', 'locations')); + $this->data['server'] = $server; + + $mods = $this->serversModel->getMods(array('mod_status' => 1),array('games'),array(), array()); + $this->data['usermods'] = $this->usersModel->getUserMods($userid); + $this->data['mods'] = $mods; + + include_once 'application/controllers/common/main.php'; + + $this->getChild(array('common/header', 'common/footer')); + return $this->load->view('servers/autoinstall', $this->data); + } + + public function action($serverid = null, $action = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 0) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + $userid = $this->user->getId(); + $this->load->model('servers'); + $this->load->library('ssh2'); + $this->load->model('users'); + $this->load->model('waste'); + $ssh2Lib = new ssh2Library(); + + $error = $this->validate($serverid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + $error = $this->validateMode($action); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + $balance = $this->user->getBalance(); + $server = $this->serversModel->getServerById($serverid, array('users', 'locations', 'games')); + + if($server['server_status'] == 3) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет установка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 4) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет переустановка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 5) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет создание BackUP сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 6) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет восстанновление сервера из BackUP!"; + return json_encode($this->data); + } else if($server['server_status'] == 7) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет обновление сервера!"; + return json_encode($this->data); + } else if($server["server_status"] == 0) { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер заблокирован!"; + return json_encode($this->data); + } + + $mod = $this->serversModel->getModById($action); + + if($mod["mod_status"] != 1) { + $this->data["status"] = "error"; + $this->data["error"] = "Данный мод не доступен для установки!"; + return json_encode($this->data); + } + + if($server['server_mysql'] == 0) { + $this->data['status'] = "error"; + $this->data['error'] = "Создайте базу MySQL и включите ее!"; + return json_encode($this->data); + } + + if($server['server_status'] != 1) { + $this->data['status'] = "error"; + $this->data['error'] = "Сервер должен быть выключен!"; + return json_encode($this->data); + } + + $stats = $this->serversModel->getHDD($server['server_id']); + if($stats > $server['game_ssd']) { + $this->data["status"] = "error"; + $this->data["error"] = "Вы привысили ограничение размера директории на ". round($stats - $server['game_ssd'], 2) ."МБ, установка мода невозможна!"; + return json_encode($this->data); + } + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $this->serversModel->deleteTask(array('task_name' => 'restart', 'server_id' => $serverid)); + $this->serversModel->deleteTask(array('task_name' => 'enable', 'server_id' => $serverid)); + $this->serversModel->deleteTask(array('task_name' => 'disable', 'server_id' => $serverid)); + if($mod['mod_price'] > 0) { + if($this->usersModel->checkFreeMode($userid, $mod['mod_id'])){ + $free_mode = 1; + } + $price = $mod['mod_price']; + if(($balance < $price) and $free_mode != 1){ + $this->data['status'] = "error"; + $this->data['error'] = "Недостаточно средств"; + return json_encode($this->data); + } + } + $this->serversModel->action($serverid, 'reinstall'); + $host = $server['location_ip']; + $uname = "gs$serverid"; + $dbpass = $server['db_pass']; + $database = "gs$serverid"; + $conn = new mysqli($host, $uname, $dbpass, $database); + $op_data = ''; + if ($mresult = $conn->query("SHOW TABLES")) + { + while($row = $mresult->fetch_array(MYSQLI_NUM)) + { + $conn->query('DROP TABLE IF EXISTS '.$row[0]); + } + } + $FILE = "scriptfiles/mysql_settings.ini"; + $link = $ssh2Lib->connect($server['location_ip'], $server['location_user'], $server['location_password']); + $ssh2Lib->execute($link, + " + cd /home/gs$serverid; + rm server.cfg; + rm -rf gamemodes; + rm -rf filterscripts; + rm -rf include; + rm -rf npcmodes; + rm -rf scriptfiles; + wget ".$mod['mod_url']."; + tar -xf ".$mod['mod_arch']."; + rm ".$mod['mod_arch']."; + mysql -h".$server['location_ip']." -u gs$serverid -p".$server['db_pass']." gs$serverid < dump.sql; + rm dump.sql; + echo 'host = ".$server['location_ip']."'>>".$FILE."; + echo 'username = gs$serverid'>>".$FILE."; + echo 'password = ".$server['db_pass']."'>>".$FILE."; + echo 'database = gs$serverid'>>".$FILE."; + sudo chown -R gs". $server['server_id'] .":gameservers /home/gs". $server['server_id'] ." + " + ); + $ssh2Lib->disconnect($link); + if($mod['mod_price'] > 0) { + if($free_mode != 1){ + $userid = $this->user->getId(); + $wasteData = array( + 'user_id' => $userid, + 'waste_ammount' => $price, + 'waste_status' => 1, + 'waste_usluga' => "Установка мода ".$mod['mod_name']."" + ); + $this->wasteModel->createWaste($wasteData); + $this->usersModel->downUserBalance($userid, $price); + $freeData = array( + 'user_id' => $userid, + 'mod_id' => "".$mod['mod_id']."" + ); + $this->usersModel->addMode($freeData); + + $user = $this->usersModel->getUserById($userid, array(), array(), array()); + + if($user['ref'] != 0) { + $ref_percent = $this->config->ref_percent; + $getpref = ($price * (1 + $ref_percent / 100)) - $price; + $this->usersModel->upUserBalance($user['ref'], $getpref); + $this->usersModel->upUserRMoney($user['ref'], $getpref); + + $wasteData = array( + 'user_id' => $user['ref'], + 'waste_ammount' => $getpref, + 'waste_status' => 0, + 'waste_usluga' => "Бонус с реферала ID-$userid" + ); + $this->wasteModel->createWaste($wasteData); + } + + $this->data['status'] = "success"; + $this->data['success'] = "Мод ".$mod['mod_name']." успешно был установлен,с вашего счёта снято ".$mod['mod_price']." р! Запускаем игровой сервер, пожалуйста, подождите..."; + } else{ + $this->data['status'] = "success"; + $this->data['success'] = "Мод ".$mod['mod_name']." успешно был установлен. Запускаем игровой сервер, пожалуйста, подождите..."; + } + } else { + $this->data['status'] = "success"; + $this->data['success'] = "Мод ".$mod['mod_name']." успешно был установлен. Запускаем игровой сервер, пожалуйста, подождите..."; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Не POST запрос!"; + } + return json_encode($this->data); + } + + private function validate($serverid) { + $result = null; + + $userid = $this->user->getId(); + + if(!$this->serversModel->getTotalServerOwners(array('server_id' => (int)$serverid, 'user_id' => (int)$userid, 'owner_status' => 1))) { + if(!$this->serversModel->getTotalServers(array('server_id' => (int)$serverid, 'user_id' => (int)$userid))) { + $result = "Запрашиваемый сервер не существует!"; + } + } + return $result; + } + + private function validateMode($modid) { + $result = null; + + if(!$this->serversModel->getTotalMods(array('mod_id' => (int)$modid))) { + $result = "Запрашиваемый мод не существует!"; + } + return $result; + } +} +?> \ No newline at end of file diff --git a/panel/application/controllers/servers/config.php b/panel/application/controllers/servers/config.php new file mode 100644 index 0000000..8f99b55 --- /dev/null +++ b/panel/application/controllers/servers/config.php @@ -0,0 +1,168 @@ +document->setActiveSection('servers'); + $this->document->setActiveItem('config'); + $this->data['activesection'] = $this->document->getActiveSection(); + $this->data['activeitem'] = $this->document->getActiveItem(); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('servers'); + + $error = $this->validate($serverid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'servers/index'); + } + + $server = $this->serversModel->getServerById($serverid, array('games', 'locations')); + $this->data['server'] = $server; + + if($server['server_status'] == 1 || $server['server_status'] == 2) { + if($server['game_query'] == 'samp') { + $file = "/server.cfg"; + } else if($server['game_query'] == 'mtasa') { + $file = "/mods/deathmatch/mtaserver.conf"; + } else if($server['game_code'] == 'cs') { + $file = "/cstrike/server.cfg"; + } else if($server['game_code'] == 'css') { + $file = "/cstrike/cfg/server.cfg"; + } else if($server['game_code'] == 'csgo') { + $file = "/csgo/cfg/server.cfg"; + } else if($server['game_query'] == 'mine') { + $file = "/server.properties"; + } else if($server['game_code'] == 'ragemp') { + $file = "/conf.json"; + } + + $this->load->library('sftp'); + $sftpLib = new sftpLibrary(); + $sftpLink = $sftpLib->connect($server['location_ip'], $server['location_user'], $server['location_password']); + $config = $sftpLib->open($sftpLink, '/home/gs' . $serverid . '/' . $file); + $this->data['config'] = $config; + } else { + $config = "В данном статусе не доступно редактирование конфигурации!"; + $this->data['config'] = $config; + } + + include_once 'application/controllers/common/main.php'; + + $this->getChild(array('common/header', 'common/footer')); + return $this->load->view('servers/config', $this->data); + } + + public function send_config($serverid = null) + { + if (!$this->user->isLogged()) { + $this->data['status'] = 'error'; + $this->data['error'] = 'Вы не авторизированы!'; + return json_encode($this->data); + } + + if ($this->user->getAccessLevel() < 0) { + $this->data['status'] = 'error'; + $this->data['error'] = 'У вас нет доступа к данному разделу!'; + return json_encode($this->data); + } + + $this->load->model('servers'); + + $error = $this->validate($serverid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'servers/index'); + } + + $server = $this->serversModel->getServerById($serverid, array('users', 'locations', 'games')); + + if($server['server_status'] == 3) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет установка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 4) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет переустановка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 5) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет создание BackUP сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 6) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет восстанновление сервера из BackUP!"; + return json_encode($this->data); + } else if($server['server_status'] == 7) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет обновление сервера!"; + return json_encode($this->data); + } else if($server["server_status"] == 0) { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер заблокирован!"; + return json_encode($this->data); + } + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + if($server['server_status'] == 1 || $server['server_status'] == 2) { + $config = htmlspecialchars_decode($this->request->post['config']); + if($server['game_query'] == 'samp') { + $file = "/server.cfg"; + } else if($server['game_query'] == 'mtasa') { + $file = "/mods/deathmatch/mtaserver.conf"; + } else if($server['game_code'] == 'cs') { + $file = "/cstrike/server.cfg"; + } else if($server['game_code'] == 'css') { + $file = "/cstrike/cfg/server.cfg"; + } else if($server['game_code'] == 'csgo') { + $file = "/csgo/cfg/server.cfg"; + } else if($server['game_query'] == 'mine') { + $file = "/server.properties"; + } else if($server['game_code'] == 'ragemp') { + $file = "/conf.json"; + } + + $this->load->library('sftp'); + $sftpLib = new sftpLibrary(); + $sftpLink = $sftpLib->connect($server['location_ip'], $server['location_user'], $server['location_password']); + $sftpLib->write($sftpLink, '/home/gs' . $serverid . '/' . $file, $config); + $this->data['status'] = 'success'; + $this->data['success'] = 'Конфигурационный файл отредактирован!'; + } + } + return json_encode($this->data); + } + + function validate($serverid) { + $result = null; + $this->user->getId( ); + $userid = $this->user->getId(); + + if(!$this->serversModel->getTotalServerOwners(array('server_id' => (int)$serverid, 'user_id' => (int)$userid, 'owner_status' => 1))) { + if(!$this->serversModel->getTotalServers(array('server_id' => (int)$serverid, 'user_id' => (int)$userid))) { + $result = "Запрашиваемый сервер не существует!"; + } + } + return $result; + } + + private function validatePOST() { + + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + + return $result; + } +} \ No newline at end of file diff --git a/panel/application/controllers/servers/console.php b/panel/application/controllers/servers/console.php new file mode 100644 index 0000000..75bdcb8 --- /dev/null +++ b/panel/application/controllers/servers/console.php @@ -0,0 +1,371 @@ +document->setActiveSection('servers'); + $this->document->setActiveItem('console'); + $this->data['activesection'] = $this->document->getActiveSection(); + $this->data['activeitem'] = $this->document->getActiveItem(); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + if(isset($this->request->get['open'])) { + $this->data['fileid'] = $this->request->get['open']; + } + + $this->load->model('servers'); + + $error = $this->validate($serverid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'servers/index'); + } + + $server = $this->serversModel->getServerById($serverid, array('games', 'locations')); + $this->data['server'] = $server; + + if(isset($_COOKIE["data-theme-console"])){ + $this->data['theme'] = $_COOKIE['data-theme-console']; + } else{ + $this->data['theme'] = "color: white; background-color: black; font-family: Inconsolata; resize: none; min-height: 300px;"; + } + + include_once 'application/controllers/common/main.php'; + + $this->getChild(array('common/header', 'common/footer')); + return $this->load->view('servers/console', $this->data); + } + + public function getconsole($serverid = null, $file = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('servers'); + $this->load->library('ssh2'); + + $server = $this->serversModel->getServerById($serverid, array('games', 'locations')); + + $error = $this->validate($serverid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'servers/index'); + } + + switch($file) { + default: { + if($server["game_query"] == "samp") { + $fileLog = "server_log.txt"; + } elseif($server["game_query"] == "mtasa") { + $fileLog = "mods/deathmatch/logs/server.log"; + } elseif($server["game_code"] == "mcpe") { + $fileLog = "server.log"; + } else { + $fileLog = "screenlog.0"; + } + break; + } + case 'screenlog': { + $fileLog = "screenlog.0"; + break; + } + } + + if($server['server_status'] == 3) { + $result = "Идет установка сервера!"; + } else if($server['server_status'] == 4) { + $result = "Идет переустановка сервера!"; + } else if($server['server_status'] == 5) { + $result = "Идет создание BackUP сервера!"; + } else if($server['server_status'] == 6) { + $result = "Идет восстанновление сервера из BackUP!"; + } else if($server['server_status'] == 7) { + $result = "Идет обновление сервера!"; + } else if($server["server_status"] == 0) { + $result = "Сервер заблокирован!"; + } else if($server["server_status"] == 1) { + $result = "Сервер должен быть включен!"; + } else if($server["server_status"] == 2) { + $ssh = new ssh2Library(); + $connect = $ssh->connect($server['location_ip'], $server['location_user'], $server['location_password']); + if($server["game_query"] == "ragemp" || $server["game_query"] == "valve") { + $logs = $ssh->execute($connect, "tail -n 500 /home/gs" . $serverid . "/" . $fileLog. " | iconv -t utf8"); + } else { + $logs = $ssh->execute($connect, "tail -n 500 /home/gs" . $serverid . "/" . $fileLog. " | iconv -f cp1251 -t utf8"); + } + $logs = str_replace("", "", $logs); + $logs = str_replace(">", "", $logs); + $logs = str_replace(">", "", $logs); + $logs = str_replace("null", "", $logs); + if(!empty($logs)) { + $result = $logs; + } else { + $result = 'Список логов пуст :('; + } + $ssh->disconnect($connect); + } + return $result; + } + + public function sendconsole($serverid = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('servers'); + $this->load->library('ssh2'); + + $server = $this->serversModel->getServerById($serverid, array('games', 'locations')); + + $error = $this->validate($serverid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'servers/index'); + } + + if($server['server_status'] == 3) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет установка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 4) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет переустановка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 5) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет создание BackUP сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 6) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет восстанновление сервера из BackUP!"; + return json_encode($this->data); + } else if($server['server_status'] == 7) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет обновление сервера!"; + return json_encode($this->data); + } else if($server["server_status"] == 0) { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер заблокирован!"; + return json_encode($this->data); + } + + $command = @$this->request->post['cmd']; + + if($server['server_status'] == 2){ + if($command == ""){ + $this->data['status'] = "error"; + $this->data['error'] = "Введите команду!"; + }elseif($command != ""){ + if($server['game_query'] == "samp") { + $this->load->library('SampRconAPI'); + $SampRcon = new SampRconAPI($server['location_ip'], $server['server_port'], $server['rcon_password']); + if ($SampRcon->connect()) { + $SampRcon->call($command, false); + + $this->data['status'] = "success"; + $this->data['success'] = "Команда успешно отправлена!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Ошибка подключения к rcon!"; + } + $SampRcon->close(); + } else { + $exec = str_replace("'", "'", $command); + $this->serversModel->action($serverid, 'sendcommand', array('command' => $exec)); + + $this->data['status'] = "success"; + $this->data['success'] = "Команда успешно отправлена!"; + } + } + }else{ + $this->data['status'] = "error"; + $this->data['error'] = "Сервер должен быть включён!"; + } + return json_encode($this->data); + } + + public function clearcon($serverid = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('servers'); + $this->load->library('ssh2'); + + $server = $this->serversModel->getServerById($serverid, array('games','locations')); + + $error = $this->validate($serverid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'servers/index'); + } + + if($server['server_status'] == 3) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет установка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 4) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет переустановка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 5) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет создание BackUP сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 6) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет восстанновление сервера из BackUP!"; + return json_encode($this->data); + } else if($server['server_status'] == 7) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет обновление сервера!"; + return json_encode($this->data); + } else if($server["server_status"] == 0) { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер заблокирован!"; + return json_encode($this->data); + } + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + if($server['server_status'] == 2) { + $ssh2Lib = new ssh2Library(); + $link = $ssh2Lib->connect($server['location_ip'], $server['location_user'], $server['location_password']); + if($server['game_query'] == 'samp') { + $ssh2Lib->execute($link, "cat /dev/null > /home/gs$serverid/server_log.txt;"); + $ssh2Lib->execute($link, "cat /dev/null > /home/gs$serverid/screenlog.0;"); + } elseif($server['game_code'] == 'mcpe') { + $ssh2Lib->execute($link, "cat /dev/null > /home/gs$serverid/server.log;"); + } elseif($server['game_query'] == 'mtasa') { + $ssh2Lib->execute($link, "cat /dev/null > /home/gs$serverid/mods/deathmatch/logs/server.log;"); + } else { + $ssh2Lib->execute($link, "cat /dev/null > /home/gs$serverid/screenlog.0;"); + } + $ssh2Lib->disconnect($link); + $this->data['status'] = "success"; + $this->data['success'] = "Консоль успешно очищена!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Сервер должен быть включен!"; + } + } + return json_encode($this->data); + } + + public function action_theme_console($action = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + switch($action) { + case 'default': { + $name = 'color: white; background-color: black; font-family: Inconsolata; resize: none; min-height: 300px;'; + setcookie('data-theme-console',$name,time() + (86400 * 5), '/' ); + $this->data['status'] = "success"; + $this->data['success'] = "Тема установлена!"; + break; + } + case 'Amethyst': { + $name = 'color: #323e42; background-color: #a48ad4; font-family: Inconsolata; resize: none; min-height: 300px;'; + setcookie('data-theme-console',$name,time() + (86400 * 5), '/' ); + $this->data['status'] = "success"; + $this->data['success'] = "Тема установлена!"; + break; + } + case 'City': { + $name = 'color: #323e42; background-color: #ff6b6b; font-family: Inconsolata; resize: none; min-height: 300px;'; + setcookie('data-theme-console',$name,time() + (86400 * 5), '/' ); + $this->data['status'] = "success"; + $this->data['success'] = "Тема установлена!"; + break; + } + case 'Flat': { + $name = 'color: #323e42; background-color: #44b4a6; font-family: Inconsolata; resize: none; min-height: 300px;'; + setcookie('data-theme-console',$name,time() + (86400 * 5), '/' ); + $this->data['status'] = "success"; + $this->data['success'] = "Тема установлена!"; + break; + } + case 'Modern': { + $name = 'color: #323e42; background-color: #14adc4; font-family: Inconsolata; resize: none; min-height: 300px;'; + setcookie('data-theme-console',$name,time() + (86400 * 5), '/' ); + $this->data['status'] = "success"; + $this->data['success'] = "Тема установлена!"; + break; + } + case 'Smooth': { + $name = 'color: #323e42; background-color: #ff6c9d; font-family: Inconsolata; resize: none; min-height: 300px;'; + setcookie('data-theme-console',$name,time() + (86400 * 5), '/' ); + $this->data['status'] = "success"; + $this->data['success'] = "Тема установлена!"; + break; + } + default: { + $this->data['status'] = "error"; + $this->data['error'] = "Вы выбрали несуществующее действие!"; + break; + } + } + + return json_encode($this->data); + } + + function validate($serverid) { + $result = null; + $this->user->getId( ); + $userid = $this->user->getId(); + + if(!$this->serversModel->getTotalServerOwners(array('server_id' => (int)$serverid, 'user_id' => (int)$userid, 'owner_status' => 1))) { + if(!$this->serversModel->getTotalServers(array('server_id' => (int)$serverid, 'user_id' => (int)$userid))) { + $result = "Запрашиваемый сервер не существует!"; + } + } + return $result; + } + + private function validatePOST() { + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + + $result = null; + return $result; + } +} \ No newline at end of file diff --git a/panel/application/controllers/servers/control.php b/panel/application/controllers/servers/control.php new file mode 100644 index 0000000..38c4007 --- /dev/null +++ b/panel/application/controllers/servers/control.php @@ -0,0 +1,1257 @@ +document->setActiveSection('servers'); + $this->document->setActiveItem('control'); + $this->data['activesection'] = $this->document->getActiveSection(); + $this->data['activeitem'] = $this->document->getActiveItem(); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->library('query'); + $this->load->model('servers'); + + $error = $this->validate($serverid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'servers/index'); + } + + $server = $this->serversModel->getServerById($serverid, array('games', 'locations')); + + if($server['server_status'] == 2) { + $queryLib = new queryLibrary($server['game_query']); + $queryLib->connect($server['location_ip'], $server['server_port']); + $query = $queryLib->getInfo(); + $queryLib->disconnect(); + $this->data['query'] = $query; + } + + $datenow = date_create('now'); + $dateend = date_create($server['server_date_end']); + $diff = date_diff($datenow, $dateend); + + if ($diff->invert) { + $days = 1; + } else { + $days = $diff->days; + } + + if($server['server_status'] == 2 AND $server['game_code'] == "cs" || $server['game_code'] == "css" || $server['game_code'] == "csgo") { + $this->load->library('ssh2'); + + $ssh = new ssh2Library(); + $connect = $ssh->connect($server['location_ip'], $server['location_user'], $pass = $server['location_password']); + $output = $ssh->execute($connect, "cd /home/gs".$server['server_id']."/cstrike/maps/; ls | grep .bsp;"); + $disconnect = $ssh->disconnect($connect); + $data = $output . $disconnect; + $data = explode("\n", $data); + + $maps = ''; + + foreach ($data as $map) { + if (!preg_match('/\.(bsp.ztmp)/', $map)) { + $map = str_replace(".bsp", "", $map); + $maps .= ''; + } + } + $this->data['maps'] = $maps; + } + + if($server['game_code'] == "mcpe" || $server['game_code'] == "mine") { + $cores = @array_reverse(@$this->game_settings->cores[$server['game_code']]); + $this->data["cores"] = $cores; + $no_core = @array_reverse(@$this->game_settings->cores[$server['game_code']]['latest_core']); + $this->data["no_core"] = $no_core; + } + + if($server['game_code'] == "cs") { + $builds = @array_reverse(@$this->game_settings->builds[$server['game_code']]); + $this->data["builds"] = $builds; + $no_build = @array_reverse(@$this->game_settings->builds[$server['game_code']]['latest_build']); + $this->data["no_build"] = $no_build; + } + + if($server['server_status'] == 1 AND $server['game_code'] == "ragemp") { + $node_modules = @array_reverse(@$this->game_settings->node_modules[$server['game_code']]); + $this->data["node_modules"] = $node_modules; + } + + if($server['server_status'] == 1 AND $server['game_code'] == "cs" || $server['game_code'] == "css" || $server['game_code'] == "csgo") { + if($server["game_code"] == "cs") { + $fps = array("300", "500", "1100"); + $this->data["fps"] = $fps; + } + + if($server["game_code"] == "csgo") { + $tickrate = array("64", "128"); + $this->data["tickrate"] = $tickrate; + } + + if($server["game_code"] == "css") { + $tickrate = array("66", "100"); + $this->data["tickrate"] = $tickrate; + } + } + + $this->data['server'] = $server; + $this->data['days'] = $days; + $this->data['portPrice'] = $portPrice = round($this->config->portPrice); + + include_once 'application/controllers/common/main.php'; + + $this->getChild(array('common/header', 'common/footer')); + return $this->load->view('servers/control', $this->data); + } + + public function ajax($serverid = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('waste'); + $this->load->model('users'); + $this->load->model('servers'); + + $server = $this->serversModel->getServerById($serverid, array('games')); + + $error = $this->validate($serverid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + if($server['server_status'] == 3) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет установка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 4) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет переустановка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 5) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет создание BackUP сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 6) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет восстанновление сервера из BackUP!"; + return json_encode($this->data); + } else if($server['server_status'] == 7) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет обновление сервера!"; + return json_encode($this->data); + } else if($server["server_status"] == 0) { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер заблокирован!"; + return json_encode($this->data); + } + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST($serverid); + if(!$errorPOST) { + if($server["server_status"] == 1) { + $slots = $this->request->post['slots']; + $userid = $this->user->getId(); + $balance = $this->user->getBalance(); + $user = $this->usersModel->getUserById($userid, array(), array(), array()); + + $datenow = date_create('now'); + $dateend = date_create($server['server_date_end']); + $diff = date_diff($datenow, $dateend); + + if ($diff->invert) { + $days = 1; + } + else { + $days = $diff->days; + } + $price = $server['game_price'] * ($slots-$server['server_slots']); + + if ($days != NULL) { + $price = ($price / 30) * $days; + } + + if ($server['server_slots'] == $slots) { + $price = '0'; + } + + if (($slots - $server['server_slots']) <= 0) { + $price = '0'; + } + + if($slots < $server['server_slots']) + { + $this->data['status'] = "error"; + $this->data['error'] = "Невозможно установить слоты ниже заданных."; + return json_encode($this->data); + } + if($slots == $server['server_slots']) + { + $this->data['status'] = "success"; + $this->data['success'] = "Слоты не были изменены."; + return json_encode($this->data); + } + if($balance >= $price) { + $this->serversModel->slotsServer($serverid, $slots); + $this->usersModel->downUserBalance($userid, round($price, 2)); + $wasteData = array( + 'user_id' => $userid, + 'waste_ammount' => round($price, 2), + 'waste_status' => 1, + 'waste_usluga' => "Увеличено до $slots слотов для сервера gs$serverid" + ); + $this->wasteModel->createWaste($wasteData); + + if($user['ref'] != 0) { + $ref_percent = $this->config->ref_percent; + $getpref = ($price * (1 + $ref_percent / 100)) - $price; + $this->usersModel->upUserBalance($user['ref'], $getpref); + $this->usersModel->upUserRMoney($user['ref'], $getpref); + + $wasteData = array( + 'user_id' => $user['ref'], + 'waste_ammount' => $getpref, + 'waste_status' => 0, + 'waste_usluga' => "Бонус с реферала ID-$userid" + ); + $this->wasteModel->createWaste($wasteData); + } + + $logData = array( + 'server_id' => $serverid, + 'reason' => 'Увеличено до '.$slots.' слотов.', + 'status' => 1 + ); + $this->serversModel->createLog($logData); + + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно установили $slots слотов! С Вашего счета снято ".(round($price, 2))." руб."; + } else { + $this->data['status'] = "error"; + $logData = array( + 'server_id' => $serverid, + 'reason' => '[SLOTS] Не достаточно средств!', + 'status' => 3 + ); + $this->serversModel->createLog($logData); + $this->data['error'] = "На Вашем счету не хватает ". round($price - $balance, 2) ." руб."; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Сервер должен быть выключен!"; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } + return json_encode($this->data); + } + + public function action($serverid = null, $action = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 0) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('servers'); + $this->load->model('users'); + $this->load->library('ssh2'); + $ssh2Lib = new ssh2Library(); + + $server = $this->serversModel->getServerById($serverid, array('users', 'locations', 'games')); + + $error = $this->validate($serverid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + if($server['server_status'] == 3) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет установка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 4) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет переустановка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 5) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет создание BackUP сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 6) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет восстанновление сервера из BackUP!"; + return json_encode($this->data); + } else if($server['server_status'] == 7) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет обновление сервера!"; + return json_encode($this->data); + } else if($action == "start" || $action == "stop" || $action == "restart" || $action == "reinstall" || $action == "backup" || $action == "unbackup" || $action == "delete_backup") { + if($server["server_status"] == 0) { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер заблокирован!"; + return json_encode($this->data); + } + } + + switch($action) { + case "start": { + if($server["server_status"] == 1) { + $stats = $this->serversModel->getHDD($server['server_id']); + if((int)$stats < $server['game_ssd']) { + $result = $this->serversModel->action($serverid, 'start'); + if($result["status"] == "success") { + $this->serversModel->deleteTask(array('task_name' => 'enable', 'server_id' => $serverid)); + $this->serversModel->updateServer($serverid, array("server_status" => 2)); + $logData = array( + 'server_id' => $serverid, + 'reason' => 'Успешный запуск сервера', + 'status' => 1 + ); + $this->serversModel->createLog($logData); + $this->data["status"] = "success"; + $this->data["success"] = "Вы успешно запустили сервер!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = $result["description"]; + } + } else { + $this->data["status"] = "error"; + $this->data["error"] = "Вы привысили ограничение размера директории на ". round($stats - $server['game_ssd'], 2) ."МБ, запуск сервера невозможен!"; + } + } else { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер должен быть выключен!"; + } + break; + } + + case "reinstall": { + if($server["server_status"] == 1) { + $logData = array( + 'server_id' => $serverid, + 'reason' => 'Сервер успешно поставлен на переустановку!', + 'status' => 2 + ); + $this->serversModel->createLog($logData); + $this->serversModel->updateServer($serverid, array('server_status' => 4, 'server_work' => 1)); + $this->data["status"] = "success"; + $this->data["success"] = "Сервер успешно поставлен на переустановку!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер должен быть выключен!"; + } + break; + } + + case "restart": { + if($server["server_status"] == 2) { + $stats = $this->serversModel->getHDD($server['server_id']); + if((int)$stats < $server['game_ssd']) { + $result = $this->serversModel->action($serverid, 'restart'); + if($result["status"] == "success") { + $this->serversModel->deleteTask(array('task_name' => 'restart', 'server_id' => $serverid)); + $logData = array( + 'server_id' => $serverid, + 'reason' => 'Успешный перезапуск сервера', + 'status' => 1 + ); + $this->serversModel->createLog($logData); + $this->data["status"] = "success"; + $this->data["success"] = "Вы успешно перезапустили сервер!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = $result["description"]; + } + } else { + $result = $this->serversModel->action($serverid, 'stop'); + if($result['status'] == "success") { + $this->serversModel->updateServer($serverid, array('server_status' => 1)); + $this->data["status"] = "error"; + $this->data["error"] = "Вы привысили ограничение размера директории на ". round($stats - $server['game_ssd'], 2) ."МБ, перезагрузка сервера невозможна!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = $result["description"]; + } + } + } else if($server["server_status"] == 2) { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер должен быть включен!"; + } + break; + } + + case "stop": { + if($server["server_status"] == 2) { + $result = $this->serversModel->action($serverid, 'stop'); + if($result["status"] == "success") { + $this->serversModel->deleteTask(array('task_name' => 'disable', 'server_id' => $serverid)); + $this->serversModel->deleteTask(array('task_name' => 'restart', 'server_id' => $serverid)); + $this->serversModel->updateServer($serverid, array("server_status" => 1)); + $logData = array( + 'server_id' => $serverid, + 'reason' => 'Успешное выключение сервера', + 'status' => 1 + ); + $this->serversModel->createLog($logData); + $this->data["status"] = "success"; + $this->data["success"] = "Вы успешно выключили сервер!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = $result["description"]; + } + } else { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер должен быть вылючен!"; + } + break; + } + + case 'backup': { + if($server['server_status'] == 1) { + $stats = $this->serversModel->getHDD($server['server_id']); + if((int)$stats < $server['game_ssd']) { + $this->serversModel->deleteTask(array('task_name' => 'restart', 'server_id' => $serverid)); + $this->serversModel->deleteTask(array('task_name' => 'enable', 'server_id' => $serverid)); + $this->serversModel->deleteTask(array('task_name' => 'disable', 'server_id' => $serverid)); + $this->serversModel->updateServer($serverid, array('server_status' => 5, 'server_work' => 1)); + $logData = array( + 'server_id' => $serverid, + 'reason' => 'Успешное начало создания BackUP сервера.', + 'status' => 1 + ); + $this->serversModel->createLog($logData); + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно начали создание BackUP сервера!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = "Вы привысили ограничение размера директории на ". round($stats - $server['game_ssd'], 2) ."МБ, создание бекапа сервера невозможено!"; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Сервер должен быть выключен!"; + } + break; + } + + case 'unbackup': { + if($server['server_status'] == 1) { + if (file_exists('ssh2.sftp://'.$server['location_user'].':'.$server['location_password'].'@'.$server['location_ip'].':22/home/cp/backups/gs'.$serverid.'.tar')) { + $this->serversModel->deleteTask(array('task_name' => 'restart', 'server_id' => $serverid)); + $this->serversModel->deleteTask(array('task_name' => 'enable', 'server_id' => $serverid)); + $this->serversModel->deleteTask(array('task_name' => 'disable', 'server_id' => $serverid)); + $this->serversModel->updateServer($serverid, array('server_status' => 6, 'server_work' => 1)); + $logData = array( + 'server_id' => $serverid, + 'reason' => 'Успешное начало восстановление BackUP сервера.', + 'status' => 1 + ); + $this->serversModel->createLog($logData); + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно восстановили BackUP сервера!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет BackUP сервера!"; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Сервер должен быть выключен!"; + } + break; + } + + case 'delete_backup': { + if($server['server_status'] == 1) { + if (file_exists('ssh2.sftp://'.$server['location_user'].':'.$server['location_password'].'@'.$server['location_ip'].':22/home/cp/backups/gs'.$serverid.'.tar')) { + $result = $this->serversModel->action($serverid, 'delete_backup'); + if($result["status"] == "success") { + $logData = array( + 'server_id' => $serverid, + 'reason' => 'Успешное удаление BackUP сервера', + 'status' => 1 + ); + $this->serversModel->createLog($logData); + $this->data["status"] = "success"; + $this->data["success"] = "Вы успешно удалили BackUP сервера!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = $result["description"]; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет BackUP сервера!"; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Сервер должен быть выключен!"; + } + break; + } + + case 'promised': { + $this->load->model('users'); + $this->load->model('waste'); + $userid = $this->user->getId(); + $user = $this->usersModel->getUserById($userid, array(), array(), array()); + if($user['user_promised_pay'] == 0){ + $result = $this->serversModel->promisedServer($serverid); + if($result["status"] == "success") { + $this->usersModel->updateUser($userid, array('user_promised_pay' => 1)); + $this->usersModel->downUserBalance($userid, 15); + $wasteData = array( + 'user_id' => $userid, + 'waste_ammount' => 15, + 'waste_status' => 1, + 'waste_usluga' => "Услуга обещанный платеж для сервера gs$serverid" + ); + $this->wasteModel->createWaste($wasteData); + $this->data['status'] = "success"; + $this->data['success'] = "Вы активирали обещаный платёж!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = $result["description"]; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "На данный момент Вам недоступна данная функция!"; + } + break; + } + + default: { + $logData = array( + 'server_id' => $serverid, + 'reason' => 'Вы выбрали несуществующее действие!', + 'status' => 3 + ); + $this->serversModel->createLog($logData); + + $this->data['status'] = "error"; + $this->data['error'] = "Вы выбрали несуществующее действие!"; + break; + } + } + return json_encode($this->data); + } + + + public function ajax_port($serverid = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $userid = $this->user->getId(); + $balance = $this->user->getBalance(); + $portPrice = round($this->config->portPrice); + + $this->load->model('waste'); + $this->load->model('users'); + $this->load->model('servers'); + + $gameServer = $this->serversModel->getServerById($serverid, array('games', 'locations')); + + $error = $this->validate($serverid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + if($gameServer['server_status'] == 3) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет установка сервера!"; + return json_encode($this->data); + } else if($gameServer['server_status'] == 4) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет переустановка сервера!"; + return json_encode($this->data); + } else if($gameServer['server_status'] == 5) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет создание BackUP сервера!"; + return json_encode($this->data); + } else if($gameServer['server_status'] == 6) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет восстанновление сервера из BackUP!"; + return json_encode($this->data); + } else if($gameServer['server_status'] == 7) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет обновление сервера!"; + return json_encode($this->data); + } else if($gameServer["server_status"] == 0) { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер заблокирован!"; + return json_encode($this->data); + } + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $port = @(int)$this->request->post['port']; + if($gameServer['server_status'] == 1){ + if($balance >= $portPrice){ + if(!$this->serversModel->getTotalFirewalls(array('server_id' => $serverid))){ + if(!$this->serversModel->getTotalServers(array('location_id' => $gameServer['location_id'], 'server_port' => $port))){ + $gameServerPorts = $this->serversModel->getGameServerPortList($gameServer['location_id'], $gameServer['game_min_port'], $gameServer['game_max_port']); + if (in_array($port, $gameServerPorts)) { + $this->serversModel->updateServer($serverid, array('server_port' => $port)); + $this->usersModel->downUserBalance($userid, $portPrice); + + $wasteData = array( + 'user_id' => $userid, + 'waste_ammount' => $portPrice, + 'waste_status' => 1, + 'waste_usluga' => "Установлен порт $port для сервера gs$serverid" + ); + $this->wasteModel->createWaste($wasteData); + + $user = $this->usersModel->getUserById($userid, array(), array(), array()); + + if($user['ref'] != 0) { + $ref_percent = $this->config->ref_percent; + $getpref = ($portPrice * (1 + $ref_percent / 100)) - $portPrice; + $this->usersModel->upUserBalance($user['ref'], $getpref); + $this->usersModel->upUserRMoney($user['ref'], $getpref); + + $wasteData = array( + 'user_id' => $user['ref'], + 'waste_ammount' => $getpref, + 'waste_status' => 0, + 'waste_usluga' => "Бонус с реферала ID-$userid" + ); + $this->wasteModel->createWaste($wasteData); + } + + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно сменили порт сервера на ".$port; + } else { + $this->data['status'] = 'error'; + $this->data['error'] = 'Выбранный порт не может быть использован!'; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Выбранный порт уже занят другим сервером!"; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Необходимо удалить все заблокированные IP адреса!"; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "На Вашем счету не хватает ".(round($portPrice-$balance, 2))." руб"; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Сервер должен быть выключен!"; + } + } + return json_encode($this->data); + } + + public function changemap_go($serverid = null) { + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'news/index'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('servers'); + + $server = $this->serversModel->getServerById($serverid, array('games', 'locations')); + + $error = $this->validate($serverid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + if($server['server_status'] == 3) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет установка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 4) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет переустановка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 5) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет создание BackUP сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 6) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет восстанновление сервера из BackUP!"; + return json_encode($this->data); + } else if($server['server_status'] == 7) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет обновление сервера!"; + return json_encode($this->data); + } else if($server["server_status"] == 0) { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер заблокирован!"; + return json_encode($this->data); + } + + if($server['server_status'] == 2){ + $command = str_replace("'", "'", "changelevel ".$_POST['map'].""); + $this->serversModel->action($serverid, 'sendcommand', array('command' => $command)); + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно сменили карту на ".$_POST['map']."!"; + }else{ + $this->data['status'] = "error"; + $this->data['error'] = "Сервер должен быть включен!"; + } + return json_encode($this->data); + } + + public function changecore($serverid = null) { + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'news/index'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('servers'); + + $server = $this->serversModel->getServerById($serverid, array('games', 'locations')); + + $error = $this->validate($serverid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + if($server['server_status'] == 3) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет установка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 4) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет переустановка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 5) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет создание BackUP сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 6) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет восстанновление сервера из BackUP!"; + return json_encode($this->data); + } else if($server['server_status'] == 7) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет обновление сервера!"; + return json_encode($this->data); + } else if($server["server_status"] == 0) { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер заблокирован!"; + return json_encode($this->data); + } + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + if($server['server_status'] == 1){ + if($server["game_code"] == "mine" || $server["game_code"] == "mcpe") { + $core = @$this->request->post['core']; + $coreInfo = $this->game_settings->cores[$server['game_code']][$core]; + if(is_array($coreInfo)) { + $result = $this->serversModel->action($serverid, 'sendcommand', array('command' => 'unsetFiles')); + if($result['status'] == "success") { + $this->serversModel->deleteTask(array('task_name' => 'restart', 'server_id' => $serverid)); + $this->serversModel->deleteTask(array('task_name' => 'enable', 'server_id' => $serverid)); + $this->serversModel->deleteTask(array('task_name' => 'disable', 'server_id' => $serverid)); + $this->serversModel->updateServer($serverid, array('server_status' => 7, 'server_work' => 1, 'server_binary' => $core, 'server_binary_version' => $this->game_settings->cores[$server['game_code']][$core]['corebinary'])); + $this->data["status"] = "success"; + $this->data["success"] = "Вы успешно начали смену ядра!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = $result["description"]; + } + } else { + $this->data["status"] = "error"; + $this->data["error"] = "Вы указали неверное ядро!"; + } + } else { + $this->data["status"] = "error"; + $this->data["error"] = "Не для Вашей игры!"; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Сервер должен быть выключен!"; + } + } + return json_encode($this->data); + } + + public function changebuild($serverid = null) { + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'news/index'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('servers'); + + $server = $this->serversModel->getServerById($serverid, array('games', 'locations')); + + $error = $this->validate($serverid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + if($server['server_status'] == 3) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет установка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 4) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет переустановка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 5) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет создание BackUP сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 6) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет восстанновление сервера из BackUP!"; + return json_encode($this->data); + } else if($server['server_status'] == 7) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет обновление сервера!"; + return json_encode($this->data); + } else if($server["server_status"] == 0) { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер заблокирован!"; + return json_encode($this->data); + } + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + if($server['server_status'] == 1){ + if($server["game_code"] == "cs") { + $build = @$this->request->post['build']; + $buildInfo = $this->game_settings->builds[$server['game_code']][$build]; + if(is_array($buildInfo)) { + $result = $this->serversModel->action($serverid, 'sendcommand', array('command' => 'unsetFiles')); + if($result['status'] == "success") { + $this->serversModel->deleteTask(array('task_name' => 'restart', 'server_id' => $serverid)); + $this->serversModel->deleteTask(array('task_name' => 'enable', 'server_id' => $serverid)); + $this->serversModel->deleteTask(array('task_name' => 'disable', 'server_id' => $serverid)); + $this->serversModel->updateServer($serverid, array('server_status' => 7, 'server_work' => 1, 'server_binary' => $build)); + $this->data["status"] = "success"; + $this->data["success"] = "Вы успешно начали смену билда!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = $result["description"]; + } + } else { + $this->data["status"] = "error"; + $this->data["error"] = "Вы указали неверный билд!"; + } + } else { + $this->data["status"] = "error"; + $this->data["error"] = "Не для Вашей игры!"; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Сервер должен быть выключен!"; + } + } + return json_encode($this->data); + } + + public function loadModuleJS($serverid = null) { + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'news/index'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('servers'); + + $server = $this->serversModel->getServerById($serverid, array('games', 'locations')); + + $error = $this->validate($serverid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + if($server['server_status'] == 3) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет установка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 4) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет переустановка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 5) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет создание BackUP сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 6) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет восстанновление сервера из BackUP!"; + return json_encode($this->data); + } else if($server['server_status'] == 7) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет обновление сервера!"; + return json_encode($this->data); + } else if($server["server_status"] == 0) { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер заблокирован!"; + return json_encode($this->data); + } + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + if($server['server_status'] == 1){ + if($server["game_code"] == "ragemp") { + $stats = $this->serversModel->getHDD($server['server_id']); + if((int)$stats < $server['game_ssd']) { + $module = @$this->request->post['module']; + $moduleInfo = $this->game_settings->node_modules[$server['game_code']][$module]; + if(is_array($moduleInfo)) { + $result = $this->serversModel->action($serverid, 'sendcommand', array('command' => 'loadModuleJS', 'module' => $module)); + if($result['status'] == "success") { + $this->data["status"] = "success"; + $this->data["success"] = "Вы успешно загрузили на сервер модуль ".$this->game_settings->node_modules[$server['game_code']][$module]['module_name']."!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = $result["description"]; + } + } else { + $this->data["status"] = "error"; + $this->data["error"] = "Вы указали неверный модуль!"; + } + } else { + $this->data["status"] = "error"; + $this->data["error"] = "Вы привысили ограничение размера директории на ". round($stats - $server['game_ssd'], 2) ."МБ, загрузка модулей невозможна!"; + } + } else { + $this->data["status"] = "error"; + $this->data["error"] = "Не для Вашей игры!"; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Сервер должен быть выключен!"; + } + } + return json_encode($this->data); + } + + public function settingStart($serverid = null) { + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'news/index'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('servers'); + + $server = $this->serversModel->getServerById($serverid, array('games', 'locations')); + + $error = $this->validate($serverid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + if($server['server_status'] == 3) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет установка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 4) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет переустановка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 5) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет создание BackUP сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 6) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет восстанновление сервера из BackUP!"; + return json_encode($this->data); + } else if($server['server_status'] == 7) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет обновление сервера!"; + return json_encode($this->data); + } else if($server["server_status"] == 0) { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер заблокирован!"; + return json_encode($this->data); + } + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + if($server['server_status'] == 1){ + if($server["game_code"] == "cs" || $server["game_code"] == "css" || $server["game_code"] == "csgo" || $server["game_query"] == "samp") { + $rcon_password = @$this->request->post['rcon_password']; + if(mb_strlen($rcon_password) < 2 || mb_strlen($rcon_password) > 18) { + $this->data["status"] = "error"; + $this->data["error"] = "RCON Пароль должен содержать от 2 до 18 символов!"; + return json_encode($this->data); + } + $this->serversModel->updateServer($serverid, array('rcon_password' => $rcon_password)); + + if($server["game_code"] == "cs" || $server["game_code"] == "css" || $server["game_code"] == "csgo") { + $vac = @$this->request->post['vac']; + if(!in_array($vac, array("0", "1"))) { + $this->data["status"] = "error"; + $this->data["error"] = "Статус античита VAC указан неверно!"; + return json_encode($this->data); + } + $this->serversModel->updateServer($serverid, array('server_vac' => $vac)); + + $fastdl = @$this->request->post['fastdl']; + if(!in_array($fastdl, array("0", "1"))) { + $this->data["status"] = "error"; + $this->data["error"] = "Статус FastDL указан неверно!"; + return json_encode($this->data); + } + $this->serversModel->updateServer($serverid, array('fastdl_status' => $fastdl)); + + if($server["game_code"] == "cs") { + $fps = @$this->request->post['fps']; + if(!in_array($fps, array("300", "500", "1100"))) { + $this->data["status"] = "error"; + $this->data["error"] = "Параметр FPS указан неверно!"; + return json_encode($this->data); + } else { + $this->serversModel->updateServer($serverid, array('server_fps' => $fps)); + } + } + + if($server["game_code"] == "csgo") { + $tickrate = @$this->request->post['tickrate']; + if(!in_array($tickrate, array("64", "128"))) { + $this->data["status"] = "error"; + $this->data["error"] = "Параметр Tickrate указан неверно!"; + return json_encode($this->data); + } else { + $this->serversModel->updateServer($serverid, array('server_tickrate' => $tickrate)); + } + } + + if($server["game_code"] == "css") { + $tickrate = @$this->request->post['tickrate']; + if(!in_array($tickrate, array("66", "100"))) { + $this->data["status"] = "error"; + $this->data["error"] = "Параметр Tickrate указан неверно!"; + return json_encode($this->data); + } else { + $this->serversModel->updateServer($serverid, array('server_tickrate' => $tickrate)); + } + } + } + + $this->data["status"] = "success"; + $this->data["success"] = "Параметры запуска успешно изменены!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = "Не для Вашей игры!"; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Сервер должен быть выключен!"; + } + } + return json_encode($this->data); + } + + public function buy_months($serverid = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('waste'); + $this->load->model('users'); + $this->load->model('servers'); + + $error = $this->validate($serverid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $days = @$this->request->post['days']; + if($days != "30" && $days != "60" && $days != "90" && $days != "180" && $days != "360" && $days != "15") { + $this->data['status'] = "error"; + $this->data['error'] = "Вы указали недопустимый период оплаты!"; + return json_encode($this->data); + } + + $userid = $this->user->getId(); + $balance = $this->user->getBalance(); + + $server = $this->serversModel->getServerById($serverid, array('games')); + + $price = $server['server_slots'] * $server['game_price']; + switch($days) { + case "15": + $price = $price / 2; + break; + case "30": + break; + case "60": + $price = $price * 2; + break; + case "90": + $price = 3 * $price * 0.95; + break; + case "180": + $price = 6 * $price * 0.90; + break; + case "360": + $price = 12 * $price * 0.85; + break; + } + if($balance >= $price) { + if($server['server_status'] == 0) { + $this->serversModel->updateServer($serverid, array('server_status' => 1)); + $this->serversModel->extendServer($serverid,$days,true); + $this->serversModel->action($serverid, "updatepassm"); + $this->serversModel->action($serverid, "updatepass"); + } else { + $this->serversModel->extendServer($serverid,$days,false); + } + $this->usersModel->downUserBalance($userid, $price); + $wasteData = array( + 'user_id' => $userid, + 'waste_ammount' => $price, + 'waste_status' => 1, + 'waste_usluga' => "Продление сервера gs$serverid на $days дней" + ); + $this->wasteModel->createWaste($wasteData); + + $user = $this->usersModel->getUserById($userid, array(), array(), array()); + + if($user['ref'] != 0) { + $ref_percent = $this->config->ref_percent; + $getpref = ($price * (1 + $ref_percent / 100)) - $price; + $this->usersModel->upUserBalance($user['ref'], $getpref); + $this->usersModel->upUserRMoney($user['ref'], $getpref); + + $wasteData = array( + 'user_id' => $user['ref'], + 'waste_ammount' => $getpref, + 'waste_status' => 0, + 'waste_usluga' => "Бонус с реферала ID-$userid" + ); + $this->wasteModel->createWaste($wasteData); + } + + $logData = array( + 'server_id' => $serverid, + 'reason' => 'Сервер успешно продлен!', + 'status' => 1 + ); + $this->serversModel->createLog($logData); + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно оплатили сервер на $days дней. С Вашего счета снято ".(round($price, 2))." руб"; + } else { + $logData = array( + 'server_id' => $serverid, + 'reason' => '[PAY] На счету не достаточно средств для продления сервера!', + 'status' => 3 + ); + $this->serversModel->createLog($logData); + $this->data['status'] = "error"; + $this->data['error'] = "На Вашем счету не хватает ".(round($price-$balance, 2))." руб"; + } + } + return json_encode($this->data); + } + + private function validate($serverid) { + $result = null; + + $userid = $this->user->getId(); + + if(!$this->serversModel->getTotalServerOwners(array('server_id' => (int)$serverid, 'user_id' => (int)$userid, 'owner_status' => 1))) { + if(!$this->serversModel->getTotalServers(array('server_id' => (int)$serverid, 'user_id' => (int)$userid))) { + $result = "Запрашиваемый сервер не существует!"; + } + } + return $result; + } + + private function validatePOST($serverid) + { + $this->load->library('validate'); + $this->load->model('games'); + $validateLib = new validateLibrary(); + $result = NULL; + $server = $this->serversModel->getServerById($serverid, array('games', 'locations')); + $gameid = $server['game_id']; + $slots = $this->request->post['slots']; + + if (!$this->gamesModel->validateSlots($gameid, $slots)) { + $result = 'Вы указали недопустимое количество слотов!'; + } + elseif(!$validateLib->money($slots)) { + $result = "Укажите количество слотов в допустимом формате!"; + } + return $result; + } +} +?> diff --git a/panel/application/controllers/servers/firewall.php b/panel/application/controllers/servers/firewall.php new file mode 100644 index 0000000..e00498c --- /dev/null +++ b/panel/application/controllers/servers/firewall.php @@ -0,0 +1,233 @@ +document->setActiveSection('servers'); + $this->document->setActiveItem('firewall'); + $this->data['activesection'] = $this->document->getActiveSection(); + $this->data['activeitem'] = $this->document->getActiveItem(); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('servers'); + + $error = $this->validate($serverid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'servers/index'); + } + + $this->data['server'] = $this->serversModel->getServerById($serverid, array('games', 'locations')); + $this->data['Firewalls'] = $this->serversModel->getFirewallsById($serverid); + + include_once 'application/controllers/common/main.php'; + + $this->getChild(array('common/header', 'common/footer')); + return $this->load->view('servers/firewall', $this->data); + } + + public function ajax($serverid = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('servers'); + + $server = $this->serversModel->getServerById($serverid); + + $error = $this->validate($serverid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + if($server['server_status'] == 3) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет установка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 4) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет переустановка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 5) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет создание BackUP сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 6) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет восстанновление сервера из BackUP!"; + return json_encode($this->data); + } else if($server['server_status'] == 7) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет обновление сервера!"; + return json_encode($this->data); + } else if($server["server_status"] == 0) { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер заблокирован!"; + return json_encode($this->data); + } + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $ipmask = @$this->request->post['address']; + + if (!$ipmask) { + $this->data['status'] = 'error'; + $this->data['error'] = 'Вы не ввели IP'; + return json_encode($this->data); + } + + $ip = explode('/', $ipmask)[0]; + $net = explode('/', $ipmask)[1]; + + if (($ipmask !== str_replace('/', '', $ipmask)) && !$net) { + $this->data['status'] = 'error'; + $this->data['error'] = 'Не введены данные после "/"'; + return json_encode($this->data); + } + + if (!filter_var($ip, FILTER_VALIDATE_IP)) { + $this->data['status'] = 'error'; + $this->data['error'] = 'Введен неверный IP'; + return json_encode($this->data); + } + if ($net) { + if (is_numeric($net)) { + if (2 < mb_strlen($net)) { + $this->data['status'] = 'error'; + $this->data['error'] = 'Не больше двух цифр после "/"'; + return json_encode($this->data); + + if (!filter_var($net, FILTER_VALIDATE_IP)) { + $this->data['status'] = 'error'; + $this->data['error'] = 'Введены неверные данные после "/"'; + return json_encode($this->data); + } + } + } + else { + $this->data['status'] = 'error'; + $this->data['error'] = 'Введены неверные данные после "/"'; + return json_encode($this->data); + } + } + + if ($this->serversModel->getTotalFirewalls(array('server_ip' => $ipmask, 'server_id' => $serverid))) { + $this->data['status'] = 'error'; + $this->data['error'] = 'Данное правило уже добавлено!'; + return json_encode($this->data); + } + + $firewallData = array( + 'server_id' => $serverid, + 'server_ip' => $ipmask + ); + $firewallid = $this->serversModel->createFirewall($firewallData); + + $this->serversModel->addFirewall($firewallid); + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно заблокировали ".$ipmask."!"; + return json_encode($this->data); + } + } + + public function action($action = null, $serverid = null, $firewallid = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('servers'); + + $server = $this->serversModel->getServerById($serverid); + + $error = $this->validate($serverid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + if($server['server_status'] == 3) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет установка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 4) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет переустановка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 5) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет создание BackUP сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 6) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет восстанновление сервера из BackUP!"; + return json_encode($this->data); + } else if($server['server_status'] == 7) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет обновление сервера!"; + return json_encode($this->data); + } else if($server["server_status"] == 0) { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер заблокирован!"; + return json_encode($this->data); + } + + switch($action) { + case 'delete': { + $this->serversModel->deleteFirewall($firewallid); + + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно разблокировали IP!"; + break; + } + default: { + $this->data['status'] = "error"; + $this->data['error'] = "Вы выбрали несуществующее действие!"; + break; + } + } + + return json_encode($this->data); + } + + private function validate($serverid) { + $result = null; + $userid = $this->user->getId(); + + if(!$this->serversModel->getTotalServerOwners(array('server_id' => (int)$serverid, 'user_id' => (int)$userid, 'owner_status' => 1))) { + if(!$this->serversModel->getTotalServers(array('server_id' => (int)$serverid, 'user_id' => (int)$userid))) { + $result = "Запрашиваемый сервер не существует!"; + } + } + + return $result; + } + +} \ No newline at end of file diff --git a/panel/application/controllers/servers/ftp.php b/panel/application/controllers/servers/ftp.php new file mode 100644 index 0000000..ef4dd41 --- /dev/null +++ b/panel/application/controllers/servers/ftp.php @@ -0,0 +1,344 @@ +document->setActiveSection('servers'); + $this->document->setActiveItem('ftp'); + $this->data['activesection'] = $this->document->getActiveSection(); + $this->data['activeitem'] = $this->document->getActiveItem(); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('servers'); + + $error = $this->validate($serverid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'servers/index'); + } + + $server = $this->serversModel->getServerById($serverid, array('games', 'locations')); + $this->data['server'] = $server; + + if(isset($_COOKIE["data-theme-ftp"])){ + $this->data['theme'] = $_COOKIE['data-theme-ftp']; + } else{ + $this->data['theme'] = "/application/public/css/elfinderT/default/css/theme.css"; + } + + include_once 'application/controllers/common/main.php'; + + $this->getChild(array('common/header', 'common/footer')); + return $this->load->view('servers/ftp', $this->data); + } + + public function ajax($serverid = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + $this->load->model('servers'); + $server = $this->serversModel->getServerById($serverid, array('games', 'locations')); + + $error = $this->validate($serverid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + if($server['server_status'] == 3) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет установка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 4) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет переустановка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 5) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет создание BackUP сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 6) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет восстанновление сервера из BackUP!"; + return json_encode($this->data); + } else if($server['server_status'] == 7) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет обновление сервера!"; + return json_encode($this->data); + } else if($server["server_status"] == 0) { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер заблокирован!"; + return json_encode($this->data); + } + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $editpassword = @$this->request->post['editpassword']; + $password = @$this->request->post['password']; + if($editpassword) { + $this->serversModel->updateServer($serverid, array('server_password' => $password)); + $result = $this->serversModel->action($serverid, "updatepass"); + if($result["status"] == "success") { + $this->data['status'] = "success"; + $this->data['success'] = "Пароль FTP успешно изменен!!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = $result["description"]; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Ошибка!"; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } + return json_encode($this->data); + } + + public function action_theme_ftp($action = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('servers'); + + switch($action) { + case 'default': { + $name = '/application/public/css/elfinderT/default/css/theme.css'; + setcookie('data-theme-ftp',$name,time() + (86400 * 5), '/' ); + $this->data['status'] = "success"; + $this->data['success'] = "Тема Default успешно установлена!"; + break; + } + case 'material': { + $name = '/application/public/css/elfinderT/Material/css/theme.css'; + setcookie('data-theme-ftp',$name,time() + (86400 * 5), '/' ); + $this->data['status'] = "success"; + $this->data['success'] = "Тема Material успешно установлена!"; + break; + } + case 'materialgray': { + $name = '/application/public/css/elfinderT/Material/css/theme-gray.css'; + setcookie('data-theme-ftp',$name,time() + (86400 * 5), '/' ); + $this->data['status'] = "success"; + $this->data['success'] = "Тема Material gray успешно установлена!"; + break; + } + case 'materiallight': { + $name = '/application/public/css/elfinderT/Material/css/theme-light.css'; + setcookie('data-theme-ftp',$name,time() + (86400 * 5), '/' ); + $this->data['status'] = "success"; + $this->data['success'] = "Тема Material light успешно установлена!"; + break; + } + default: { + $this->data['status'] = "error"; + $this->data['error'] = "Вы выбрали несуществующее действие!"; + break; + } + } + + return json_encode($this->data); + } + + private function validate($serverid) { + $result = null; + + $userid = $this->user->getId(); + + if(!$this->serversModel->getTotalServerOwners(array('server_id' => (int)$serverid, 'user_id' => (int)$userid, 'owner_status' => 1))) { + if(!$this->serversModel->getTotalServers(array('server_id' => (int)$serverid, 'user_id' => (int)$userid))) { + $result = "Запрашиваемый сервер не существует!"; + } + } + return $result; + } + + public function getftp($serverid = null) { + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('servers'); + + $error = $this->validate($serverid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'servers/index'); + } + + $server = $this->serversModel->getServerById($serverid, array('games', 'locations')); + + if($server['server_status'] == 3) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет установка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 4) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет переустановка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 5) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет создание BackUP сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 6) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет восстанновление сервера из BackUP!"; + return json_encode($this->data); + } else if($server['server_status'] == 7) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет обновление сервера!"; + return json_encode($this->data); + } else if($server["server_status"] == 0) { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер заблокирован!"; + return json_encode($this->data); + } + + include_once ENGINE_DIR . 'engine_ftp/elFinderConnector.class.php'; + include_once ENGINE_DIR . 'engine_ftp/elFinder.class.php'; + include_once ENGINE_DIR . 'engine_ftp/elFinderVolumeDriver.class.php'; + include_once ENGINE_DIR . 'engine_ftp/elFinderVolumeLocalFileSystem.class.php'; + include_once ENGINE_DIR . 'engine_ftp/elFinderVolumeFTP.class.php'; + + function access($attr, $path, $data, $volume) { + return strpos(basename($path), '.') === 0 + ? !($attr == 'read' || $attr == 'write') + : null; + } + + function logger($cmd, $result, $args, $elfinder) { + $log = sprintf('[%s] %s:', date('r'), strtoupper($cmd)); + foreach ($result as $key => $value) { + if (empty($value)) { + continue; + } + $data = array(); + if (in_array($key, array('error', 'warning'))) { + array_push($data, implode(' ', $value)); + } else { + if (is_array($value)) { + foreach ($value as $file) { + $filepath = (isset($file['realpath']) ? $file['realpath'] : $elfinder->realpath($file['hash'])); + array_push($data, $filepath); + } + } else { + array_push($data, $value); + } + } + $log .= sprintf(' %s(%s)', $key, implode(', ', $data)); + } + $log .= "\n"; + + $logfile = 'files/log.txt'; + $dir = dirname($logfile); + if (!is_dir($dir) && !mkdir($dir)) { + return; + } + if (($fp = fopen($logfile, 'a'))) { + fwrite($fp, $log); + fclose($fp); + } + } + + $opts = array( + 'roots' => array( + array( + 'driver' => 'FTP', + 'URL' => 'ftp://gs'.$server['server_id'].':'.$server['server_password'].'@'.$server['location_ip'].':21/', + 'host' => $server['location_ip'], + 'user' => 'gs'.$server['server_id'], + 'pass' => $server['server_password'], + 'port' => 21, + 'mode' => 'passive', + 'path' => '/', + 'read' => true, + 'write' => true, + 'utf8fix' => true, + 'bind' => array( + 'mkdir mkfile rename duplicate upload rm paste' => 'logger' + ), + 'rootAlias'=>'Server Root', + 'fileURL'=>True, + 'dotFiles'=>True, + 'dirSize'=>True, + 'fileMode'=>0644, + 'dirMode'=>0775, + 'imgLib'=>False, + 'tmbDir'=>'.tmb', + 'tmbAtOnce'=>5, + 'debug'=>True + ), + 'attributes' => array( + array( + 'pattern' => '~/\.~', + 'read' => true, + 'write' => true, + 'hidden' => true + ), + + ) + ) + ); + $connector = new elFinderConnector(new elFinder($opts)); + $connector->run(); + } + + private function validatePOST() { + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + + $result = null; + + $editpassword = @$this->request->post['editpassword']; + $password = @$this->request->post['password']; + $password2 = @$this->request->post['password2']; + if($editpassword) { + if(!$validateLib->password($password)) { + $result = "Пароль должен содержать от 6 до 32 латинских букв, цифр и знаков ,.!?_-!"; + } + elseif($password != $password2) { + $result = "Введенные вами пароли не совпадают!"; + } + } + return $result; + } + +} +?> diff --git a/panel/application/controllers/servers/index.php b/panel/application/controllers/servers/index.php new file mode 100644 index 0000000..5459d9c --- /dev/null +++ b/panel/application/controllers/servers/index.php @@ -0,0 +1,208 @@ +document->setActiveSection('servers'); + $this->document->setActiveItem('index'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->library('pagination'); + $this->load->model('servers'); + + $userid = $this->user->getId(); + + $options = array( + 'start' => ($page - 1) * $this->limit, + 'limit' => $this->limit + ); + + $this->data['servers'] = $this->serversModel->getServers(array('user_id' => (int)$userid), array('games', 'locations'), array(), $options); + $this->data['serversOwners'] = $this->serversModel->getOwners(array('servers_owners.user_id' => $userid), array('servers', 'games', 'locations')); + + $paginationLib = new paginationLibrary(); + + $paginationLib->total = $this->serversModel->getTotalServers(array('user_id' => (int)$userid)); + $paginationLib->page = $page; + $paginationLib->limit = $this->limit; + $paginationLib->url = $this->config->url . 'servers/index/index/{page}'; + + $this->data['pagination'] = $paginationLib->render(); + + $this->getChild(array('common/header', 'common/footer')); + return $this->load->view('servers/index', $this->data); + } + + public function action($serverid = null, $action = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('servers'); + + $error = $this->validate($serverid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + $server = $this->serversModel->getServerById($serverid, array('users', 'locations', 'games')); + + if($server['server_status'] == 3) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет установка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 4) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет переустановка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 5) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет создание BackUP сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 6) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет восстанновление сервера из BackUP!"; + return json_encode($this->data); + } else if($server['server_status'] == 7) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет обновление сервера!"; + return json_encode($this->data); + } else if($server["server_status"] == 0) { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер заблокирован!"; + return json_encode($this->data); + } + + switch($action) { + case "start": { + if($server["server_status"] == 1) { + $stats = $this->serversModel->getHDD($server['server_id']); + if((int)$stats < $server['game_ssd']) { + $result = $this->serversModel->action($serverid, 'start'); + if($result["status"] == "success") { + $this->serversModel->deleteTask(array('task_name' => 'enable', 'server_id' => $serverid)); + $this->serversModel->updateServer($serverid, array("server_status" => 2)); + $logData = array( + 'server_id' => $serverid, + 'reason' => 'Успешный запуск сервера', + 'status' => 1 + ); + $this->serversModel->createLog($logData); + $this->data["status"] = "success"; + $this->data["success"] = "Вы успешно запустили сервер!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = $result["description"]; + } + } else { + $this->data["status"] = "error"; + $this->data["error"] = "Вы привысили ограничение размера директории на ". round($stats - $server['game_ssd'], 2) ."МБ, запуск сервера невозможен!"; + } + } else { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер должен быть выключен!"; + } + break; + } + + case "restart": { + if($server["server_status"] == 2) { + $stats = $this->serversModel->getHDD($server['server_id']); + if((int)$stats < $server['game_ssd']) { + $result = $this->serversModel->action($serverid, 'restart'); + if($result["status"] == "success") { + $this->serversModel->deleteTask(array('task_name' => 'restart', 'server_id' => $serverid)); + $logData = array( + 'server_id' => $serverid, + 'reason' => 'Успешный перезапуск сервера', + 'status' => 1 + ); + $this->serversModel->createLog($logData); + $this->data["status"] = "success"; + $this->data["success"] = "Вы успешно перезапустили сервер!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = $result["description"]; + } + } else { + $result = $this->serversModel->action($serverid, 'stop'); + if($result['status'] == "success") { + $this->serversModel->updateServer($serverid, array('server_status' => 1)); + $this->data["status"] = "error"; + $this->data["error"] = "Вы привысили ограничение размера директории на ". round($stats - $server['game_ssd'], 2) ."МБ, перезагрузка сервера невозможна!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = $result["description"]; + } + } + } else if($server["server_status"] == 2) { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер должен быть включен!"; + } + break; + } + + case "stop": { + if($server["server_status"] == 2) { + $result = $this->serversModel->action($serverid, 'stop'); + if($result["status"] == "success") { + $this->serversModel->deleteTask(array('task_name' => 'disable', 'server_id' => $serverid)); + $this->serversModel->deleteTask(array('task_name' => 'restart', 'server_id' => $serverid)); + $this->serversModel->updateServer($serverid, array("server_status" => 1)); + $logData = array( + 'server_id' => $serverid, + 'reason' => 'Успешное выключение сервера', + 'status' => 1 + ); + $this->serversModel->createLog($logData); + $this->data["status"] = "success"; + $this->data["success"] = "Вы успешно выключили сервер!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = $result["description"]; + } + } else { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер должен быть вылючен!"; + } + break; + } + } + + return json_encode($this->data); + } + + private function validate($serverid) { + $result = null; + + $userid = $this->user->getId(); + + if(!$this->serversModel->getTotalServerOwners(array('server_id' => (int)$serverid, 'user_id' => (int)$userid, 'owner_status' => 1))) { + if(!$this->serversModel->getTotalServers(array('server_id' => (int)$serverid, 'user_id' => (int)$userid))) { + $result = "Запрашиваемый сервер не существует!"; + } + } + return $result; + } +} +?> diff --git a/panel/application/controllers/servers/mysql.php b/panel/application/controllers/servers/mysql.php new file mode 100644 index 0000000..615eceb --- /dev/null +++ b/panel/application/controllers/servers/mysql.php @@ -0,0 +1,246 @@ +document->setActiveSection('servers'); + $this->document->setActiveItem('mysql'); + $this->data['activesection'] = $this->document->getActiveSection(); + $this->data['activeitem'] = $this->document->getActiveItem(); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('servers'); + + $error = $this->validate($serverid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'servers/index'); + } + + $server = $this->serversModel->getServerById($serverid, array('games', 'locations')); + $this->data['server'] = $server; + + include_once 'application/controllers/common/main.php'; + + $this->getChild(array('common/header', 'common/footer')); + return $this->load->view('servers/mysql', $this->data); + } + + public function action($serverid = null, $action = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + + if($this->user->getAccessLevel() < 0) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('servers'); + + $error = $this->validate($serverid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'servers/index'); + } + + $server = $this->serversModel->getServerById($serverid); + + if($server['server_status'] == 3) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет установка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 4) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет переустановка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 5) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет создание BackUP сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 6) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет восстанновление сервера из BackUP!"; + return json_encode($this->data); + } else if($server['server_status'] == 7) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет обновление сервера!"; + return json_encode($this->data); + } else if($server["server_status"] == 0) { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер заблокирован!"; + return json_encode($this->data); + } + + switch($action) { + case 'mysqlon': { + if($server['server_mysql'] == 2) { + $this->serversModel->updateServer($serverid, array('server_mysql' => 1)); + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно включили базу данных gs$serverid!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = "База данных и так включена либо вы ее еще не создали!"; + } + break; + } + case 'mysqloff': { + if($server['server_mysql'] == 1) { + $this->serversModel->updateServer($serverid, array('server_mysql' => 2)); + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно выключили базу данных gs$serverid!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = "База данных и так выключена!"; + } + break; + } + case 'mysqlcr': { + if($server['server_mysql'] == 0) { + $result = $this->serversModel->action($serverid, 'create_mysql'); + if($result["status"] == "success") { + $this->serversModel->updateServer($serverid, array('server_mysql' => 2)); + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно создали базу данных gs$serverid!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = $result["description"]; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "База данных и так создана!"; + } + break; + } + default: { + $this->data['status'] = "error"; + $this->data['error'] = "Вы выбрали несуществующее действие!"; + break; + } + } + return json_encode($this->data); + } + + + private function validate($serverid) { + $result = null; + + $userid = $this->user->getId(); + + if(!$this->serversModel->getTotalServerOwners(array('server_id' => (int)$serverid, 'user_id' => (int)$userid, 'owner_status' => 1))) { + if(!$this->serversModel->getTotalServers(array('server_id' => (int)$serverid, 'user_id' => (int)$userid))) { + $result = "Запрашиваемый сервер не существует!"; + } + } + return $result; + } + + public function ajax($serverid = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + $this->load->model('servers'); + $server = $this->serversModel->getServerById($serverid, array('games', 'locations')); + + $error = $this->validate($serverid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + if($server['server_status'] == 3) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет установка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 4) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет переустановка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 5) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет создание BackUP сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 6) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет восстанновление сервера из BackUP!"; + return json_encode($this->data); + } else if($server['server_status'] == 7) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет обновление сервера!"; + return json_encode($this->data); + } else if($server["server_status"] == 0) { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер заблокирован!"; + return json_encode($this->data); + } + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $editpassword = @$this->request->post['editpassword']; + $password = @$this->request->post['password']; + if($editpassword) { + $this->serversModel->updateServer($serverid, array('db_pass' => $password)); + $result = $this->serversModel->action($serverid, "updatepassm"); + if($result["status"] == "success") { + $this->data['status'] = "success"; + $this->data['success'] = "Пароль MySql успешно изменен!!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = $result["description"]; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Ошибка!"; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } + return json_encode($this->data); + } + + private function validatePOST() { + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + + $result = null; + + $editpassword = @$this->request->post['editpassword']; + $password = @$this->request->post['password']; + $password2 = @$this->request->post['password2']; + if($editpassword) { + if(!$validateLib->password($password)) { + $result = "Пароль должен содержать от 6 до 32 латинских букв, цифр и знаков ,.!?_-!"; + } + elseif($password != $password2) { + $result = "Введенные вами пароли не совпадают!"; + } + } + return $result; + } +} +?> diff --git a/panel/application/controllers/servers/order.php b/panel/application/controllers/servers/order.php new file mode 100644 index 0000000..dc708ee --- /dev/null +++ b/panel/application/controllers/servers/order.php @@ -0,0 +1,281 @@ +data['serv_test'] = $this->config->serv_test; + $this->document->setActiveSection('servers'); + $this->document->setActiveItem('order'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('games'); + $this->load->model('locations'); + + $games = $this->gamesModel->getGames(array('game_status' => 1)); + $locations = $this->locationsModel->getLocations(array('location_status' => 1)); + + $this->data['games'] = $games; + $this->data['locations'] = $locations; + + $this->getChild(array('common/header', 'common/footer')); + return $this->load->view('servers/order', $this->data); + } + + public function promo() { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('users'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $code = $this->request->post['code']; + $skidka = $this->usersModel->getSkidkaByCode($code, false); + $kofficent=(100-$skidka['skidka'])/100; + if($skidka['skidka'] == NULL){ + $this->data['status'] = "error"; + $this->data['error'] = "Данного кода не существует"; + }else{ + $this->data['status'] = "success"; + $this->data['success'] = "Вы активировали скидку ".$skidka['skidka']."%"; + $this->data['skidka'] = $kofficent; + } + } + + return json_encode($this->data); + } + + public function ajax() { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('waste'); + $this->load->model('users'); + $this->load->model('games'); + $this->load->model('locations'); + $this->load->model('servers'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $gameid = $this->request->post['gameid']; + $locationid = $this->request->post['locationid']; + $slots = $this->request->post['slots']; + $days = $this->request->post['days']; + $password = $this->request->post['password']; + + $location = $this->locationsModel->getLocationById($locationid); + $location_games = explode(" ", $location['location_games']); + + if(!in_array($gameid, $location_games)) { + $this->data['status'] = "error"; + $this->data['error'] = "Данная игра не доступна для указанной локации!"; + return json_encode($this->data); + } + + + $userid = $this->user->getId(); + $balance = $this->user->getBalance(); + $firstname = $this->user->getFirstname(); + $lastname = $this->user->getLastname(); + $email = $this->user->getEmail(); + $test_server = $this->user->getTest_server(); + + $game = $this->gamesModel->getGameById($gameid); + $port = $this->serversModel->getServerNewPort($locationid, $game['game_min_port'], $game['game_max_port']); + $user = $this->usersModel->getUserById($userid, array(), array(), array()); + $code = $this->request->post['promo']; + $skidka = $this->usersModel->getSkidkaByCode($code,true);$kofficent=(100-$skidka['skidka'])/100; + if($port) { + $price = $slots * $game['game_price']; + + switch($days) { + case "0": + $test_periud = true; + break; + case "15": + $price = $price / 2; + $test_periud = false; + break; + case "30": + $test_periud = false; + break; + case "60": + $price = $price * 2; + $test_periud = false; + break; + case "90": + $price = 3 * $price * 0.95; + $test_periud = false; + break; + case "180": + $price = 6 * $price * 0.90; + $test_periud = false; + break; + case "360": + $price = 12 * $price * 0.85; + $test_periud = false; + break; + } + + if($skidka['skidka'] != NULL){ + $price = $price * $kofficent; + } + if($test_periud == true){ + if($this->config->serv_test == 1) { + if($test_server == 1){ + $serverData = array( + 'user_id' => $userid, + 'game_id' => $gameid, + 'location_id' => $locationid, + 'server_mysql' => 0, + 'server_slots' => $slots, + 'server_port' => $port, + 'server_password' => $password, + 'server_status' => 3, + 'test_periud' => $test_periud, + 'server_days' => $days + ); + + $serverid = $this->serversModel->createServer($serverData); + $this->usersModel->downUserBalance($userid, $price); + $wasteData = array( + 'user_id' => $userid, + 'waste_ammount' => $price, + 'waste_status' => 1, + 'waste_usluga' => "Заказ тестового сервера gs$serverid" + ); + $this->wasteModel->createWaste($wasteData); + + $this->data['status'] = "success"; + $this->data['success'] = "Сервер успешно поставлен в очередь на установку."; + $this->data['id'] = $serverid; + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Вы уже брали тестовый период, либо у вас нет одобрения администратора!"; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Тестовый период отключен на хостинге!"; + } + }elseif($balance >= $price AND $test_periud == false) { + $serverData = array( + 'user_id' => $userid, + 'game_id' => $gameid, + 'location_id' => $locationid, + 'server_mysql' => 0, + 'server_slots' => $slots, + 'server_port' => $port, + 'server_password' => $password, + 'server_status' => 3, + 'test_periud' => $test_periud, + 'server_days' => $days + ); + + $serverid = $this->serversModel->createServer($serverData); + $this->usersModel->downUserBalance($userid, $price); + $wasteData = array( + 'user_id' => $userid, + 'waste_ammount' => $price, + 'waste_status' => 1, + 'waste_usluga' => "Заказ сервера gs$serverid" + ); + $this->wasteModel->createWaste($wasteData); + + if($user['ref'] != 0) { + $ref_percent = $this->config->ref_percent; + $getpref = ($price * (1 + $ref_percent / 100)) - $price; + $this->usersModel->upUserBalance($user['ref'], $getpref); + $this->usersModel->upUserRMoney($user['ref'], $getpref); + + $wasteData = array( + 'user_id' => $user['ref'], + 'waste_ammount' => $getpref, + 'waste_status' => 0, + 'waste_usluga' => "Бонус с реферала ID-$userid" + ); + $this->wasteModel->createWaste($wasteData); + } + + $this->data['status'] = "success"; + $this->data['success'] = "Сервер успешно поставлен в очередь на установку."; + $this->data['id'] = $serverid; + } else { + $this->data['status'] = "error"; + $this->data['error'] = "На Вашем счету недостаточно средств"; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "На выбранной Вами локации нет свободных портов для данной игры"; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } + + return json_encode($this->data); + } + + private function validatePOST() { + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + + $result = null; + + $gameid = @$this->request->post['gameid']; + $locationid = @$this->request->post['locationid']; + $slots = @$this->request->post['slots']; + $days = @$this->request->post['days']; + $password = @$this->request->post['password']; + $password2 = @$this->request->post['password2']; + + if(!$this->gamesModel->getTotalGames(array('game_id' => (int)$gameid, 'game_status' => 1))) { + $result = "Вы указали несуществующую игру!"; + } + elseif(!$this->locationsModel->getTotalLocations(array('location_id' => (int)$locationid, 'location_status' => 1))) { + $result = "Вы указали несуществующую локацию!"; + } + elseif($days != "30" && $days != "60" && $days != "90" && $days != "180" && $days != "360" && $days != "15" && $days != "0") { + $result = "Вы указали недопустимый период оплаты!"; + } + elseif(!$this->gamesModel->validateSlots($gameid, $slots)) { + $result = "Вы указали недопустимое количество слотов!"; + } + elseif(!$validateLib->password($password)) { + $result = "Пароль должен содержать от 6 до 32 латинских букв, цифр и знаков ,.!?_-!"; + } + elseif($password != $password2) { + $result = "Введенные вами пароли не совпадают!"; + } + return $result; + } +} +?> diff --git a/panel/application/controllers/servers/owner.php b/panel/application/controllers/servers/owner.php new file mode 100644 index 0000000..e40b8e2 --- /dev/null +++ b/panel/application/controllers/servers/owner.php @@ -0,0 +1,210 @@ +document->setActiveSection('servers'); + $this->document->setActiveItem('owner'); + $this->data['activesection'] = $this->document->getActiveSection(); + $this->data['activeitem'] = $this->document->getActiveItem(); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('servers'); + + $error = $this->validate($serverid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'servers/index'); + } + + $this->data['server'] = $this->serversModel->getServerById($serverid, array('games', 'locations')); + $this->data['serversOwners'] = $this->serversModel->getOwners(array('server_id' => $serverid), array('users')); + + include_once 'application/controllers/common/main.php'; + + $this->getChild(array('common/header', 'common/footer')); + return $this->load->view('servers/owner', $this->data); + } + + public function create($serverid = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('users'); + $this->load->model('servers'); + + $server = $this->serversModel->getServerById($serverid); + + $error = $this->validate($serverid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + if($server['server_status'] == 3) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет установка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 4) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет переустановка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 5) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет создание BackUP сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 6) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет восстанновление сервера из BackUP!"; + return json_encode($this->data); + } else if($server['server_status'] == 7) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет обновление сервера!"; + return json_encode($this->data); + } else if($server["server_status"] == 0) { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер заблокирован!"; + return json_encode($this->data); + } + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + if(!$this->validatePOST($serverid)) { + $ownerid = @$this->request->post['ownerid']; + + $ownerData = array( + 'server_id' => $serverid, + 'user_id' => $ownerid, + 'owner_status' => 1 + ); + $this->serversModel->createOwner($ownerData); + + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно добавили друга!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = $this->validatePOST($serverid); + } + } + + return json_encode($this->data); + } + + + public function delete($serverid = null, $ownerid = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('users'); + $this->load->model('servers'); + + $server = $this->serversModel->getServerById($serverid); + + $error = $this->validate($serverid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + if($server['server_status'] == 3) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет установка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 4) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет переустановка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 5) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет создание BackUP сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 6) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет восстанновление сервера из BackUP!"; + return json_encode($this->data); + } else if($server['server_status'] == 7) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет обновление сервера!"; + return json_encode($this->data); + } else if($server["server_status"] == 0) { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер заблокирован!"; + return json_encode($this->data); + } + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + if($this->serversModel->getTotalServerOwners(array('server_id' => $serverid, 'owner_id' => $ownerid))) { + $this->serversModel->deleteOwner($ownerid); + + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно удалили друга!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Ошибка!"; + } + } + + return json_encode($this->data); + } + + private function validate($serverid) { + $result = null; + $userid = $this->user->getId(); + + if (!$this->serversModel->getTotalServers( array( 'server_id' => (int)$serverid, 'user_id' => (int)$userid ) )) { + $result = 'Вы не являетесь владельцем сервера. У вас нет доступа к разделу!'; + } + + return $result; + } + + private function validatePOST($serverid) { + $result = null; + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + $ownerid = @$this->request->post['ownerid']; + $userid = $this->user->getId(); + + if(!$validateLib->money($ownerid)) { + $result = "Вы указали недоступный ID пользователя!"; + }elseif(!$this->usersModel->getTotalUsers(array('user_id' => $ownerid))) { + $result = "Запрашиваемый пользователь не существует!"; + }elseif($this->serversModel->getTotalServerOwners(array('server_id' => $serverid, 'user_id' => $ownerid))) { + $result = "Запрашиваемый пользователь уже добавлен!"; + }elseif($userid == $ownerid) { + $result = "Запрашиваемый пользователь является владельцем сервера!"; + } + return $result; + } +} \ No newline at end of file diff --git a/panel/application/controllers/servers/repo.php b/panel/application/controllers/servers/repo.php new file mode 100644 index 0000000..0560cc6 --- /dev/null +++ b/panel/application/controllers/servers/repo.php @@ -0,0 +1,183 @@ +document->setActiveSection('servers'); + $this->document->setActiveItem('repo'); + $this->data['activesection'] = $this->document->getActiveSection(); + $this->data['activeitem'] = $this->document->getActiveItem(); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('servers'); + $this->load->model('users'); + + $error = $this->validate($serverid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'servers/index'); + } + + $userid = $this->user->getId(); + + $server = $this->serversModel->getServerById($serverid, array('games', 'locations')); + $this->data['server'] = $server; + + $repos = $this->serversModel->getRepos(array('repo_status' => 1),array('games'),array(), array()); + $this->data['userrepos'] = $this->usersModel->getUserRepos($userid); + $this->data['repos'] = $repos; + + include_once 'application/controllers/common/main.php'; + + $this->getChild(array('common/header', 'common/footer')); + return $this->load->view('servers/repo', $this->data); + } + + public function action($serverid = null, $action = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 0) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + $userid = $this->user->getId(); + $this->load->model('servers'); + $this->load->model('users'); + $this->load->model('waste'); + + $error = $this->validate($serverid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + $error = $this->validateRepo($action); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + $balance = $this->user->getBalance(); + $server = $this->serversModel->getServerById($serverid, array('users', 'locations', 'games')); + + if($server['server_status'] == 3) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет установка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 4) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет переустановка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 5) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет создание BackUP сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 6) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет восстанновление сервера из BackUP!"; + return json_encode($this->data); + } else if($server['server_status'] == 7) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет обновление сервера!"; + return json_encode($this->data); + } else if($server["server_status"] == 0) { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер заблокирован!"; + return json_encode($this->data); + } + + $repo = $this->serversModel->getRepoById($action); + + if($repo["repo_status"] != 1) { + $this->data["status"] = "error"; + $this->data["error"] = "Данный файл не доступен!"; + return json_encode($this->data); + } + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $price = $repo['repo_price']; + if($balance < $price){ + $this->data['status'] = "error"; + $this->data['error'] = "Недостаточно средств"; + return json_encode($this->data); + } + $userid = $this->user->getId(); + $wasteData = array( + 'user_id' => $userid, + 'waste_ammount' => $price, + 'waste_status' => 1, + 'waste_usluga' => "Покупка файла ".$repo['repo_id']."" + ); + $this->wasteModel->createWaste($wasteData); + $this->usersModel->downUserBalance($userid, $price); + $freeData = array( + 'user_id' => $userid, + 'repo_id' => "".$repo['repo_id']."" + ); + $this->usersModel->addRepos($freeData); + + $user = $this->usersModel->getUserById($userid, array(), array(), array()); + + if($user['ref'] != 0) { + $ref_percent = $this->config->ref_percent; + $getpref = ($price * (1 + $ref_percent / 100)) - $price; + $this->usersModel->upUserBalance($user['ref'], $getpref); + $this->usersModel->upUserRMoney($user['ref'], $getpref); + + $wasteData = array( + 'user_id' => $user['ref'], + 'waste_ammount' => $getpref, + 'waste_status' => 0, + 'waste_usluga' => "Бонус с реферала ID-$userid" + ); + $this->wasteModel->createWaste($wasteData); + } + + $this->data['status'] = "success"; + $this->data['success'] = "Файл ".$repo['repo_name']." успешно был приобретен, с вашего счёта снято ".$repo['repo_price']." р!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Не POST запрос!"; + } + return json_encode($this->data); + } + + private function validate($serverid) { + $result = null; + + $userid = $this->user->getId(); + + if(!$this->serversModel->getTotalServerOwners(array('server_id' => (int)$serverid, 'user_id' => (int)$userid, 'owner_status' => 1))) { + if(!$this->serversModel->getTotalServers(array('server_id' => (int)$serverid, 'user_id' => (int)$userid))) { + $result = "Запрашиваемый сервер не существует!"; + } + } + return $result; + } + + private function validateRepo($repoid) { + $result = null; + + if(!$this->serversModel->getRepoById(array('repo_id' => (int)$repoid))) { + $result = "Запрашиваемый файл не существует!"; + } + return $result; + } +} +?> \ No newline at end of file diff --git a/panel/application/controllers/servers/statistics.php b/panel/application/controllers/servers/statistics.php new file mode 100644 index 0000000..bb77eea --- /dev/null +++ b/panel/application/controllers/servers/statistics.php @@ -0,0 +1,109 @@ +document->setActiveSection('servers'); + $this->document->setActiveItem('statistic'); + $this->data['activesection'] = $this->document->getActiveSection(); + $this->data['activeitem'] = $this->document->getActiveItem(); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('servers'); + + $error = $this->validate($serverid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'servers/index'); + } + + $server = $this->serversModel->getServerById($serverid, array('games', 'locations')); + $logs = $this->serversModel->getLogs(array(), array('servers'), array(), array()); + $stats = $this->serversModel->getServerStats($serverid, "NOW() - INTERVAL 31 DAY", "NOW()"); + + $this->data['server'] = $server; + $this->data['logs'] = $logs; + $this->data['stats'] = $stats; + + include_once 'application/controllers/common/main.php'; + + $this->getChild(array('common/header', 'common/footer')); + return $this->load->view('servers/statistics', $this->data); + } + + public function getData($serverid = null) { + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('servers'); + $this->load->library('query'); + + $error = $this->validate($serverid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'servers/index'); + } + + $server = $this->serversModel->getServerById($serverid, array('games', 'locations')); + + if($server['server_status'] == 2) { + $queryLib = new queryLibrary($server['game_query']); + $queryLib->connect($server['location_ip'], $server['server_port']); + $query = $queryLib->getInfo(); + $queryLib->disconnect(); + + $sysload = $this->serversModel->getServerSystemLoad($serverid); + $ssd = round($sysload['ssd']); + $ssd_all = $server['game_ssd']; + $this->data['ssd'] = (int)(($ssd * 100) / $ssd_all); + $this->data['cpu'] = $sysload['cpu'] > 100 ? 100 : round($sysload['cpu']); + $this->data['ram'] = $sysload['ram'] > 100 ? 100 : round($sysload['ram']); + $this->data['players'] = $query['players']; + } else if($server['server_status'] == 3 || $server['server_status'] == 4) { + $this->data['ssd'] = 'N/A'; + $this->data['cpu'] = 'N/A'; + $this->data['ram'] = 'N/A'; + $this->data['players'] = 'N/A'; + } else { + $ssd = $this->serversModel->getHDD($serverid); + $ssd = round($ssd); + $ssd_all = $server['game_ssd']; + $this->data['ssd'] = (int)(($ssd * 100) / $ssd_all); + $this->data['cpu'] = 0; + $this->data['ram'] = 0; + $this->data['players'] = 0; + } + + return json_encode($this->data); + } + + private function validate($serverid) { + $result = null; + + $userid = $this->user->getId(); + + if(!$this->serversModel->getTotalServerOwners(array('server_id' => (int)$serverid, 'user_id' => (int)$userid, 'owner_status' => 1))) { + if(!$this->serversModel->getTotalServers(array('server_id' => (int)$serverid, 'user_id' => (int)$userid))) { + $result = "Запрашиваемый сервер не существует!"; + } + } + return $result; + } +} +?> diff --git a/panel/application/controllers/servers/tasks.php b/panel/application/controllers/servers/tasks.php new file mode 100644 index 0000000..9225bae --- /dev/null +++ b/panel/application/controllers/servers/tasks.php @@ -0,0 +1,216 @@ +document->setActiveSection('servers'); + $this->document->setActiveItem('tasks'); + $this->data['activesection'] = $this->document->getActiveSection(); + $this->data['activeitem'] = $this->document->getActiveItem(); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('servers'); + + $error = $this->validate($serverid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'servers/index'); + } + + $server = $this->serversModel->getServerById($serverid, array('games', 'locations')); + $this->data['server'] = $server; + + $tasks = $this->serversModel->getTasks(array("server_id" => $serverid, "isSystemTask" => 0), array(), array("task_id" => "DESC")); + $this->data["tasks"] = $tasks; + + include_once 'application/controllers/common/main.php'; + + $this->getChild(array('common/header', 'common/footer')); + return $this->load->view('servers/tasks', $this->data); + } + + public function createTask($serverid = null) { + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'news/index'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('servers'); + + $server = $this->serversModel->getServerById($serverid, array('games', 'locations')); + + $error = $this->validate($serverid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + if($server['server_status'] == 3) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет установка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 4) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет переустановка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 5) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет создание BackUP сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 6) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет восстанновление сервера из BackUP!"; + return json_encode($this->data); + } else if($server['server_status'] == 7) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет обновление сервера!"; + return json_encode($this->data); + } else if($server["server_status"] == 0) { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер заблокирован!"; + return json_encode($this->data); + } + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $tasks = $this->serversModel->getTasks(array("server_id" => $serverid)); + if(count($tasks) < 4) { + $task = @$this->request->post['task']; + $type = @$this->request->post['type']; + $time = @$this->request->post['time']; + if(!in_array($task, array("enable", "disable", "restart"))) { + $this->data["status"] = "error"; + $this->data["error"] = "Вы указали несуществующую задачу!"; + } else if(($task == 'enable' && $server['server_status'] != 1) || ($task == 'diable' && $server['server_status'] != 2) || ($task == 'restart' && $server['server_status'] != 2)) { + $this->data["status"] = "error"; + $this->data["error"] = "Вы не можете создать данную задачу!"; + } else if(!empty($this->serversModel->getTasks(array("server_id" => $serverid, "task_name" => $task)))) { + $this->data["status"] = "error"; + $this->data["error"] = "Данная задача уже создана!"; + } else if(!in_array($type, array('repeating', 'single'))) { + $this->data["status"] = "error"; + $this->data["error"] = "Вы указали несуществующий тип задачи!"; + } else if($task == 'repeating' && ($task == 'enable' || $task == 'diable')) { + $this->data["status"] = "error"; + $this->data["error"] = "Данный тип задачи недоступен для задачи!"; + } else if(!in_array($time, array("15min", "30min", "1hour", "12hours", "24hours"))) { + $this->data["status"] = "error"; + $this->data["error"] = "Вы указали недопустимое время выполнения!"; + } else { + if($time == '15min') { + $lead_time = "NOW() + INTERVAL 15 MINUTE"; + } else if($time == '30min') { + $lead_time = "NOW() + INTERVAL 30 MINUTE"; + } else if($time == '1hour') { + $lead_time = "NOW() + INTERVAL 1 HOUR"; + } else if($time == '12hours') { + $lead_time = "NOW() + INTERVAL 12 HOUR"; + } else if($time == '24hours') { + $lead_time = "NOW() + INTERVAL 24 HOUR"; + } + $task = $this->serversModel->getTaskById($this->serversModel->createTask(array("server_id" => $serverid, "task_name" => $task, "task_type" => $type, "task_time" => $time, "task_lead_time" => $lead_time))); + + $this->data['task'] = array("task_id" => $task['task_id'], "task_name" => $task['task_name'], "task_type" => $task['task_type'], "task_time" => $task['task_time'], "task_lead_time" => date("d.m.Y в H:i", strtotime($task['task_lead_time']))); + + $this->data["status"] = "success"; + $this->data["success"] = "Задача успешно создана!"; + } + } else { + $this->data["status"] = "error"; + $this->data["error"] = "Вы не можете создавать больше 4-х задач!"; + } + } + return json_encode($this->data); + } + + public function deleteTask($serverid = null) { + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'news/index'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('servers'); + + $server = $this->serversModel->getServerById($serverid, array('games', 'locations')); + + $error = $this->validate($serverid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + if($server['server_status'] == 3) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет установка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 4) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет переустановка сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 5) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет создание BackUP сервера!"; + return json_encode($this->data); + } else if($server['server_status'] == 6) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет восстанновление сервера из BackUP!"; + return json_encode($this->data); + } else if($server['server_status'] == 7) { + $this->data["status"] = "error"; + $this->data["error"] = "Идет обновление сервера!"; + return json_encode($this->data); + } else if($server["server_status"] == 0) { + $this->data["status"] = "error"; + $this->data["error"] = "Сервер заблокирован!"; + return json_encode($this->data); + } + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $task_id = @$this->request->post['task_id']; + $task = $this->serversModel->getTaskById($serverid); + if($task['server_id'] == $server_id) { + $this->serversModel->deleteTask(array('task_id' => $task_id)); + $this->data["status"] = "success"; + $this->data["success"] = "Задача успешно удалена!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = "Задача не найдена!"; + } + } + return json_encode($this->data); + } + + + private function validate($serverid) { + $result = null; + + $userid = $this->user->getId(); + + if(!$this->serversModel->getTotalServerOwners(array('server_id' => (int)$serverid, 'user_id' => (int)$userid, 'owner_status' => 1))) { + if(!$this->serversModel->getTotalServers(array('server_id' => (int)$serverid, 'user_id' => (int)$userid))) { + $result = "Запрашиваемый сервер не существует!"; + } + } + return $result; + } +} +?> diff --git a/panel/application/controllers/status/index.php b/panel/application/controllers/status/index.php new file mode 100644 index 0000000..8ec4fc0 --- /dev/null +++ b/panel/application/controllers/status/index.php @@ -0,0 +1,76 @@ +document->setActiveSection('status'); + $this->document->setActiveItem('index'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('servers'); + $this->load->model('tickets'); + $this->load->model('users'); + $this->load->model('invoices'); + $this->load->model('games'); + $this->load->model('locations'); + $this->load->model('promos'); + $this->load->model('news'); + $userid = $this->user->getId(); + $ticketsSort = array( + 'ticket_status' => 'DESC', + 'ticket_date_add' => 'DESC' + ); + $getData = array(); + if(isset($this->request->get['gameid'])) { + $getData['servers.game_id'] = (int)$this->request->get['gameid']; + } + + if(isset($this->request->get['locationid'])) { + $getData['servers.location_id'] = (int)$this->request->get['locationid']; + } + + $options = array( + 'start' => 0, + 'limit' => 100000 + ); + $getOptions = array( + 'start' => 0, + 'limit' => 100000 + ); + + $total = $this->ticketsModel->getTotalTickets($getData); + $tickets = $this->ticketsModel->getTickets($getData, array('users'), array(), $getOptions); + $servers = $this->serversModel->getServers(array('user_id' => (int)$userid), array('games', 'locations'), array(), $options); + $total = $this->serversModel->getTotalServers($getData); + $tservers = $this->serversModel->getServers($getData, array('games', 'locations'), array(), $getOptions); + $total = $this->invoicesModel->getTotalInvoices($getData); + $invoices = $this->invoicesModel->getInvoices($getData, array('users'), array(), $options); + $users = $this->usersModel->getUsers(array(), array(), $options); + $games = $this->gamesModel->getGames(array(), array(), $options); + $locations = $this->locationsModel->getLocations(array('location_status' => 1), array(), $options); + $promos = $this->promosModel->getpromo(array(), array(), $options); + $news = $this->newsModel->getNews(array(), array(), array(),$options); + $this->data['games'] = $games; + $this->data['users'] = $users; + $this->data['tservers'] = $tservers; + $this->data['tickets'] = $tickets; + $this->data['servers'] = $servers; + $this->data['invoices'] = $invoices; + $this->data['locations'] = $locations; + $this->data['promos'] = $promos; + $this->data['news'] = $news; + $this->getChild(array('common/header', 'common/footer')); + return $this->load->view('status/index', $this->data); + } +} +?> \ No newline at end of file diff --git a/panel/application/controllers/tickets/create.php b/panel/application/controllers/tickets/create.php new file mode 100644 index 0000000..8379cc9 --- /dev/null +++ b/panel/application/controllers/tickets/create.php @@ -0,0 +1,131 @@ +document->setActiveSection('tickets'); + $this->document->setActiveItem('create'); + $this->data['url'] = $this->config->url; + $this->data['recaptcha'] = $this->config->recaptcha; + $this->data['captcha_enable'] = $this->config->captcha_enable; + + if($this->user->isLogged()) { + $this->data['logged'] = true; + $this->data['user_email'] = $this->user->getEmail(); + $this->data['user_firstname'] = $this->user->getFirstname(); + $this->data['user_lastname'] = $this->user->getLastname(); + $this->data['user_balance'] = $this->user->getBalance(); + $this->data['user_access_level'] = $this->user->getAccessLevel(); + $this->data['user_img'] = $this->user->getUser_img(); + } else { + $this->data['logged'] = false; + $this->data['user_access_level'] = 0; + } + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + $this->load->model('ticketsCategory'); + $this->load->model('users'); + $category = @$this->request->post['category']; + $category = $this->ticketsCategoryModel->getTicketsCategory(array('category_status' => 1)); + $userid = $this->user->getId(); + + $this->data['category'] = $category; + $this->getChild(array('common/header', 'common/footer')); + return $this->load->view('tickets/create', $this->data); + } + + public function ajax($ticketid = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('tickets'); + $this->load->model('ticketsMessages'); + $this->load->model('ticketsCategory'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $name = @$this->request->post['name']; + $text = @$this->request->post['text']; + $category = @$this->request->post['category']; + $userid = $this->user->getId(); + $ticketData = array( + 'user_id' => $userid, + 'ticket_name' => $name, + 'ticket_status' => 1, + 'category_id' => $category + ); + $ticketid = $this->ticketsModel->createTicket($ticketData); + $messageData = array( + 'ticket_id' => $ticketid, + 'user_id' => $userid, + 'ticket_message' => $text + ); + $this->ticketsMessagesModel->createTicketMessage($messageData); + + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно создали запрос!"; + $this->data['id'] = $ticketid; + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } + + return json_encode($this->data); + } + + private function validatePOST() { + $result = null; + + $name = @$this->request->post['name']; + $text = @$this->request->post['text']; + $recaptcha = @$this->request->post['g-recaptcha-response']; + $this->load->model('tickets'); + $userid = $this->user->getId(); + + if(mb_strlen($name) < 6 || mb_strlen($name) > 32) { + $result = "Название тикета должно содержать от 6 до 32 символов!"; + } + elseif(mb_strlen($text) < 10 || mb_strlen($text) > 10000) { + $result = "Текст тикета должен содержать от 10 до 350 символов!"; + } + elseif (3 <= $this->ticketsModel->dateCreateInfo($userid)) { + $result = 'Нельзя создать тикет, так как за сегодня вы создали больше 3 тикетов.'; + } + if($this->config->captcha_enable != '1') return $result; + if(!$recaptcha) return 'Подтвердите, что вы не робот!'; + $url = 'https://www.google.com/recaptcha/api/siteverify'; + $data = array('secret' => $this->config->secret_recaptcha, 'response' => $recaptcha); + $options = array( + 'http' => array( + 'header' => "Content-type: application/x-www-form-urlencoded\r\n", + 'method' => 'POST', + 'remoteip' => 'remoteip', + 'content' => http_build_query($data), + ) + ); + + $context = stream_context_create($options); + $recaptcha_get = json_decode(file_get_contents($url, false, $context))->{'success'}; + if($recaptcha_get != '1') return 'Проверьте правильность капчи!'; + return $result; + } +} diff --git a/panel/application/controllers/tickets/faq.php b/panel/application/controllers/tickets/faq.php new file mode 100644 index 0000000..fed0579 --- /dev/null +++ b/panel/application/controllers/tickets/faq.php @@ -0,0 +1,38 @@ +document->setActiveSection('tickets'); + $this->document->setActiveItem('faq'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + + $this->data['user_img'] = $this->user->getUser_img(); + $this->data['url'] = $this->config->url; + + $userid = $this->user->getId(); + + $this->data['logged'] = true; + $this->data['user_email'] = $this->user->getEmail(); + $this->data['user_id'] = $userid; + $this->data['user_firstname'] = $this->user->getFirstname(); + $this->data['user_lastname'] = $this->user->getLastname(); + $this->data['user_balance'] = $this->user->getBalance(); + $this->data['user_access_level'] = $this->user->getAccessLevel(); + + $this->getChild(array('common/header', 'common/footer')); + return $this->load->view('tickets/faq', $this->data); + } +} +?> \ No newline at end of file diff --git a/panel/application/controllers/tickets/index.php b/panel/application/controllers/tickets/index.php new file mode 100644 index 0000000..213cb08 --- /dev/null +++ b/panel/application/controllers/tickets/index.php @@ -0,0 +1,70 @@ +document->setActiveSection('tickets'); + $this->document->setActiveItem('index'); + $this->data['url'] = $this->config->url; + + if($this->user->isLogged()) { + $this->data['logged'] = true; + $this->data['user_email'] = $this->user->getEmail(); + $this->data['user_firstname'] = $this->user->getFirstname(); + $this->data['user_lastname'] = $this->user->getLastname(); + $this->data['user_balance'] = $this->user->getBalance(); + $this->data['user_access_level'] = $this->user->getAccessLevel(); + $this->data['user_img'] = $this->user->getUser_img(); + } else { + $this->data['logged'] = false; + $this->data['user_access_level'] = 0; + } + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->library('pagination'); + $this->load->model('tickets'); + $this->load->model('ticketsCategory'); + $this->load->model('users'); + + $userid = $this->user->getId(); + $sort = array( + 'ticket_status' => 'DESC', + 'ticket_date_add' => 'DESC' + ); + $options = array( + 'start' => ($page - 1) * $this->limit, + 'limit' => $this->limit + ); + + $total = $this->ticketsModel->getTotalTickets(array('user_id' => (int)$userid)); + $tickets = $this->ticketsModel->getTickets(array('user_id' => (int)$userid), array('tickets_category'), $sort, $options); + + $paginationLib = new paginationLibrary(); + + $paginationLib->total = $total; + $paginationLib->page = $page; + $paginationLib->limit = $this->limit; + $paginationLib->url = $this->config->url . 'tickets/index/index/{page}'; + $pagination = $paginationLib->render(); + $this->data['tickets'] = $tickets; + $this->data['pagination'] = $pagination; + $this->data['user_firstname'] = $this->user->getFirstname(); + $this->data['user_lastname'] = $this->user->getLastname(); + $this->data['user_access_level'] = $this->user->getAccessLevel(); + $this->data['user_img'] = $this->user->getUser_img(); + $this->getChild(array('common/header', 'common/footer')); + return $this->load->view('tickets/index', $this->data); + } +} +?> \ No newline at end of file diff --git a/panel/application/controllers/tickets/view.php b/panel/application/controllers/tickets/view.php new file mode 100644 index 0000000..fd158d0 --- /dev/null +++ b/panel/application/controllers/tickets/view.php @@ -0,0 +1,297 @@ +document->setActiveSection('tickets'); + $this->document->setActiveItem('index'); + $this->data['url'] = $this->config->url; + + if($this->user->isLogged()) { + $this->data['logged'] = true; + $this->data['user_email'] = $this->user->getEmail(); + $this->data['user_firstname'] = $this->user->getFirstname(); + $this->data['user_lastname'] = $this->user->getLastname(); + $this->data['user_balance'] = $this->user->getBalance(); + $this->data['user_access_level'] = $this->user->getAccessLevel(); + $this->data['user_img'] = $this->user->getUser_img(); + } else { + $this->data['logged'] = false; + $this->data['user_access_level'] = 0; + } + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('tickets'); + $this->load->model('users'); + + $error = $this->validate($ticketid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'tickets/index'); + } + + $ticket = $this->ticketsModel->getTicketById($ticketid, array('users')); + $this->data['ticket'] = $ticket; + $this->data['user_img'] = $this->user->getUser_img(); + + $LastTime = time() - 105; + $online_sup = 0; + foreach($this->usersModel->getUsers() as $line) { + if($line['user_access_level'] > 1) { + if ($line['user_online_date'] > $LastTime) { + $online_sup++; + } + } + } + if($online_sup > 0) { + $this->data['sup_status'] = ' В сети'; + } else { + $this->data['sup_status'] = ' Не в сети'; + } + + $this->getChild(array('common/header', 'common/footer')); + return $this->load->view('tickets/view', $this->data); + } + + public function action($ticketid = null, $action = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 0) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + $this->load->model('tickets'); + switch($action) { + case 'closed': { + $this->ticketsModel->updateTicket($ticketid, array('ticket_status' => 0)); + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно закрыли запрос!"; + break; + } + default: { + $this->data['status'] = "error"; + $this->data['error'] = "Вы выбрали несуществующее действие!"; + break; + } + } + return json_encode($this->data); + } + + public function ajax($ticketid = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('tickets'); + $this->load->model('ticketsMessages'); + + $error = $this->validate($ticketid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST($ticketid); + if(!$errorPOST) { + $userid = $this->user->getId(); + $text = @$this->request->post['text']; + $ticket = $this->ticketsModel->getTicketById($ticketid, array('users')); + if($ticket['ticket_status'] != 0) { + $messageData = array( + 'ticket_id' => $ticketid, + 'user_id' => $userid, + 'ticket_message' => $text + ); + $this->ticketsModel->updateTicket($ticketid, array('ticket_status' => 1)); + $this->ticketsMessagesModel->createTicketMessage($messageData); + + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно отправили сообщение!"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Данный запрос закрыт, оставить новое сообщение невозможно!"; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } + return json_encode($this->data); + } + + public function uploadFile($ticketid = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('tickets'); + $this->load->model('ticketsMessages'); + $this->load->model('users'); + + $error = $this->validate($ticketid); + if ($error) { + $this->session->data['error'] = $error; + } + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $uploaddir = "tmp/tickets_img/"; + $apend=date('YmdHis').rand(100,1000).'.jpg'; + $uploadfile = "$uploaddir$apend"; + + if(move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) { + if($_FILES['userfile']['type'] == 'image/gif' || $_FILES['userfile']['type'] == 'image/jpeg' || $_FILES['userfile']['type'] == 'image/png') { + if($_FILES['userfile']['size'] != 0 and $_FILES['userfile']['size'] <= 5120000) { + $size = getimagesize($uploadfile); + if ($size[0] < 2560 && $size[1] < 1440) { + if(round(($_FILES['userfile']['size'] / 1024), 2) > 1500.00) { + $message = 'Изображение: ' . $apend . '
Размер: ' . round(($_FILES['userfile']['size'] / 1024), 2) . 'КБ
Открыть'; + } else { + $message = ''; + } + $userid = $this->user->getId(); + $messageData = array( + 'ticket_id' => $ticketid, + 'user_id' => $userid, + 'ticket_message' => $message + ); + $this->ticketsModel->updateTicket($ticketid, array('ticket_status' => 1)); + $this->ticketsMessagesModel->createTicketMessage($messageData); + $this->data['status'] = 'success'; + $this->data['success'] = 'Изображение загружено!'; + } else { + $this->data['error'] = 'Загружаемое изображение превышает допустимые нормы!'; + $this->data['status'] = "error"; + unlink($uploadfile); + } + } else { + $this->data['error'] = 'Размер изображения не должено превышать 5120Кб'; + $this->data['status'] = "error"; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Можно загружать только изображения в форматах jpg, jpeg и png"; + } + } else { + $this->data['error'] = 'Изображение не загружено!'; + $this->data['status'] = "error"; + } + } + return json_encode($this->data); + } + + public function getMessagess() { + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $this->load->model('tickets'); + $this->load->model('ticketsMessages'); + + $id = $this->request->post['tid']; + + $error = $this->validate($id); + if($error) { + $this->session->data['error'] = $error; + } + + $url = $this->config->url; + $messages = $this->ticketsMessagesModel->getTicketsMessages(array('ticket_id' => $id), array('users')); + + foreach($messages as $item) { + $item['ticket_message'] = preg_replace("#(https?|ftp)://\S+[^\s.,>)\];'\"!?]#",'\\0', $item['ticket_message']); + if($item['user_access_level'] == '1') { + echo '
+
+
+ Pic +
+
+ '. $item['user_firstname'] .' '. $item['user_lastname'] .' + '. date("d.m.Y в H:i", strtotime($item['ticket_message_date_add'])) .' +
+
+
'. nl2br($item['ticket_message']) .' +
'; + } + + if($item['user_access_level'] >= '2') { + echo '
+
+
+ Pic +
+
+ '. $item['user_firstname'] .' '. $item['user_lastname'] .' + '. date("d.m.Y в H:i", strtotime($item['ticket_message_date_add'])) .' +
+
+
'. nl2br($item['ticket_message']) .'
+
'; + } + } + } + } + + + private function validate($ticketid) { + $result = null; + $userid = $this->user->getId(); + if(!$this->ticketsModel->getTotalTickets(array('ticket_id' => (int)$ticketid, 'user_id' => (int)$userid))) { + $result = "Запрашиваемый запрос не существует!"; + } + return $result; + } + + private function validatePOST($ticketid) { + $result = null; + + $this->load->model('tickets'); + $userid = $this->user->getId(); + + $text = @$this->request->post['text']; + + if (5 <= $this->ticketsModel->spam($userid)) { + $result = 'Пожалуйста, подождите 10 секунд.'; + } + else if(mb_strlen($text) < 1 || mb_strlen($text) > 350) { + $result = "Текст сообщения должен содержать от 1 до 350 символов."; + } + return $result; + } +} \ No newline at end of file diff --git a/panel/application/controllers/webhost/control.php b/panel/application/controllers/webhost/control.php new file mode 100644 index 0000000..0ef4d7d --- /dev/null +++ b/panel/application/controllers/webhost/control.php @@ -0,0 +1,223 @@ +document->setActiveSection('webhost'); + $this->document->setActiveItem('control'); + $this->data['activesection'] = $this->document->getActiveSection(); + $this->data['activeitem'] = $this->document->getActiveItem(); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + + $this->load->model('webhost'); + + $error = $this->validate($webid); + if($error) { + $this->session->data['error'] = $error; + $this->response->redirect($this->config->url . 'webhost/index'); + } + + $webhost = $this->webhostModel->getWebhostById($webid, array('users','web_tarifs','web_locations')); + $this->data['webhost'] = $webhost; + + include_once 'application/controllers/common/main.php'; + + $this->getChild(array('common/header', 'common/footer')); + return $this->load->view('webhost/control', $this->data); + } + + public function ajax($webid = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + $this->load->model('webhost'); + + $error = $this->validate($webid); + if($error) { + $this->data['status'] = "error"; + $this->data['error'] = $error; + return json_encode($this->data); + } + $webhost = $this->webhostModel->getWebhostById($webid, array('web_tarifs')); + if($webhost['web_status'] == 0) { + $this->data['status'] = "error"; + $this->data['error'] = "Веб-хостинг заблокирован!"; + return json_encode($this->data); + } + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $editpassword = @$this->request->post['editpassword']; + $password = @$this->request->post['password']; + if($editpassword) { + $result = $this->webhostModel->updatepassUser($webid, $password); + if($result["status"] == "success") { + $this->webhostModel->updateWebhost($webid, array('web_password' => $password)); + $this->data['status'] = "success"; + $this->data['success'] = "Пароль доступа успешно изменен!"; + } else { + $this->data["status"] = "error"; + $this->data["error"] = $result["description"]; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Ошибка!"; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } + + return json_encode($this->data); + } + + public function buy_months($webid = null) { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('users'); + $this->load->model('webhost'); + $this->load->model('waste'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $days = @$this->request->post['days']; + if($days != "30" && $days != "60" && $days != "90" && $days != "180" && $days != "360" && $days != "15") { + $this->data['status'] = "error"; + $this->data['error'] = "Вы указали недопустимый период оплаты!"; + return json_encode($this->data); + } + + $userid = $this->user->getId(); + $balance = $this->user->getBalance(); + $webhost = $this->webhostModel->getWebhostById($webid, array('web_tarifs')); + + $price = $webhost['tarif_price']; + switch($days) { + case "15": + $price = $price / 2; + break; + case "30": + break; + case "60": + $price = $price * 2; + break; + case "90": + $price = 3 * $price * 0.95; + break; + case "180": + $price = 6 * $price * 0.90; + break; + case "360": + $price = 12 * $price * 0.85; + break; + } + + if($balance >= $price) { + if($webhost['web_status'] == 0) { + $this->webhostModel->extendWebhost($webid,$days,false); + $result = $this->webhostModel->unblockWebhost($webid); + if($result["status"] != "success") { + $this->data["status"] = "error"; + $this->data["error"] = $result["description"]; + } + } else { + $this->webhostModel->extendWebhost($webid,$days,false); + } + + $wasteData = array( + 'user_id' => $userid, + 'waste_ammount' => $price, + 'waste_status' => 1, + 'waste_usluga' => "Продление веб-хостинга ws$webid на $days дней" + ); + $this->wasteModel->createWaste($wasteData); + + $this->usersModel->downUserBalance($userid, $price); + + $user = $this->usersModel->getUserById($userid, array(), array(), array()); + if($user['ref'] != 0) { + $ref_percent = $this->config->ref_percent; + $getpref = ($price * (1 + $ref_percent / 100)) - $price; + $this->usersModel->upUserBalance($user['ref'], $getpref); + $this->usersModel->upUserRMoney($user['ref'], $getpref); + + $wasteData = array( + 'user_id' => $user['ref'], + 'waste_ammount' => $getpref, + 'waste_status' => 0, + 'waste_usluga' => "Бонус с реферала ID-$userid" + ); + $this->wasteModel->createWaste($wasteData); + } + + $this->data['status'] = "success"; + $this->data['success'] = "Вы успешно оплатили веб-хостинг на $days дней. С Вашего счета снято ".(round($price, 2))." руб"; + } else { + $this->data['status'] = "error"; + $this->data['error'] = "На Вашем счету не хватает ".(round($price-$balance, 2))." руб"; + } + } + return json_encode($this->data); + } + + private function validate($webid) { + $result = null; + + $userid = $this->user->getId(); + + if(!$this->webhostModel->getTotalWebhosts(array('web_id' => (int)$webid, 'user_id' => (int)$userid))) { + $result = "Запрашиваемый веб-хостинг не существует!"; + } + return $result; + } + + private function validatePOST() { + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + + $result = null; + + $editpassword = @$this->request->post['editpassword']; + $password = @$this->request->post['password']; + $password2 = @$this->request->post['password2']; + + if($editpassword) { + if(!$validateLib->password_web($password)) { + $result = "Пароль должен содержать от 8 до 32 латинских букв, цифр и знаков ,.!?_-!"; + } + elseif($password != $password2) { + $result = "Введенные вами пароли не совпадают!"; + } + } + return $result; + } +} +?> diff --git a/panel/application/controllers/webhost/index.php b/panel/application/controllers/webhost/index.php new file mode 100644 index 0000000..46e80ec --- /dev/null +++ b/panel/application/controllers/webhost/index.php @@ -0,0 +1,49 @@ +document->setActiveSection('webhost'); + $this->document->setActiveItem('index'); + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не залогинены!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "Нет доступа!"; + $this->response->redirect($this->config->url); + } + + $this->load->library('pagination'); + $this->load->model('webhost'); + + $userid = $this->user->getId(); + + $options = array( + 'start' => ($page - 1) * $this->limit, + 'limit' => $this->limit + ); + + $total = $this->webhostModel->getTotalWebhosts(array('user_id' => (int)$userid)); + $webhosts = $this->webhostModel->getWebhosts(array('user_id' => (int)$userid), array('web_tarifs', 'web_locations'), array(), $options); + + $paginationLib = new paginationLibrary(); + + $paginationLib->total = $total; + $paginationLib->page = $page; + $paginationLib->limit = $this->limit; + $paginationLib->url = $this->config->url . 'webhost/index/index/{page}'; + + $pagination = $paginationLib->render(); + + $this->data['webhosts'] = $webhosts; + $this->data['pagination'] = $pagination; + + $this->getChild(array('common/header', 'common/footer')); + return $this->load->view('webhost/index', $this->data); + } +} +?> diff --git a/panel/application/controllers/webhost/order.php b/panel/application/controllers/webhost/order.php new file mode 100644 index 0000000..60bdef3 --- /dev/null +++ b/panel/application/controllers/webhost/order.php @@ -0,0 +1,216 @@ +document->setActiveSection('webhost'); + $this->document->setActiveItem('order'); + + if(!$this->user->isLogged()) { + $this->session->data['error'] = "Вы не авторизированы!"; + $this->response->redirect($this->config->url . 'account/login'); + } + if($this->user->getAccessLevel() < 0) { + $this->session->data['error'] = "У вас нет доступа к данному разделу!"; + $this->response->redirect($this->config->url); + } + $this->load->model('webhostTarifs'); + $this->load->model('webLocations'); + $tarifs = $this->webhostTarifsModel->getTarifs(array('tarif_status' => 1)); + $locations = $this->webLocationsModel->getLocations(array('location_status' => 1)); + $this->data['tarifs'] = $tarifs; + $this->data['locations'] = $locations; + $this->getChild(array('common/header', 'common/footer')); + return $this->load->view('webhost/order', $this->data); + } + + public function promo() { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('users'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + $code = $this->request->post['code']; + $skidka = $this->usersModel->getSkidkaByCode($code, false);$kofficent=(100-$skidka['skidka'])/100; + if($skidka['skidka'] == NULL){ + $this->data['status'] = "error"; + $this->data['error'] = "Данного кода не существует"; + }else{ + $this->data['status'] = "success"; + $this->data['success'] = "Вы активировали скидку ".$skidka['skidka']."%"; + $this->data['skidka'] = $kofficent; + } + } + + return json_encode($this->data); + } + + public function ajax() { + if(!$this->user->isLogged()) { + $this->data['status'] = "error"; + $this->data['error'] = "Вы не авторизированы!"; + return json_encode($this->data); + } + if($this->user->getAccessLevel() < 1) { + $this->data['status'] = "error"; + $this->data['error'] = "У вас нет доступа к данному разделу!"; + return json_encode($this->data); + } + + $this->load->model('users'); + $this->load->model('waste'); + $this->load->model('webhost'); + $this->load->model('webhostTarifs'); + $this->load->model('webLocations'); + + if($this->request->server['REQUEST_METHOD'] == 'POST') { + if($this->config->webhost == 1) { + $errorPOST = $this->validatePOST(); + if(!$errorPOST) { + $tarifid = $this->request->post['tarifid']; + $days = $this->request->post['days']; + $locationid = $this->request->post['locationid']; + + $location = $this->webLocationsModel->getLocationById($locationid); + $location_tarifs = explode(" ", $location['location_tarifs']); + + if(!in_array($tarifid, $location_tarifs)) { + $this->data['status'] = "error"; + $this->data['error'] = "Данный тариф не доступен для указанной локации!"; + return json_encode($this->data); + } + + $chars="qazxswedcvfrtgbnhyujmkiolp1234567890QAZXSWEDCVFRTGBNHYUJMKIOLP"; + $max=14; + $size=StrLen($chars)-1; + $password=null; + while($max--) + $password.=$chars[rand(0,$size)]; + + $userid = $this->user->getId(); + $balance = $this->user->getBalance(); + $tarif = $this->webhostTarifsModel->getTarifById($tarifid); + $code = $this->request->post['promo']; + $skidka = $this->usersModel->getSkidkaByCode($code,true);$kofficent=(100-$skidka['skidka'])/100; + $price = $tarif['tarif_price']; + + switch($days) { + case "15": + $price = $price / 2; + break; + case "30": + break; + case "60": + $price = $price * 2; + break; + case "90": + $price = 3 * $price * 0.95; + break; + case "180": + $price = 6 * $price * 0.90; + break; + case "360": + $price = 12 * $price * 0.85; + break; + } + + if($skidka['skidka'] != NULL){ + $price = $price * $kofficent; + } + + if($balance >= $price) { + $webData = array( + 'user_id' => $userid, + 'location_id' => $locationid, + 'web_password' => $password, + 'tarif_id' => $tarifid, + 'web_status' => 1, + 'web_days' => $days + ); + $package = $tarif['package']; + $webid = $this->webhostModel->createWebhost($webData); + $result = $this->webhostModel->installWebhost($webid,$password,$package); + if($result["status"] == "success") { + $this->usersModel->downUserBalance($userid, $price); + $wasteData = array( + 'user_id' => $userid, + 'waste_ammount' => $price, + 'waste_status' => 1, + 'waste_usluga' => "Заказ веб-хостинга ws$webid" + ); + $this->wasteModel->createWaste($wasteData); + + $user = $this->usersModel->getUserById($userid, array(), array(), array()); + if($user['ref'] != 0) { + $ref_percent = $this->config->ref_percent; + $getpref = ($price * (1 + $ref_percent / 100)) - $price; + $this->usersModel->upUserBalance($user['ref'], $getpref); + $this->usersModel->upUserRMoney($user['ref'], $getpref); + + $wasteData = array( + 'user_id' => $user['ref'], + 'waste_ammount' => $getpref, + 'waste_status' => 0, + 'waste_usluga' => "Бонус с реферала ID-$userid" + ); + $this->wasteModel->createWaste($wasteData); + } + $this->data['status'] = "success"; + $this->data['success'] = "Веб-хостинг №".$webid." успешно заказан."; + $this->data['id'] = $webid; + } else { + $this->data["status"] = "error"; + $this->data["error"] = $result["description"]; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "На Вашем счету не хватает ".(round($price-$balance, 2))." руб"; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = $errorPOST; + } + } else { + $this->data['status'] = "error"; + $this->data['error'] = "Веб.хостинг не доступен для заказа!"; + } + } + + return json_encode($this->data); + } + + private function validatePOST() { + $this->load->library('validate'); + + $validateLib = new validateLibrary(); + + $result = null; + $tarifid = @$this->request->post['tarifid']; + $months = @$this->request->post['months']; + $locationid = @$this->request->post['locationid']; + $days = @$this->request->post['days']; + + if(!$this->webhostTarifsModel->getTotalTarifs(array('tarif_id' => (int)$tarifid, 'tarif_status' => 1))) { + $result = "Вы указали несуществующий тариф!"; + } + elseif(!$this->webLocationsModel->getTotalLocations(array('location_id' => (int)$locationid, 'location_status' => 1))) { + $result = "Вы указали несуществующую локацию!"; + } + elseif($days != "30" && $days != "60" && $days != "90" && $days != "180" && $days != "360" && $days != "15") { + $result = "Вы указали недопустимый период оплаты!"; + } + return $result; + } +} +?> diff --git a/panel/application/models/games.php b/panel/application/models/games.php new file mode 100644 index 0000000..49233fd --- /dev/null +++ b/panel/application/models/games.php @@ -0,0 +1,112 @@ +db->escape($data['game_name']) . "', "; + $sql .= "game_code = '" . $this->db->escape($data['game_code']) . "', "; + $sql .= "game_query = '" . $this->db->escape($data['game_query']) . "', "; + $sql .= "game_min_slots = '" . (int)$data['game_min_slots'] . "', "; + $sql .= "game_max_slots = '" . (int)$data['game_max_slots'] . "', "; + $sql .= "game_min_port = '" . (int)$data['game_min_port'] . "', "; + $sql .= "game_max_port = '" . (int)$data['game_max_port'] . "', "; + $sql .= "game_price = '" . (float)$data['game_price'] . "', "; + $sql .= "game_cores = '" . (int)$data['game_cores'] . "', "; + $sql .= "game_ram = '" . (int)$data['game_ram'] . "', "; + $sql .= "game_ssd = '" . (int)$data['game_ssd'] . "', "; + $sql .= "game_status = '" . (int)$data['game_status'] . "'"; + $this->db->query($sql); + return $this->db->getLastId(); + } + + public function deleteGame($gameid) { + $sql = "DELETE FROM `games` WHERE game_id = '" . (int)$gameid . "'"; + $this->db->query($sql); + } + + public function updateGame($gameid, $data = array()) { + $sql = "UPDATE `games`"; + if(!empty($data)) { + $count = count($data); + $sql .= " SET"; + foreach($data as $key => $value) { + $sql .= " $key = '" . $this->db->escape($value) . "'"; + + $count--; + if($count > 0) $sql .= ","; + } + } + $sql .= " WHERE `game_id` = '" . (int)$gameid . "'"; + $query = $this->db->query($sql); + return true; + } + + public function getGames($data = array(), $sort = array(), $options = array()) { + $sql = "SELECT * FROM `games`"; + if(!empty($data)) { + $count = count($data); + $sql .= " WHERE"; + foreach($data as $key => $value) { + $sql .= " $key = '" . $this->db->escape($value) . "'"; + + $count--; + if($count > 0) $sql .= " AND"; + } + } + + if(!empty($sort)) { + $count = count($sort); + $sql .= " ORDER BY"; + foreach($sort as $key => $value) { + $sql .= " $key " . $value; + + $count--; + if($count > 0) $sql .= ","; + } + } + + if(!empty($options)) { + if ($options['start'] < 0) { + $options['start'] = 0; + } + if ($options['limit'] < 1) { + $options['limit'] = 20; + } + $sql .= " LIMIT " . (int)$options['start'] . "," . (int)$options['limit']; + } + $query = $this->db->query($sql); + return $query->rows; + } + + public function getGameById($gameid) { + $sql = "SELECT * FROM `games` WHERE `game_id` = '" . (int)$gameid . "' LIMIT 1"; + $query = $this->db->query($sql); + return $query->row; + } + + public function getTotalGames($data = array()) { + $sql = "SELECT COUNT(*) AS count FROM `games`"; + if(!empty($data)) { + $count = count($data); + $sql .= " WHERE"; + foreach($data as $key => $value) { + $sql .= " $key = '" . $this->db->escape($value) . "'"; + + $count--; + if($count > 0) $sql .= " AND"; + } + } + $query = $this->db->query($sql); + return $query->row['count']; + } + + public function validateSlots($gameid, $slots) { + $sql = "SELECT COUNT(*) AS total FROM `games` WHERE game_id = '" . (int)$gameid . "' AND " . (int)$slots . " BETWEEN game_min_slots AND game_max_slots"; + $query = $this->db->query($sql); + return $query->row['total']; + } +} +?> diff --git a/panel/application/models/invoices.php b/panel/application/models/invoices.php new file mode 100644 index 0000000..004099d --- /dev/null +++ b/panel/application/models/invoices.php @@ -0,0 +1,123 @@ +db->query($sql); + return $this->db->getLastId(); + } + + public function deleteInvoice($invoiceid) { + $sql = "DELETE FROM `invoices` WHERE invoice_id = '" . (int)$invoiceid . "'"; + $this->db->query($sql); + } + + public function updateInvoice($invoiceid, $data = array()) { + $sql = "UPDATE `invoices`"; + if(!empty($data)) { + $count = count($data); + $sql .= " SET"; + foreach($data as $key => $value) { + $sql .= " $key = '" . $this->db->escape($value) . "'"; + + $count--; + if($count > 0) $sql .= ","; + } + } + $sql .= " WHERE `invoice_id` = '" . (int)$invoiceid . "'"; + $query = $this->db->query($sql); + return true; + } + + public function getInvoices($data = array(), $joins = array(), $sort = array(), $options = array()) { + $sql = "SELECT * FROM `invoices`"; + foreach($joins as $join) { + $sql .= " LEFT JOIN $join"; + switch($join) { + case "users": + $sql .= " ON invoices.user_id=users.user_id"; + break; + } + } + + if(!empty($data)) { + $count = count($data); + $sql .= " WHERE"; + foreach($data as $key => $value) { + $sql .= " $key = '" . $this->db->escape($value) . "'"; + + $count--; + if($count > 0) $sql .= " AND"; + } + } + + if(!empty($sort)) { + $count = count($sort); + $sql .= " ORDER BY"; + foreach($sort as $key => $value) { + $sql .= " $key " . $value; + + $count--; + if($count > 0) $sql .= ","; + } + } + + if(!empty($options)) { + if ($options['start'] < 0) { + $options['start'] = 0; + } + if ($options['limit'] < 1) { + $options['limit'] = 20; + } + $sql .= " LIMIT " . (int)$options['start'] . "," . (int)$options['limit']; + } + $query = $this->db->query($sql); + return $query->rows; + } + + public function getInvoiceById($invoiceid, $joins = array()) { + $sql = "SELECT * FROM `invoices`"; + foreach($joins as $join) { + $sql .= " LEFT JOIN $join"; + switch($join) { + case "users": + $sql .= " ON invoices.user_id=users.user_id"; + break; + } + } + $sql .= " WHERE `invoice_id` = '" . (int)$invoiceid . "' LIMIT 1"; + $query = $this->db->query($sql); + return $query->row; + } + + public function getTotalInvoices($data = array()) { + $sql = "SELECT COUNT(*) AS count FROM `invoices`"; + if(!empty($data)) { + $count = count($data); + $sql .= " WHERE"; + foreach($data as $key => $value) { + $sql .= " $key = '" . $this->db->escape($value) . "'"; + + $count--; + if($count > 0) $sql .= " AND"; + } + } + $query = $this->db->query($sql); + return $query->row['count']; + } + //Статистика + public function getStatisticsInvStatsById() { + $sql = "SELECT invoice_date_add, SUM(`invoice_ammount`) FROM invoices WHERE `invoice_status` = 1 GROUP BY `invoice_date_add`"; + $query = $this->db->query($sql); + return $query->rows; + } +} +?> diff --git a/panel/application/models/locations.php b/panel/application/models/locations.php new file mode 100644 index 0000000..2be0d65 --- /dev/null +++ b/panel/application/models/locations.php @@ -0,0 +1,100 @@ +db->escape($data['location_name']) . "', "; + $sql .= "location_ip = '" . $this->db->escape($data['location_ip']) . "', "; + $sql .= "location_ip2 = '" . $this->db->escape($data['location_ip2']) . "', "; + $sql .= "location_user = '" . $this->db->escape($data['location_user']) . "', "; + $sql .= "location_password = '" . $this->db->escape($data['location_password']) . "', "; + $sql .= "location_status = '" . (int)$data['location_status'] . "'"; + $this->db->query($sql); + return $this->db->getLastId(); + } + + public function deleteLocation($locationid) { + $sql = "DELETE FROM `locations` WHERE location_id = '" . (int)$locationid . "'"; + $this->db->query($sql); + } + + public function updateLocation($locationid, $data = array()) { + $sql = "UPDATE `locations`"; + if(!empty($data)) { + $count = count($data); + $sql .= " SET"; + foreach($data as $key => $value) { + $sql .= " $key = '" . $this->db->escape($value) . "'"; + + $count--; + if($count > 0) $sql .= ","; + } + } + $sql .= " WHERE `location_id` = '" . (int)$locationid . "'"; + $query = $this->db->query($sql); + return true; + } + + public function getLocations($data = array(), $sort = array(), $options = array()) { + $sql = "SELECT * FROM `locations`"; + if(!empty($data)) { + $count = count($data); + $sql .= " WHERE"; + foreach($data as $key => $value) { + $sql .= " $key = '" . $this->db->escape($value) . "'"; + + $count--; + if($count > 0) $sql .= " AND"; + } + } + + if(!empty($sort)) { + $count = count($sort); + $sql .= " ORDER BY"; + foreach($sort as $key => $value) { + $sql .= " $key " . $value; + + $count--; + if($count > 0) $sql .= ","; + } + } + + if(!empty($options)) { + if ($options['start'] < 0) { + $options['start'] = 0; + } + if ($options['limit'] < 1) { + $options['limit'] = 20; + } + $sql .= " LIMIT " . (int)$options['start'] . "," . (int)$options['limit']; + } + $query = $this->db->query($sql); + return $query->rows; + } + + public function getLocationById($locationid) { + $sql = "SELECT * FROM `locations` WHERE `location_id` = '" . (int)$locationid . "' LIMIT 1"; + $query = $this->db->query($sql); + return $query->row; + } + + public function getTotalLocations($data = array()) { + $sql = "SELECT COUNT(*) AS count FROM `locations`"; + if(!empty($data)) { + $count = count($data); + $sql .= " WHERE"; + foreach($data as $key => $value) { + $sql .= " $key = '" . $this->db->escape($value) . "'"; + + $count--; + if($count > 0) $sql .= " AND"; + } + } + $query = $this->db->query($sql); + return $query->row['count']; + } +} +?> diff --git a/panel/application/models/mail.php b/panel/application/models/mail.php new file mode 100644 index 0000000..81af054 --- /dev/null +++ b/panel/application/models/mail.php @@ -0,0 +1,109 @@ +db->escape($data['user_firstname']) . "', "; + $sql .= "user_lastname = '" . $this->db->escape($data['user_lastname']) . "', "; + $sql .= "user_email = '" . $this->db->escape($data['user_email']) . "', "; + $sql .= "category = '" . $this->db->escape($data['category']) . "', "; + // $sql .= "text = '" . (float)$data['text'] . "', "; + $sql .= "text = '" . strip_tags(htmlspecialchars_decode($this->db->escape($data['text'])), '').appendTo(u),u.remove(),m.remove()},100)},m=e('').on("load",function(){m.off("load").on("load",function(){f(),d.resolve()}),o=setTimeout(function(){a=!0,s.notify({type:"upload",cnt:i})},s.options.notifyDelay),s.options.iframeTimeout>0&&(r=setTimeout(function(){f(),d.reject(["errConnect","errTimeout"])},s.options.iframeTimeout)),u.submit()}),g=t.target||s.cwd().hash,v=[],b=[],y=[],w={};if(c&&c.length)e.each(c,function(e,t){u.append('')}),i=1;else{if(!(l&&e(l).is(":file")&&e(l).val()))return d.reject();n.options.overwriteUploadConfirm&&n.option("uploadOverwrite",g)&&(v=l.files?l.files:[{name:e(l).val().replace(/^(?:.+[\\\/])?([^\\\/]+)$/,"$1")}],b.push(s.uploads.checkExists(v,g,s).done(function(n,a){w=a,null===n?t.overwrite=0:(y=n,i=e.grep(v,function(e){return!e._remove}).length,i!=v.length&&(i=0))}))),i=l.files?l.files.length:1,u.append(l)}return e.when.apply(e,b).done(function(){ +return i<1?d.reject():(u.append('').append('').append('').append(e(l).attr("name","upload[]")),y.length>0&&(e.each(y,function(e,t){u.append('')}),u.append('')),w&&e.each(y,function(e,t){u.append('')}),0===t.overwrite&&u.append(''),e.each(s.options.onlyMimes||[],function(e,t){u.append('')}),e.each(s.customData,function(e,t){u.append('')}),u.appendTo("body"),void m.appendTo("body"))}),d}},one:function(e,t,n){var i=this,a=e.toLowerCase(),o=function(e,n){return i.toUnbindEvents[a]||(i.toUnbindEvents[a]=[]),i.toUnbindEvents[a].push({type:a,callback:o}),(t.done?t.done:t).apply(this,arguments)};return t.done&&(o={done:o}),this.bind(a,o,n)},localStorage:function(t,n){var i,a,o,r,s,l=this,c=window.localStorage,d="elfinder-"+(t||"")+this.id,p=window.location.pathname+"-elfinder-",u=this.id,h=[];if("undefined"==typeof t)return r=p.length,s=u.length*-1,e.each(c,function(e){e.substr(0,r)===p&&e.substr(s)===u&&h.push(e)}),e.each(h,function(e,t){c.removeItem(t)}),!0;if(t=p+t+u,null===n)return c.removeItem(t);if(void 0===n&&!(i=c.getItem(t))&&(a=c.getItem(d))&&(n=a,c.removeItem(d)),void 0!==n){o=typeof n,"string"!==o&&"number"!==o&&(n=JSON.stringify(n));try{c.setItem(t,n)}catch(f){try{c.clear(),c.setItem(t,n)}catch(f){l.debug("error",f.toString())}}i=c.getItem(t)}if(i&&("{"===i.substr(0,1)||"["===i.substr(0,1)))try{return JSON.parse(i)}catch(f){}return i},sessionStorage:function(e,t){var n,i,a,o=this;try{n=window.sessionStorage}catch(r){}if(n){if(null===t)return n.removeItem(e);if(void 0!==t){a=typeof t,"string"!==a&&"number"!==a&&(t=JSON.stringify(t));try{n.setItem(e,t)}catch(r){try{n.clear(),n.setItem(e,t)}catch(r){o.debug("error",r.toString())}}}if(i=n.getItem(e),i&&("{"===i.substr(0,1)||"["===i.substr(0,1)))try{return JSON.parse(i)}catch(r){}return i}},cookie:function(t,n){var i,a,o,r,s,l;if(t="elfinder-"+t+this.id,void 0===n){if(this.cookieEnabled&&document.cookie&&""!=document.cookie)for(o=document.cookie.split(";"),t+="=",r=0;r"),escape:function(e){return this._node.text(e).html().replace(/"/g,""").replace(/'/g,"'")},normalize:function(t){var n,i,a,o,r,s=this,l=function(){var e,t;return(t=s.options.fileFilter)&&("function"==typeof t?e=function(e){return t.call(s,e)}:t instanceof RegExp&&(e=function(e){return t.test(e.name)})),e?e:null}(),c=function(t){var n;t.uiCmdMap&&(e.isPlainObject(t.uiCmdMap)&&Object.keys(t.uiCmdMap).length?(t.disabledFlip||(t.disabledFlip={}),n=t.disabledFlip,e.each(t.uiCmdMap,function(e,i){"hidden"!==i||n[e]||(t.disabled.push(e),t.disabledFlip[e]=!0)})):delete t.uiCmdMap)},d=function(t){var n=function(e){var t=typeof e;return"object"===t&&Array.isArray(e)&&(t="array"),t};return e.each(s.optionProperties,function(e,i){void 0!==i&&t[e]&&n(t[e])!==n(i)&&(t[e]=i)}),t.disabled?(t.disabledFlip=s.arrayFlip(t.disabled,!0),e.each(s.options.disabledCmdsRels,function(n,i){var a,o;t.disabledFlip[n]?o=!0:(a=n.match(/^([^&]+)&([^=]+)=(.*)$/))&&t.disabledFlip[a[1]]&&t[a[2]]==a[3]&&(o=!0),o&&e.each(i,function(e,n){t.disabledFlip[n]||(t.disabledFlip[n]=!0,t.disabled.push(n))})})):t.disabledFlip={},t},p=function(t,r,p){var u,h,m,g,v=!r||t,b=!!r&&null;if(t&&t.hash&&t.name&&t.mime){if("application/x-empty"===t.mime&&(t.mime="text/plain"),m=s.isRoot(t),m&&!t.volumeid&&s.debug("warning","The volume root statuses requires `volumeid` property."),m||"directory"===t.mime){if(t.phash){if(t.phash===t.hash)return f=f.concat(['Parent folder of "$1" is itself.',t.name]),b;if(m&&t.volumeid&&0===t.phash.indexOf(t.volumeid))return f=f.concat(['Parent folder of "$1" is inner itself.',t.name]),b}t.volumeid&&(u=t.volumeid,m&&(t.phash&&(s.leafRoots[t.phash]?e.inArray(t.hash,s.leafRoots[t.phash])===-1&&s.leafRoots[t.phash].push(t.hash):s.leafRoots[t.phash]=[t.hash]),s.hasVolOptions=!0,s.volOptions[u]||(s.volOptions[u]={dispInlineRegex:s.options.dispInlineRegex}),h=s.volOptions[u],t.options&&Object.assign(h,t.options),t.disabled&&(h.disabled=t.disabled,h.disabledFlip=s.arrayFlip(t.disabled,!0)),t.tmbUrl&&(h.tmbUrl=t.tmbUrl),h.url&&"/"!==h.url.substr(-1)&&(h.url+="/"),c(h),h.trashHash&&(s.trashes[h.trashHash]===!1?delete h.trashHash:s.trashes[h.trashHash]=t.hash),e.each(s.optionProperties,function(e){h[e]&&(t[e]=h[e])}),"cwd"!==p&&(s.roots[u]=t.hash),t.expires&&(s.volumeExpires[u]=t.expires)),o!==u&&(o=u,a=s.option("i18nFolderName",u))),m&&!t.i18&&(n="volume_"+t.name,i=s.i18n(!1,n),n!==i&&(t.i18=i)),a&&!t.i18&&(n="folder_"+t.name,i=s.i18n(!1,n),n!==i&&(t.i18=i)),m&&(g=s.storage("rootNames"))&&(g[t.hash]&&(t._name=t.name,t._i18=t.i18,t.name=g[t.hash]=g[t.hash],delete t.i18),s.storage("rootNames",g)),s.trashes[t.hash]&&(t.locked=!0)}else{if(l)try{if(!l(t))return b}catch(y){s.debug(y)}0==t.size&&(t.mime=s.getMimetype(t.name,t.mime))}return t.options&&(s.optionsByHashes[t.hash]=d(t.options)),delete t.options,v}return b},u=function(t){var n=[];return e.each(s.files(),function(i,a){e.each(s.parents(i),function(a,o){if(e.inArray(o,t)!==-1&&e.inArray(i,t)===-1)return n.push(i),!1})}),n},h=function(n,i){e.each(n,function(n,a){var o,r;s.leafRoots[a.hash]&&s.applyLeafRootStats(a),"change"!==i&&a.phash&&s.isRoot(a)&&(o=s.file(a.phash))&&(s.applyLeafRootStats(o),t.changed?(e.each(t.changed,function(e,n){if(n.hash===o.hash)return t.changed[e]=o,r=!0,!1}),r||t.changed.push(o)):t.changed=[o])})},f=[];if(t.customData&&(!s.prevCustomData||JSON.stringify(t.customData)!==JSON.stringify(s.prevCustomData))){s.prevCustomData=t.customData;try{r=JSON.parse(t.customData),e.isPlainObject(r)&&(s.prevCustomData=r,e.each(Object.keys(r),function(e,t){null===r[t]&&(delete r[t],delete s.optsCustomData[t])}),s.customData=Object.assign({},s.optsCustomData,r))}catch(m){}}return t.options&&d(t.options),t.cwd&&(t.cwd.volumeid&&t.options&&Object.keys(t.options).length&&s.isRoot(t.cwd)&&(s.hasVolOptions=!0,s.volOptions[t.cwd.volumeid]=t.options),t.cwd=p(t.cwd,!0,"cwd")),t.files&&(t.files=e.grep(t.files,p)),t.tree&&(t.tree=e.grep(t.tree,p)),t.added&&(t.added=e.grep(t.added,p)),t.changed&&(t.changed=e.grep(t.changed,p)),t.removed&&t.removed.length&&2===s.searchStatus.state&&(t.removed=t.removed.concat(u(t.removed))),t.api&&(t.init=!0),Object.keys(s.leafRoots).length&&(t.files&&h(t.files),t.tree&&h(t.tree),t.added&&h(t.added),t.changed&&h(t.changed,"change")),t.cwd&&t.cwd.options&&t.options&&Object.assign(t.options,d(t.cwd.options)),t.options&&t.options.url&&"/"!==t.options.url.substr(-1)&&(t.options.url+="/"),f.length&&(t.norError=["errResponse"].concat(f)),t},setSort:function(e,t,n,i){this.storage("sortType",this.sortType=this.sortRules[e]?e:"name"),this.storage("sortOrder",this.sortOrder=/asc|desc/.test(t)?t:"asc"),this.storage("sortStickFolders",(this.sortStickFolders=!!n)?1:""),this.storage("sortAlsoTreeview",(this.sortAlsoTreeview=!!i)?1:""),this.trigger("sortchange")},_sortRules:{name:function(e,t){return i.prototype.naturalCompare(e.i18||e.name,t.i18||t.name)},size:function(e,t){var n=parseInt(e.size)||0,i=parseInt(t.size)||0;return n===i?0:n>i?1:-1},kind:function(e,t){return i.prototype.naturalCompare(e.mime,t.mime)},date:function(e,t){var n=e.ts||e.date||0,i=t.ts||t.date||0;return n===i?0:n>i?1:-1},perm:function(e,t){var n=function(e){return(e.write?2:0)+(e.read?1:0)},i=n(e),a=n(t);return i===a?0:i>a?1:-1},mode:function(e,t){var n=e.mode||e.perm||"",a=t.mode||t.perm||"";return i.prototype.naturalCompare(n,a)},owner:function(e,t){var n=e.owner||"",a=t.owner||"";return i.prototype.naturalCompare(n,a)},group:function(e,t){var n=e.group||"",a=t.group||"";return i.prototype.naturalCompare(n,a)}},sorters:{},naturalCompare:function(e,t){var n=i.prototype.naturalCompare;return"undefined"==typeof n.loc&&(n.loc=navigator.userLanguage||navigator.browserLanguage||navigator.language||"en-US"),"undefined"==typeof n.sort&&("11".localeCompare("2",n.loc,{numeric:!0})>0?window.Intl&&window.Intl.Collator?n.sort=new Intl.Collator(n.loc,{numeric:!0}).compare:n.sort=function(e,t){return e.localeCompare(t,n.loc,{numeric:!0})}:(n.sort=function(e,t){var i,a,o=/(^-?[0-9]+(\.?[0-9]*)[df]?e?[0-9]?$|^0x[0-9a-f]+$|[0-9]+)/gi,r=/(^[ ]*|[ ]*$)/g,s=/(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/,l=/^0x[0-9a-f]+$/i,c=/^0/,d=/^[\x01\x21-\x2f\x3a-\x40\x5b-\x60\x7b-\x7e]/,p=function(e){return n.sort.insensitive&&(""+e).toLowerCase()||""+e},u=p(e).replace(r,"").replace(/^_/,"")||"",h=p(t).replace(r,"").replace(/^_/,"")||"",f=u.replace(o,"\0$1\0").replace(/\0$/,"").replace(/^\0/,"").split("\0"),m=h.replace(o,"\0$1\0").replace(/\0$/,"").replace(/^\0/,"").split("\0"),g=parseInt(u.match(l))||1!=f.length&&u.match(s)&&Date.parse(u),v=parseInt(h.match(l))||g&&h.match(s)&&Date.parse(h)||null,b=0;if(v){if(gv)return 1}for(var y=0,w=Math.max(f.length,m.length);ya)return 1}return 0},n.sort.insensitive=!0)),n.sort(e,t)},compare:function(e,t){var n,i=this,a=i.sortType,o="asc"==i.sortOrder,r=i.sortStickFolders,s=i.sortRules,l=s[a],c="directory"==e.mime,d="directory"==t.mime;if(r){if(c&&!d)return-1;if(!c&&d)return 1}return n=o?l(e,t):l(t,e),"name"!==a&&0===n?n=o?s.name(e,t):s.name(t,e):n},sortFiles:function(e){return e.sort(this.compare)},notify:function(t){var n,i,a,o=this,r=t.type,s=t.id?"elfinder-notify-"+t.id:"",l=this.i18n("undefined"!=typeof t.msg?t.msg:this.messages["ntf"+r]?"ntf"+r:"ntfsmth"),c=this.arrayFlip(this.options.notifyDialog.hiddens||[]),d=this.ui.notify,p=d.closest(".ui-dialog"),u=d.children(".elfinder-notify-"+r+(s?"."+s:"")),h=u.children("div.elfinder-notify-cancel").children("button"),f='
{msg}
',m=t.cnt+0,g="undefined"!=typeof t.size?parseInt(t.size):null,v="undefined"!=typeof t.progress&&t.progress>=0?t.progress:null,b=t.fakeinterval||200,y=t.cancel,w="ui-state-hover",x=function(){var t=u.find(".elfinder-notify-progress"),n=function(){u.remove(),d.children(p.data("minimized")?void 0:":visible").length||(p.data("minimized")?p.data("minimized").hide():d.elfinderdialog("close")),C()};u._esc&&e(document).off("keydown",u._esc),u.data("cur")<100?t.animate({width:"100%"},50,function(){requestAnimationFrame(function(){n()})}):n()},k=function(e){var t;u.length&&(t=u.data("cur")+1,t<=98&&(u.find(".elfinder-notify-progress").width(t+"%"),u.data("cur",t),C(),setTimeout(function(){e*=1.05,k(e)},e)))},C=function(){var t,n=0,i=0,a=d.children(".elfinder-notify");a.length?(a.each(function(){n++,i+=Math.min(e(this).data("cur"),100)}),t=n?Math.floor(i/(100*n)*100)+"%":0,o.ui.progressbar.width(t),p.data("minimized")&&(p.data("minimized").title(t),p.data("minimized").dialog().children(".ui-dialog-titlebar").children(".elfinder-ui-progressbar").width(t))):(o.ui.progressbar.width(0),p.data("minimized")&&p.data("minimized").hide())};return r?(u.length?"undefined"!=typeof t.msg&&u.children("span.elfinder-notify-msg").html(l):(u=e(f.replace(/\{type\}/g,r).replace(/\{msg\}/g,l)),c[r]?u.hide():d.on("minimize",function(e){p.data("minimized")&&C()}),u.appendTo(d).data("cnt",0),null!=v?u.data({progress:0,total:0,cur:0}):(u.data({cur:0}),k(b)),y&&(h=e('').on("mouseenter mouseleave",function(t){e(this).toggleClass(w,"mouseenter"===t.type)}),u.children("div.elfinder-notify-cancel").append(h)),d.trigger("resize")),n=m+parseInt(u.data("cnt")),n>0?(y&&h.length&&(e.isFunction(y)||"object"==typeof y&&y.promise)&&(u._esc=function(t){"keydown"==t.type&&t.keyCode!=e.ui.keyCode.ESCAPE||(t.preventDefault(),t.stopPropagation(),x(),y.promise?y.reject(0):y(t))},h.on("click",function(e){u._esc(e)}),e(document).on("keydown."+this.namespace,u._esc)),!t.hideCnt&&u.children(".elfinder-notify-cnt").text("("+n+")"),m>0&&d.is(":hidden")&&!c[r]&&(p.data("minimized")?p.data("minimized").show():d.elfinderdialog("open",this).height("auto")),u.data("cnt",n),null!=v&&(i=u.data("total"))>=0&&(a=u.data("progress"))>=0&&(i+=null!=g?g:m,a+=v,null==g&&m<0&&(a+=100*m),u.data({progress:a,total:i}),null!=g&&(a*=100,i=Math.max(1,i)),v=Math.min(parseInt(a/i),100),u.find(".elfinder-notify-progress").animate({width:(v<100?v:100)+"%"},20,function(){u.data("cur",v),C()}))):x(),this):this},confirm:function(t){var n,i,a=this,o=!1,r={cssClass:"elfinder-dialog-confirm",modal:!0,resizable:!1,title:this.i18n(t.title||"confirmReq"),buttons:{},close:function(){!o&&t.cancel.callback(),e(this).elfinderdialog("destroy")}},s=this.i18n("apllyAll");return t.cssClass&&(r.cssClass+=" "+t.cssClass),r.buttons[this.i18n(t.accept.label)]=function(){t.accept.callback(!(!n||!n.prop("checked"))),o=!0,e(this).elfinderdialog("close")},r.buttons[this.i18n(t.accept.label)]._cssClass="elfinder-confirm-accept",t.reject&&(r.buttons[this.i18n(t.reject.label)]=function(){t.reject.callback(!(!n||!n.prop("checked"))),o=!0,e(this).elfinderdialog("close")},r.buttons[this.i18n(t.reject.label)]._cssClass="elfinder-confirm-reject"),t.buttons&&t.buttons.length>0&&(i=1,e.each(t.buttons,function(t,s){r.buttons[a.i18n(s.label)]=function(){s.callback(!(!n||!n.prop("checked"))),o=!0,e(this).elfinderdialog("close")},r.buttons[a.i18n(s.label)]._cssClass="elfinder-confirm-extbtn"+i++,s.cssClass&&(r.buttons[a.i18n(s.label)]._cssClass+=" "+s.cssClass)})),r.buttons[this.i18n(t.cancel.label)]=function(){e(this).elfinderdialog("close")},r.buttons[this.i18n(t.cancel.label)]._cssClass="elfinder-confirm-cancel",t.all&&(r.create=function(){var t=e('
');n=e(''),e(this).next().find(".ui-dialog-buttonset").prepend(t.append(e("").prepend(n)))}),t.optionsCallback&&e.isFunction(t.optionsCallback)&&t.optionsCallback(r),this.dialog(''+this.i18n(t.text),r)},uniqueName:function(e,t,n){var i,a,o=0,r="";if(e=this.i18n(!1,e),t=t||this.cwd().hash,n="undefined"==typeof n?" ":n,(i=e.match(/^(.+)(\.[^.]+)$/))&&(r=i[2],e=i[1]),a=e+r,!this.fileByName(a,t))return a;for(;o<1e4;)if(a=e+n+ ++o+r,!this.fileByName(a,t))return a;return e+Math.random()+r},i18n:function(){var t,n,i,a,o,r=this,s=this.messages,l=[],c=[],d=function(e){var t;return 0===e.indexOf("#")&&(t=r.file(e.substr(1)))?t.name:e},p=0;for(arguments.length&&arguments[0]===!1&&(a=function(e){return e},p=1),t=p;t0&&l[n]&&c.push(n),i=a?a(l[n]):r.escape(l[n]),o&&(i=''+i+""),i})):i=i.get(0).outerHTML,l[t]=i);return e.grep(l,function(t,n){return e.inArray(n,c)===-1}).join("
")},getIconStyle:function(t,n){var i=this,a={background:"url('{url}') 0 0 no-repeat","background-size":"contain"},o="",r={},s=0;return t.icon&&(o='style="',e.each(a,function(e,a){0===s++&&(a=a.replace("{url}",i.escape(t.icon))),n?r[e]=a:o+=e+":"+a+";"}),o+='"'),n?r:o},mime2class:function(e){var t="elfinder-cwd-icon-",n=e.toLowerCase(),i=this.textMimes[n];return n=n.split("/"),i?n[0]+=" "+t+"text":n[1]&&n[1].match(/\+xml$/)&&(n[0]+=" "+t+"xml"),t+n[0]+(n[1]?" "+t+n[1].replace(/(\.|\+)/g,"-"):"")},mime2kind:function(e){var t,n="object"==typeof e,i=n?e.mime:e;return n&&e.alias&&"symlink-broken"!=i?t="Alias":this.kinds[i]&&(t=!n||"directory"!==i||e.phash&&!e.isroot?this.kinds[i]:"Root"),t||(t=0===i.indexOf("text")?"Text":0===i.indexOf("image")?"Image":0===i.indexOf("audio")?"Audio":0===i.indexOf("video")?"Video":0===i.indexOf("application")?"App":i),this.messages["kind"+t]?this.i18n("kind"+t):i},mimeIsText:function(e){return!!(this.textMimes[e.toLowerCase()]||0===e.indexOf("text/")&&"rtf"!==e.substr(5,3)||e.match(/^application\/.+\+xml$/))},date:function(e,t){var n,i,a,o,r,s,l,c,d,p=this;return t||(t=new Date),s=t[p.getHours](),l=s>12?s-12:s,c=t[p.getMinutes](),d=t[p.getSeconds](),i=t[p.getDate](),a=t[p.getDay](),o=t[p.getMonth]()+1,r=t[p.getFullYear](),n=e.replace(/[a-z]/gi,function(e){switch(e){case"d":return i>9?i:"0"+i;case"j":return i;case"D":return p.i18n(p.i18.daysShort[a]);case"l":return p.i18n(p.i18.days[a]);case"m":return o>9?o:"0"+o;case"n":return o;case"M":return p.i18n(p.i18.monthsShort[o-1]);case"F":return p.i18n(p.i18.months[o-1]);case"Y":return r;case"y":return(""+r).substr(2);case"H":return s>9?s:"0"+s;case"G":return s;case"g":return l;case"h":return l>9?l:"0"+l;case"a":return s>=12?"pm":"am";case"A":return s>=12?"PM":"AM";case"i":return c>9?c:"0"+c;case"s":return d>9?d:"0"+d}return e})},formatDate:function(e,t){var n,i,a,o=this,r=t||e.ts;o.i18;return o.options.clientFormatDate&&r>0?(n=new Date(1e3*r),i=r>=this.yesterday?this.fancyFormat:this.dateFormat,a=o.date(i,n),r>=this.yesterday?a.replace("$1",this.i18n(r>=this.today?"Today":"Yesterday")):a):e.date?e.date.replace(/([a-z]+)\s/i,function(e,t){return o.i18n(t)+" "}):o.i18n("dateUnknown")},toLocaleString:function(e){var t=new Number(e);return t?t.toLocaleString?t.toLocaleString():String(e).replace(/(\d)(?=(\d\d\d)+(?!\d))/g,"$1,"):e},perms2class:function(e){var t="";return e.read||e.write?e.read?e.write||(t="elfinder-ro"):t="elfinder-wo":t="elfinder-na",e.type&&(t+=" elfinder-"+this.escape(e.type)),t},formatPermissions:function(e){var t=[];return e.read&&t.push(this.i18n("read")),e.write&&t.push(this.i18n("write")),t.length?t.join(" "+this.i18n("and")+" "):this.i18n("noaccess")},formatSize:function(e){var t=1,n="b";return"unknown"==e?this.i18n("unknown"):(e>1073741824?(t=1073741824,n="GB"):e>1048576?(t=1048576,n="MB"):e>1024&&(t=1024,n="KB"),e/=t,(e>0?t>=1048576?e.toFixed(2):Math.round(e):0)+" "+n)},formatFileMode:function(t,n){var i,a,o,r,s,l,c,d,p;if(n||(n=this.options.fileModeStyle.toLowerCase()),t=e.trim(t),t.match(/[rwxs-]{9}$/i)){if(d=t=t.substr(-9),"string"==n)return d;for(p="",o=0,i=0;i<7;i+=3)a=t.substr(i,3),r=0,a.match(/[r]/i)&&(r+=4),a.match(/[w]/i)&&(r+=2),a.match(/[xs]/i)&&(a.match(/[xs]/)&&(r+=1),a.match(/[s]/i)&&(0==i?o+=4:3==i&&(o+=2))),p+=r.toString(8);o&&(p=o.toString(8)+p)}else{if(t=parseInt(t,8),p=t?t.toString(8):"",!t||"octal"==n)return p;for(a=t.toString(8),o=0,a.length>3&&(a=a.substr(-4),o=parseInt(a.substr(0,1),8),a=a.substr(1)),s=1==(1&o),c=2==(2&o),l=4==(4&o),d="",i=0;i<3;i++)d+=4==(4&parseInt(a.substr(i,1),8))?"r":"-",d+=2==(2&parseInt(a.substr(i,1),8))?"w":"-",d+=1==(1&parseInt(a.substr(i,1),8))?0==i&&l||1==i&&c?"s":"x":"-"}return"both"==n?d+" ("+p+")":"string"==n?d:p},registRawStringDecoder:function(t){e.isFunction(t)&&(this.decodeRawString=this.options.rawStringDecoder=t)},uploadMimeCheck:function(t,n){n=n||this.cwd().hash;var i,a,o=!0,r=this.option("uploadMime",n),s=function(n){var i=!1;return"string"==typeof n&&"all"===n.toLowerCase()?i=!0:Array.isArray(n)&&n.length&&e.each(n,function(e,n){if(n=n.toLowerCase(),"all"===n||0===t.indexOf(n))return i=!0,!1}),i};return t&&e.isPlainObject(r)&&(t=t.toLowerCase(),i=s(r.allow),a=s(r.deny),"allow"===r.firstOrder?(o=!1,a||i!==!0||(o=!0)):(o=!0,a!==!0||i||(o=!1))),o},sequence:function(e){var t=e.length,n=function(t,i){return++i,e[i]?n(t.then(e[i]),i):t};return t>1?n(e[0](),0):e[0]()},reloadContents:function(t){var n,i=e.Deferred();try{n=e('';d.remove(),e(x).appendTo("body").ready(function(){setTimeout(function(){e(x).each(function(){e("#"+e(this).attr("id")).remove()})},2e4+1e4*i)}),b.trigger("download",{files:y}),w.resolve()}),u=y.length,g=[],i=0;i');return t&&e.each(t,function(e,t){a=i.escape(t.value),o.append('")}),e.each(n.options.encodings,function(e,t){o.append('")}),o},d=function(){var t,a,o=i.options.dialogContained?i.getUI():e(window);return a="string"==typeof n.options.dialogWidth&&(t=n.options.dialogWidth.match(/(\d+)%/))?parseInt(o.width()*(t[1]/100)):parseInt(n.options.dialogWidth||650),Math.min(a,o.width())},p=function(){if(n.options.dialogHeight){var t,a,o=i.options.dialogContained?i.getUI():e(window);return a="string"==typeof n.options.dialogHeight&&(t=n.options.dialogHeight.match(/(\d+)%/))?parseInt(o.height()*(t[1]/100)):parseInt(n.options.dialogHeight||o.height()),Math.min(a,o.height())}},u=function(t){var a,l,c,d=t.length;return d>1&&(a=t[0].mime,l=t[0].name.replace(/^.*(\.[^.]+)$/,"$1")),e.grep(t,function(t){var p;return!c&&"directory"!==t.mime&&(p=t.read&&(s||i.mimeIsText(t.mime)||e.inArray(t.mime,1===d?o:r)!==-1)&&(!n.onlyMimes.length||e.inArray(t.mime,n.onlyMimes)!==-1)&&(1===d||t.mime===a&&t.name.substr(l.length*-1)===l)&&!!i.uploadMimeCheck(t.mime,t.phash)&&b(t,d)&&Object.keys(g).length,p||(c=!0),p)})},h=function(e){var t,n=i.file(e);i.request({cmd:"info",targets:[e],preventDefault:!0}).done(function(e){var a;e&&e.files&&e.files.length&&(t=e.files[0],n.ts==t.ts&&n.size==t.size||(a={changed:[t]},i.updateCache(a),i.change(a)))})},f=function(t,o,r,s,u,f){var g,v,b,y,w,k,C=e.Deferred(),z=!1,T=function(){return!!z||(i.toast({mode:"warning",msg:i.i18n("nowLoading")}),!1)},A=function(){f&&Array.isArray(f)&&e.each(f,function(){this.msg&&i.toast(this)})},j=function(){var t,n,a,o=y?y.val():void 0,r=e.Deferred().fail(function(e){b.show().find("button.elfinder-btncnt-0,button.elfinder-btncnt-1").hide()});return T()?(g.editor&&(g.editor.save(g[0],g.editor.instance),t=g.editor.confObj,t.info&&(t.info.schemeContent||t.info.arrayBufferContent)&&(o="scheme")),n=D(),U(n),n.promise?(a=setTimeout(function(){i.notify({type:"chkcontent",cnt:1,hideCnt:!0,cancel:function(){n.reject()}})},100),n.always(function(){a&&clearTimeout(a),i.notify({type:"chkcontent",cnt:-1})}).done(function(e){C.notifyWith(g,[o,g.data("hash"),v,r])}).fail(function(e){r.reject(e)})):C.notifyWith(g,[o,g.data("hash"),v,r]),r):r.resolve()},O=function(){T()&&j().fail(function(e){e&&i.error(e)})},S=function(){g.elfinderdialog("close")},I=function(){T()&&(b.hide(),j().done(function(){z=!1,b.show(),S()}).fail(function(e){b.show(),e&&i.error(e)}))},M=function(){if(T()){var t=v,r=o.phash,s=function(e){p.addClass(a).fadeIn(function(){e&&i.error(e)}),v=t,i.disable()},l=function(){n.mime=R.mime||o.mime,n.prefix=(R.name||o.name).replace(/ \d+(\.[^.]+)?$/,"$1"),n.requestCmd="mkfile",n.nextAction={},n.data={target:r},e.proxy(i.res("mixin","make"),n)().done(function(e){var t;e.added&&e.added.length?(t=g.data("hash"),g.data("hash",e.added[0].hash),j().done(function(){z=!1,b.show(),S(),p.fadeIn()}).fail(function(){i.exec("rm",[e.added[0].hash],{forceRm:!0,quiet:!0}),g.data("hash",t),b.find("button.elfinder-btncnt-2").hide(),s()})):s()}).progress(function(e){e&&"errUploadMime"===e&&g.trigger("saveAsFail")}).fail(s).always(function(){delete n.mime,delete n.prefix,delete n.nextAction,delete n.data}),i.trigger("unselectfiles",{files:[o.hash]})},c=null,d=null,p=i.getUI().children("."+n.dialogClass+":visible");b.is(":hidden")&&(p=p.add(b)),p.removeClass(a).fadeOut(),i.enable(),i.searchStatus.state<2&&r!==i.cwd().hash?c=i.exec("open",[r],{thash:r}):i.file(r)||(d=i.request({cmd:"info",targets:[r]})),e.when([c,d]).done(function(){d?i.one("infodone",function(){i.file(r)?l():s("errFolderNotFound")}):c?i.one("cwdrender",l):l()}).fail(s)}},E=function(){var t,n,a=e.Deferred();return z?(g.editor&&g.editor.save(g[0],g.editor.instance),t=D(),t&&t.promise?(n=setTimeout(function(){i.notify({type:"chkcontent",cnt:1,hideCnt:!0,cancel:function(){t.reject()}})},100),t.always(function(){n&&clearTimeout(n),i.notify({type:"chkcontent",cnt:-1})}).done(function(e){a.resolve(v!==e)}).fail(function(e){a.resolve(e||void 0!==v)})):a.resolve(v!==t),a):a.resolve(!1)},F={title:i.escape(o.name),width:d(),height:p(),buttons:{},cssClass:a,maxWidth:"window",maxHeight:"window",allowMinimize:!0,allowMaximize:!0,openMaximized:x()||u&&u.info&&u.info.openMaximized,btnHoverFocus:!1,closeOnEscape:!1,propagationEvents:["mousemove","mouseup","click"],minimize:function(){var e;g.editor&&b.closest(".ui-dialog").is(":hidden")&&(e=g.editor.confObj,e.info&&e.info.syncInterval&&h(o.hash))},close:function(){var e=function(){var e;C.resolve(),g.editor&&(g.editor.close(g[0],g.editor.instance),e=g.editor.confObj,e.info&&e.info.syncInterval&&h(o.hash)),g.elfinderdialog("destroy")},t="undefined"!=typeof R.name,a=t?{label:"btnSaveAs",callback:function(){requestAnimationFrame(M)}}:{label:"btnSaveClose",callback:function(){j().done(function(){e()})}};E().done(function(o){var r=["confirmNotSave"];o?("string"==typeof o&&r.unshift(o),i.confirm({title:n.title,text:r,accept:a,cancel:{label:"btnClose",callback:e},buttons:t?null:[{label:"btnSaveAs",callback:function(){requestAnimationFrame(M)}}]})):e()})},open:function(){var e,n,a;if(g.initEditArea.call(g,t,o,r,i),g.editor){if(e=g.editor.load(g[0])||null,e&&e.done)e.always(function(){z=!0}).done(function(e){g.editor.instance=e,g.editor.focus(g[0],g.editor.instance),U(D()),requestAnimationFrame(function(){b.trigger("resize")})}).fail(function(e){e&&i.error(e),g.elfinderdialog("destroy")}).always(A);else{if(z=!0,e&&("string"==typeof e||Array.isArray(e)))return i.error(e),void g.elfinderdialog("destroy");g.editor.instance=e,g.editor.focus(g[0],g.editor.instance),U(D()),requestAnimationFrame(function(){b.trigger("resize")}),A()}n=g.editor.confObj,n.info&&n.info.syncInterval&&(a=parseInt(n.info.syncInterval))&&setTimeout(function(){P(a)},a)}else z=!0,U(D())},resize:function(e,t){g.editor&&g.editor.resize(g[0],g.editor.instance,e,t||{})}},D=function(){var t=g.getContent.call(g,g[0]);return void 0!==t&&t!==!1&&null!==t||(t=e.Deferred().reject()),t},U=function(e){e&&e.promise?e.done(function(e){v=e}):v=e},P=function(e){b.is(":visible")&&(h(o.hash),setTimeout(function(){P(e)},e))},q=function(){y&&E().done(function(e){e?y.attr("title",i.i18n("saveAsEncoding")).addClass("elfinder-edit-changed"):y.attr("title",i.i18n("openAsEncoding")).removeClass("elfinder-edit-changed")})},R={};if(u&&(u.html&&(g=e(u.html)),w={init:u.init||null,load:u.load,getContent:u.getContent||null,save:u.save,beforeclose:"function"==typeof u.beforeclose?u.beforeclose:void 0,close:"function"==typeof u.close?u.close:function(){},focus:"function"==typeof u.focus?u.focus:function(){},resize:"function"==typeof u.resize?u.resize:function(){},instance:null,doSave:O,doCancel:S,doClose:I,file:o,fm:i,confObj:u,trigger:function(e,t){i.trigger("editEditor"+e,Object.assign({},u.info||{},t))}}),!g){if(!i.mimeIsText(o.mime))return C.reject("errEditorNotFound");!function(){g=e('').on("input propertychange",q),u&&u.info&&!u.info.useTextAreaEvent||g.on("keydown",function(t){var n,i,a=t.keyCode;t.stopPropagation(),a==e.ui.keyCode.TAB&&(t.preventDefault(),this.setSelectionRange&&(n=this.value,i=this.selectionStart,this.value=n.substr(0,i)+"\t"+n.substr(this.selectionEnd),i+=1,this.setSelectionRange(i,i))),(t.ctrlKey||t.metaKey)&&(a!="Q".charCodeAt(0)&&a!="W".charCodeAt(0)||(t.preventDefault(),S()),a=="S".charCodeAt(0)&&(t.preventDefault(),O()))}).on("mouseenter",function(){this.focus()}),g.initEditArea=function(e,t,n){g.hide().val(n),this._setupSelEncoding(n)}}()}return g._setupSelEncoding=function(t){var n=s&&"unknown"!==s?[{value:s}]:[],a=e("").hide(),r=function(t){t&&a.appendTo(y.parent()),a.empty().append(e("").text(y.val())),y.width(a.width())};""!==t&&s&&"UTF-8"===s||n.push({value:"UTF-8"}),y=c(n).on("touchstart",function(e){e.stopPropagation()}).on("change",function(){E().done(function(e){e||""===D()||(S(),m(o,y.val(),u).fail(function(e){e&&i.error(e)}))}),r()}).on("mouseover",q),g.parent().next().prepend(e('
').append(y)),r(!0)},g.data("hash",o.hash),w&&(g.editor=w,"function"==typeof w.beforeclose&&(F.beforeclose=function(){return w.beforeclose(g[0],w.instance)}),"function"==typeof w.init&&(g.initEditArea=w.init),"function"==typeof w.getContent&&(g.getContent=w.getContent)),g.initEditArea||(g.initEditArea=function(){}),g.getContent||(g.getContent=function(){return l(g.val())}),u&&u.info&&u.info.preventGet||(F.buttons[i.i18n("btnSave")]=O,F.buttons[i.i18n("btnSaveClose")]=I,F.buttons[i.i18n("btnSaveAs")]=M,F.buttons[i.i18n("btnCancel")]=S),u&&"function"==typeof u.prepare&&u.prepare(g,F,o),b=n.fmDialog(g,F).attr("id",t).on("keydown keyup keypress",function(e){e.stopPropagation()}).css({overflow:"hidden",minHeight:"7em"}).addClass("elfinder-edit-editor").closest(".ui-dialog").on("changeType",function(t,n){if(n.extention&&n.mime){var a=(n.extention,n.mime,e(this).children(".ui-dialog-buttonpane").children(".ui-dialog-buttonset"));a.children(".elfinder-btncnt-0,.elfinder-btncnt-1").hide(),R.name=i.splitFileExtention(o.name)[0]+"."+n.extention,R.mime=n.mime,n.keepEditor||a.children(".elfinder-btncnt-2").trigger("click")}}),k=(i.options.dialogContained?i.getUI():e(window)).width(),b.width()>k&&b.width(k),C.promise()},m=function(t,a,o){var r,s,l,d=t.hash,p=(i.options,e.Deferred()),u="edit-"+i.namespace+"-"+t.hash,h=i.getUI().find("#"+u),g=a?a:0,v=!1;if(h.length)return h.elfinderdialog("toTop"),p.resolve();if(!(t.read&&(t.write||o.info&&o.info.converter)))return s=["errOpen",t.name,"errPerm"],p.reject(s);if(o&&o.info){if("function"==typeof o.info.edit)return l=o.info.edit.call(i,t,o),l.promise?l.done(function(){p.resolve()}).fail(function(e){p.reject(e)}):l?p.resolve():p.reject(),p;v=o.info.preventGet||o.info.noContent,o.info.urlAsContent||v?(r=e.Deferred(),o.info.urlAsContent?i.url(d,{async:!0,onetime:!0,temporary:!0}).done(function(e){r.resolve({content:e})}):r.resolve({})):(g&&(t.encoding=g,i.cache(t,"change")),r=i.request({data:{cmd:"get",target:d,conv:g,_t:t.ts},options:{type:"get",cache:!0},notify:{type:"file",cnt:1},preventDefault:!0})),r.done(function(a){var r,s,l;a.doconv?i.confirm({title:n.title,text:"unknown"===a.doconv?"confirmNonUTF8":"confirmConvUTF8",accept:{label:"btnConv",callback:function(){p=m(t,r.val(),o)}},cancel:{label:"btnCancel",callback:function(){p.reject()}},optionsCallback:function(t){t.create=function(){var t=e('
'),n={value:a.doconv};"unknown"===a.doconv&&(n.caption="-"),r=c([n]),e(this).next().find(".ui-dialog-buttonset").prepend(t.append(e("").append(r)))}}}):(!v&&i.mimeIsText(t.mime)&&(s=new RegExp("^(data:"+t.mime.replace(/([.+])/g,"\\$1")+";base64,)","i"),o.info.dataScheme?window.btoa&&!a.content.match(s)&&(a.content="data:"+t.mime+";base64,"+btoa(a.content)):window.atob&&(l=a.content.match(s))&&(a.content=atob(a.content.substr(l[1].length)))),f(u,t,a.content,a.encoding,o,a.toasts).done(function(e){p.resolve(e)}).progress(function(e,t,n,a){var o=this;t&&(d=t),i.request({options:{type:"post"},data:{cmd:"put",target:d,encoding:e||n.encoding,content:n},notify:{type:"save",cnt:1},syncOnFail:!0,preventFail:!0,navigate:{target:"changed",toast:{inbuffer:{msg:i.i18n(["complete",i.i18n("btnSave")])}}}}).fail(function(e){p.reject(e),a.reject()}).done(function(e){requestAnimationFrame(function(){o.trigger("focus"),o.editor&&o.editor.focus(o[0],o.editor.instance)}),a.resolve()})}).fail(function(e){p.reject(e)}))}).fail(function(e){var n=i.parseError(e);n=Array.isArray(n)?n[0]:n,t.encoding&&(t.encoding="",i.cache(t,"change")),"errConvUTF8"!==n&&i.sync(),p.reject(e)})}return p.promise()},g={},v={info:{id:"textarea",name:"TextArea",useTextAreaEvent:!0},load:function(t){this.trigger("Prepare",{node:t,editorObj:void 0,instance:void 0,opts:{}}),t.setSelectionRange&&t.setSelectionRange(0,0),e(t).trigger("focus").show()},save:function(){}},b=function(a,o){var r=function(t,n){if(n){if("*"===n[0]||e.inArray(t,n)!==-1)return!0;var a,o;for(o=n.length,a=0;a0||!t.info.converter&&t.info.canMakeEmpty!==!1&&i.mimesCanMakeEmpty[a.mime])&&(!t.info.maxSize||a.size<=t.info.maxSize)&&r(a.mime,t.mimes||null)&&s(a.name,t.exts||null)&&"function"==typeof t.load&&"function"==typeof t.save&&(n=t.info.name?t.info.name:"Editor "+e,t.id=t.info.id?t.info.id:"editor"+e,t.name=n,t.i18n=i.i18n(n),g[t.id]=t)}),!!Object.keys(g).length},y=function(n,a){n&&a&&(e.isPlainObject(t)||(t={}),t[n]=a.id,i.storage("storedEditors",t),i.trigger("selectfiles",{files:i.selected()}))},w=function(){var e=i.storage("useStoredEditor");return e?e>0:n.options.useStoredEditor},x=function(){var e=i.storage("editorMaximized");return e?e>0:n.options.editorMaximized},k=function(t,n){var a=[];return e.each(g,function(e,o){a.push({label:i.escape(o.i18n),icon:o.info&&o.info.icon?o.info.icon:"edit",options:{iconImg:o.info&&o.info.iconImg?i.baseUrl+o.info.iconImg:void 0},callback:function(){y(t[0].mime,o),n&&n.call(o)}})}),a},C=function(e){return e.toLowerCase().replace(/ +/g,"")},z=function(e){var n=t[e];return n&&Object.keys(g).length?g[C(n)]:void 0};this.getEncSelect=c,this.shortcuts=[{pattern:"ctrl+e"}],this.init=function(){var t,n,i=this,a=this.fm,l=this.options,c=[];this.onlyMimes=this.options.mimes||[],a.one("open",function(){l.editors&&Array.isArray(l.editors)&&(a.trigger("canMakeEmptyFile",{mimes:Object.keys(a.storage("mkfileTextMimes")||{}).concat(l.makeTextMimes||["text/plain"])}),e.each(l.editors,function(e,t){t.info&&t.info.cmdCheck&&c.push(t.info.cmdCheck)}),c.length?a.api>=2.103?n=a.request({data:{cmd:"editor",name:c,method:"enabled"},preventDefault:!0}).done(function(e){t=e}).fail(function(){t={}}):(t={},n=e.Deferred().resolve()):n=e.Deferred().resolve(),n.always(function(){t&&(l.editors=e.grep(l.editors,function(e){return!e.info||!e.info.cmdCheck||!!t[e.info.cmdCheck]})),e.each(l.editors,function(e,t){t.setup&&"function"==typeof t.setup&&t.setup.call(t,l,a),t.disabled||(t.mimes&&Array.isArray(t.mimes)&&(o=o.concat(t.mimes),t.info&&t.info.single||(r=r.concat(t.mimes))),!s&&t.mimes&&"*"===t.mimes[0]&&(s=!0),t.info||(t.info={}),t.info.integrate&&a.trigger("helpIntegration",Object.assign({cmd:"edit"},t.info.integrate)),t.info.canMakeEmpty&&a.trigger("canMakeEmptyFile",{mimes:Array.isArray(t.info.canMakeEmpty)?t.info.canMakeEmpty:t.mimes}))}),o=(e.uniqueSort||e.unique)(o),r=(e.uniqueSort||e.unique)(r),l.editors=e.grep(l.editors,function(e){return!e.disabled})}))}).bind("select",function(){g=null}).bind("contextmenucreate",function(t){var n,o,r=function(e){var t=i.title;a.one("contextmenucreatedone",function(){i.title=t}),i.title=a.escape(e.i18n),e.info&&e.info.iconImg&&(i.contextmenuOpts={iconImg:a.baseUrl+e.info.iconImg}),delete i.variants};i.contextmenuOpts=void 0,"files"===t.data.type&&i.enabled()&&(n=a.file(t.data.targets[0]),b(n,t.data.targets.length)&&(Object.keys(g).length>1?w()&&(o=z(n.mime))?(r(o),i.extra={icon:"menu",node:e("").attr({title:a.i18n("select")}).on("click touchstart",function(t){if(!("touchstart"===t.type&&t.originalEvent.touches.length>1)){var n=e(this);t.stopPropagation(),t.preventDefault(),a.trigger("contextmenu",{raw:k(a.selectedFiles(),function(){var e=a.selected();a.exec("edit",e,{editor:this}),a.trigger("selectfiles",{files:e})}),x:n.offset().left,y:n.offset().top})}})}):(delete i.extra,i.variants=[],e.each(g,function(e,t){i.variants.push([{editor:t},t.i18n,t.info&&t.info.iconImg?a.baseUrl+t.info.iconImg:"edit"])})):(r(g[Object.keys(g)[0]]),delete i.extra)))}).bind("canMakeEmptyFile",function(t){if(t.data&&t.data.resetTexts){var n=a.arrayFlip(i.options.makeTextMimes||["text/plain"]),o=i.getMkfileHides();e.each(a.storage("mkfileTextMimes")||{},function(e,t){n[e]||(delete a.mimesCanMakeEmpty[e],delete o[e])}),a.storage("mkfileTextMimes",null),Object.keys(o).length?a.storage("mkfileHides",o):a.storage("mkfileHides",null)}})},this.getstate=function(e){var t=this.files(e),n=t.length;return n&&u(t).length==n?0:-1},this.exec=function(t,n){var i,a=this.fm,o=u(this.files(t)),r=e.map(o,function(e){return e.hash}),s=[],l=n&&n.editor?n.editor:null,c=e(n&&n._currentNode?n._currentNode:a.cwdHash2Elm(r[0])),d=function(){var t=e.Deferred();return!l&&Object.keys(g).length>1?w()&&(l=z(o[0].mime))?t.resolve(l):(a.trigger("contextmenu",{raw:k(o,function(){t.resolve(this)}),x:c.offset().left,y:c.offset().top+22,opened:function(){a.one("closecontextmenu",function(){requestAnimationFrame(function(){"pending"===t.state()&&t.reject()})})}}),a.trigger("selectfiles",{files:r}),t):(Object.keys(g).length>1&&l&&y(o[0].mime,l),t.resolve(l?l:Object.keys(g).length?g[Object.keys(g)[0]]:null))},p=e.Deferred();return null===g&&b(o[0],r.length),c.length||(c=a.getUI("cwd")),d().done(function(t){for(;i=o.shift();)s.push(m(i,i.encoding||void 0,t).fail(function(e){e&&a.error(e)}));s.length?e.when.apply(null,s).done(function(){p.resolve()}).fail(function(){p.reject()}):p.reject()}).fail(function(){p.reject()}),p},this.getMkfileHides=function(){return i.storage("mkfileHides")||i.arrayFlip(n.options.mkfileHideMimes||[])}},i.prototype.commands.empty=function(){var t,n,i=function(e){var i=t.files(e);return i.length||(i=[n.cwd()]),i};this.linkedCmds=["rm"],this.init=function(){t=this,n=this.fm},this.getstate=function(t){var n,a=i(t);return n=a.length,e.grep(a,function(e){return!(!e.read||!e.write||"directory"!==e.mime)}).length==n?0:-1},this.exec=function(t){var a=i(t),o=a.length,r=e.Deferred().done(function(){var t={changed:{}};n.toast({msg:n.i18n(['"'+s.join('", ')+'"',"complete",n.i18n("cmdempty")])}),e.each(a,function(e,n){t.changed[n.hash]=n}),n.change(t)}).always(function(){var t=n.cwd().hash;n.trigger("selectfiles",{files:e.map(a,function(e){return t===e.phash?e.hash:null})})}),s=[],l=function(e){"number"==typeof e?(s.push(a[e].name),delete a[e].dirs):e&&n.error(e),--o<1&&r[s.length?"resolve":"reject"]()};return e.each(a,function(t,i){var a;return i.write&&"directory"===i.mime?n.isCommandEnabled("rm",i.hash)?(a=setTimeout(function(){n.notify({type:"search",cnt:1,hideCnt:!(o>1)})},n.notifyDelay),void n.request({data:{cmd:"open",target:i.hash},preventDefault:!0,asNotOpen:!0}).done(function(r){var s=[];a&&clearTimeout(a),n.ui.notify.children(".elfinder-notify-search").length&&n.notify({type:"search",cnt:-1,hideCnt:!(o>1)}),r&&r.files&&r.files.length?r.files.length>n.maxTargets?l(["errEmpty",i.name,"errMaxTargets",n.maxTargets]):(n.updateCache(r),e.each(r.files,function(e,t){return!t.write||t.locked?(l(["errEmpty",i.name,"errRm",t.name,"errPerm"]),s=[],!1):void s.push(t.hash)}),s.length&&n.exec("rm",s,{_userAction:!0,addTexts:[n.i18n("folderToEmpty",i.name)]}).fail(function(e){n.trigger("unselectfiles",{files:n.selected()}),l(n.parseError(e)||"")}).done(function(){l(t)})):(n.toast({mode:"warning",msg:n.i18n("filderIsEmpty",i.name)}),l(""))}).fail(function(e){l(n.parseError(e)||"")})):(l(["errCmdNoSupport",'"rm"']),null):(l(["errEmpty",i.name,"errPerm"]),null)}),r}},i.prototype.commands.extract=function(){var t=this,n=t.fm,i=[],a=function(t){return e.grep(t,function(t){return!(!t.read||e.inArray(t.mime,i)===-1)})};this.variants=[],this.disableOnSearch=!0,n.bind("open reload",function(){i=n.option("archivers").extract||[],n.api>2?t.variants=[[{makedir:!0},n.i18n("cmdmkdir")],[{},n.i18n("btnCwd")]]:t.variants=[[{},n.i18n("btnCwd")]],t.change()}),this.getstate=function(e){var t=this.files(e),n=t.length;return n&&this.fm.cwd().write&&a(t).length==n?0:-1},this.exec=function(t,a){var o,r,s,l=this.files(t),c=e.Deferred(),d=l.length,p=a&&a.makedir?1:0,u=!1,h=!1,f=0,m=e.map(n.files(t),function(e){return e.name}),g={};e.grep(n.files(t),function(e){return g[e.name]=e,!1});var v=function(e){switch(e){case"overwrite_all":u=!0;break;case"omit_all":h=!0}},b=function(t){t.read&&n.file(t.phash).write?e.inArray(t.mime,i)===-1?(r=["errExtract",t.name,"errNoArchive"],n.error(r),c.reject(r)):n.request({data:{cmd:"extract",target:t.hash,makedir:p},notify:{type:"extract",cnt:1},syncOnFail:!0,navigate:{toast:p?{incwd:{msg:n.i18n(["complete",n.i18n("cmdextract")]),action:{cmd:"open",msg:"cmdopen"}},inbuffer:{msg:n.i18n(["complete",n.i18n("cmdextract")]),action:{cmd:"open",msg:"cmdopen"}}}:{inbuffer:{msg:n.i18n(["complete",n.i18n("cmdextract")])}}}}).fail(function(e){"rejected"!=c.state()&&c.reject(e)}).done(function(){}):(r=["errExtract",t.name,"errPerm"],n.error(r),c.reject(r))},y=function(t,i){var a=t[i],r=n.splitFileExtention(a.name)[0],l=e.inArray(r,m)>=0,w=function(){i+10&&b(a),w())};return this.enabled()&&d&&i.length?(d>0&&y(l,0),c):c.reject()}},(i.prototype.commands.forward=function(){this.alwaysEnabled=!0,this.updateOnSelect=!0,this.shortcuts=[{pattern:"ctrl+right"}],this.getstate=function(){return this.fm.history.canForward()?0:-1},this.exec=function(){return this.fm.history.forward()}}).prototype={forceLoad:!0},i.prototype.commands.fullscreen=function(){var t=this,n=this.fm,i=function(e,n){e.preventDefault(),e.stopPropagation(),n&&n.fullscreen&&t.update(void 0,"on"===n.fullscreen)};this.alwaysEnabled=!0,this.updateOnSelect=!1,this.syncTitleOnChange=!0,this.value=!1,this.options={ui:"fullscreenbutton"},this.getstate=function(){return 0},this.exec=function(){var i=n.getUI().get(0),a=i===n.toggleFullscreen(i);return t.title=n.i18n(a?"reinstate":"cmdfullscreen"),t.update(void 0,a),e.Deferred().resolve()},n.bind("init",function(){n.getUI().off("resize."+n.namespace,i).on("resize."+n.namespace,i)})},(i.prototype.commands.getfile=function(){var t=this,n=this.fm,i=function(n){var i=t.options;return n=e.grep(n,function(e){return!("directory"==e.mime&&!i.folders||!e.read)}),i.multiple||1==n.length?n:[]};this.alwaysEnabled=!0,this.callback=n.options.getFileCallback,this._disabled="function"==typeof this.callback,this.getstate=function(e){var t=this.files(e),n=t.length;return this.callback&&n&&i(t).length==n?0:-1},this.exec=function(n){var i,a,o,r=this.fm,s=this.options,l=this.files(n),c=l.length,d=r.option("url"),p=r.option("tmbUrl"),u=e.Deferred().done(function(e){var n,i=function(){"close"==s.oncomplete?r.hide():"destroy"==s.oncomplete&&r.destroy()},a=function(e){"close"==s.onerror?r.hide():"destroy"==s.onerror?r.destroy():e&&r.error(e)};r.trigger("getfile",{files:e});try{n=t.callback(e,r)}catch(o){return void a(["Error in `getFileCallback`.",o.message])}"object"==typeof n&&"function"==typeof n.done?n.done(i).fail(a):i()}),h=function(t){return s.onlyURL?s.multiple?e.map(l,function(e){return e.url}):l[0].url:s.multiple?l:l[0]},f=[];for(i=0;i {link}',d='
{author}
{work}
',p=/\{url\}/,u=/\{link\}/,h=/\{author\}/,f=/\{work\}/,m="replace",g="ui-priority-primary",v="ui-priority-secondary",b="elfinder-help-license",y='
  • {title}
  • ',w=['
    ','
      '],x='
      {pattern}
      {descrip}
      ',k='
      ',C=e("base").length?document.location.href.replace(/#.*$/,""):"",z=s.res("class","tabsactive"),T=function(){var e;return e=s.theme&&s.theme.author?d[m]("elfinder-help-team","elfinder-help-team elfinder-help-term-theme")[m](h,s.i18n(s.theme.author)+(s.theme.email?" <"+s.theme.email+">":""))[m](f,s.i18n("theme")+" ("+s.i18n(s.theme.name)+")"):''},A=function(){w.push('
      '),w.push("

      elFinder

      "),w.push('
      '+s.i18n("webfm")+"
      "),w.push('
      '+s.i18n("ver")+": "+s.version+"
      "),w.push('
      '+s.i18n("protocolver")+':
      '),w.push('
      jQuery/jQuery UI: '+e().jquery+"/"+e.ui.version+"
      "),w.push(k),w.push(c[m](p,"https://studio-42.github.io/elFinder/")[m](u,s.i18n("homepage"))),w.push(c[m](p,"https://github.com/Studio-42/elFinder/wiki")[m](u,s.i18n("docs"))),w.push(c[m](p,"https://github.com/Studio-42/elFinder")[m](u,s.i18n("github"))),w.push(k),w.push('
      '+s.i18n("team")+"
      "),w.push(d[m](h,'Dmitry "dio" Levashov <dio@std42.ru>')[m](f,s.i18n("chiefdev"))),w.push(d[m](h,"Naoki Sawada <hypweb+elfinder@gmail.com>")[m](f,s.i18n("developer"))),w.push(d[m](h,"Troex Nevelin <troex@fury.scancode.ru>")[m](f,s.i18n("maintainer"))),w.push(d[m](h,"Alexey Sukhotin <strogg@yandex.ru>")[m](f,s.i18n("contributor"))),s.i18[s.lang].translator&&e.each(s.i18[s.lang].translator.split(", "),function(){w.push(d[m](h,e.trim(this))[m](f,s.i18n("translator")+" ("+s.i18[s.lang].language+")"))}),w.push(T()),w.push(k),w.push('
      '+s.i18n("icons")+': Pixelmixer, Fugue, Icons8
      '),w.push(k),w.push('
      Licence: 3-clauses BSD Licence
      '),w.push('
      Copyright © 2009-2020, Studio 42
      '),w.push('
      „ …'+s.i18n("dontforget")+" ”
      "),w.push("
      ")},j=function(){var t=s.shortcuts();w.push('
      '),t.length?(w.push('
      '),e.each(t,function(e,t){w.push(x.replace(/\{pattern\}/,t[0]).replace(/\{descrip\}/,t[1]))}),w.push("
      ")):w.push('
      '+s.i18n("shortcutsof")+"
      "),w.push("
      ")},O=function(){w.push('
      '),w.push('DON\'T PANIC'),w.push("
      ")},S=!1,I=function(){S=!0,w.push('
      ')},M=!1,E=function(){M=!0,w.push('
      '),w.push('
        '),w.push("
        ")},F=function(){var n,i,a,c,d,p,u=function(t,n){return e.each(n,function(n,i){t.append(e("
        ").text(n)),"undefined"==typeof i?t.append(e("
        ").append(e("").text("undfined"))):"object"!=typeof i||i?"object"==typeof i&&(e.isPlainObject(i)||i.length)?t.append(e("
        ").append(u(e("
        "),i))):t.append(e("
        ").append(e("").text(i&&"object"==typeof i?"[]":i?i:'""'))):t.append(e("
        ").append(e("").text("null")))}),t},h=r.children("li").length;(l.debug.options||l.debug.debug)&&(h>=5&&(d=r.children("li:last"),p=o.children("div:last"),p.is(":hidden")?(d.remove(),p.remove()):(d.prev().remove(),p.prev().remove())),a=s.namespace+"-help-debug-"+ +new Date,n=e("
      • ").html(''+l.debug.debug.cmd+"").prependTo(r),i=e('
        ').data("debug",l.debug),n.on("click.debugrender",function(){var t=i.data("debug");i.removeData("debug"),t&&(i.hide(),t.debug&&(c=e("
        ").append(e("").text("debug"),u(e("
        "),t.debug)),i.append(c)),t.options&&(c=e("
        ").append(e("").text("options"),u(e("
        "),t.options)),i.append(c)),i.show()),n.off("click.debugrender")}),r.after(i),t&&o.tabs("refresh"))},D="";this.alwaysEnabled=!0,this.updateOnSelect=!1,this.state=-1,this.shortcuts=[{pattern:"f1",description:this.title}],s.bind("load",function(){var c,d,p,u,h,f,g=l.options.view||["about","shortcuts","help","integrations","debug"];(c=e.inArray("preference",g))!==-1&&g.splice(c,1),e.fn.tabs||(c=e.inArray(g,"debug"))!==-1&&g.splice(c,1),e.each(g,function(e,t){w.push(y[m](/\{id\}/g,t)[m](/\{title\}/,s.i18n(t)))}),w.push("
      "),e.inArray("about",g)!==-1&&A(), +e.inArray("shortcuts",g)!==-1&&j(),e.inArray("help",g)!==-1&&(d=s.i18nBaseUrl+"help/%s.html.js",O()),e.inArray("integrations",g)!==-1&&I(),e.inArray("debug",g)!==-1&&E(),w.push("
      "),D=e(w.join("")),D.find(".ui-tabs-nav li").on("mouseenter mouseleave",function(t){e(this).toggleClass("ui-state-hover","mouseenter"===t.type)}).on("focus blur","a",function(t){e(t.delegateTarget).toggleClass("ui-state-focus","focusin"===t.type)}).children().on("click",function(t){var n=e(this);t.preventDefault(),t.stopPropagation(),n.parent().addClass(z).siblings().removeClass(z),D.children(".ui-tabs-panel").hide().filter(n.attr("href")).show()}).filter(":first").trigger("click"),S&&(n=D.find(".elfinder-help-tab-integrations").hide(),i=D.find("#"+s.namespace+"-help-integrations").hide().append(e('
      ').html(s.i18n("integrationWith"))),s.bind("helpIntegration",function(t){var a,o,r,l,c=i.children("ul:first");t.data&&(e.isPlainObject(t.data)?(a=Object.assign({link:"",title:"",banner:""},t.data),(a.title||a.link)&&(a.title||(a.title=a.link),o=a.link?e("").attr("href",a.link).attr("target","_blank").text(a.title):e("").text(a.title),a.banner&&(o=e("").append(e("").attr(a.banner),o)))):(o=e(t.data),o.filter("a").each(function(){var t=e(this);t.attr("target")||t.attr("target","_blank")})),o&&(n.show(),c.length||(c=e('
        ').appendTo(i)),a&&a.cmd?(l="elfinder-help-integration-"+a.cmd,r=c.find("ul."+l),r.length||(r=e('
          '),c.append(e("
        • ").append(e("").html(s.i18n("cmd"+a.cmd))).append(r))),o=r.append(e("
        • ").append(o))):c.append(e("
        • ").append(o))))}).bind("themechange",function(){D.find("div.elfinder-help-term-theme").replaceWith(T())})),M&&(a=D.find(".elfinder-help-tab-debug").hide(),o=D.find("#"+s.namespace+"-help-debug").children("div:first"),r=o.children("ul:first").on("click",function(e){e.preventDefault(),e.stopPropagation()}),l.debug={},s.bind("backenddebug",function(e){M&&e.data&&e.data.debug&&(l.debug={options:e.data.options,debug:Object.assign({cmd:s.currentReqCmd},e.data.debug)},l.dialog&&F())})),D.find("#"+s.namespace+"-help-about").find(".apiver").text(s.api),l.dialog=l.fmDialog(D,{title:l.title,width:530,maxWidth:"window",maxHeight:"window",autoOpen:!1,destroyOnClose:!1,close:function(){M&&(a.hide(),o.tabs("destroy")),t=!1}}).on("click",function(e){e.stopPropagation()}).css({overflow:"hidden"}),p=l.dialog.children(".ui-tabs"),u=p.children(".ui-tabs-nav:first"),h=p.children(".ui-tabs-panel"),f=l.dialog.outerHeight(!0)-l.dialog.height(),l.dialog.closest(".ui-dialog").on("resize",function(){h.height(l.dialog.height()-f-u.outerHeight(!0)-20)}),d&&l.dialog.one("initContents",function(){e.ajax({url:l.options.helpSource?l.options.helpSource:d.replace("%s",s.lang),dataType:"html"}).done(function(t){e("#"+s.namespace+"-help-help").html(t)}).fail(function(){e.ajax({url:d.replace("%s","en"),dataType:"html"}).done(function(t){e("#"+s.namespace+"-help-help").html(t)})})}),l.state=0,s.trigger("helpBuilded",l.dialog)}).one("open",function(){var e=!1;s.one("backenddebug",function(){e=!0}).one("opendone",function(){requestAnimationFrame(function(){!e&&M&&(M=!1,a.hide(),o.hide(),r.hide())})})}),this.getstate=function(){return 0},this.exec=function(n,i){var s=i?i.tab:void 0,l=function(){M&&(o.tabs(),r.find("a:first").trigger("click"),a.show(),t=!0)};return l(),this.dialog.trigger("initContents").elfinderdialog("open").find((s?".elfinder-help-tab-"+s:".ui-tabs-nav li")+" a:first").trigger("click"),e.Deferred().resolve()}}).prototype={forceLoad:!0},i.prototype.commands.hidden=function(){this.hidden=!0,this.updateOnSelect=!1,this.getstate=function(){return-1}},i.prototype.commands.hide=function(){var t,n,i,a,o=this,r={};this.syncTitleOnChange=!0,this.shortcuts=[{pattern:"ctrl+shift+dot",description:this.fm.i18n("toggleHidden")}],this.init=function(){var e=this.fm;t=e.storage("hide")||{items:{}},n=Object.keys(t.items).length,this.title=e.i18n(t.show?"hideHidden":"showHidden"),o.update(void 0,o.title)},this.fm.bind("select contextmenucreate closecontextmenu",function(e,r){var s=(e.data?e.data.selected||e.data.targets:null)||r.selected();"select"===e.type&&e.data?a=e.data.origin:"contextmenucreate"===e.type&&(i=e.data.type),!s.length||("contextmenucreate"!==e.type&&"navbar"!==a||"cwd"===i)&&s[0]===r.cwd().hash?o.title=r.i18n(t.show?"hideHidden":"showHidden"):o.title=r.i18n("cmdhide"),"closecontextmenu"!==e.type?o.update("cwd"===i?n?0:-1:void 0,o.title):(i="",requestAnimationFrame(function(){o.update(void 0,o.title)}))}),this.getstate=function(e){return this.fm.cookieEnabled&&"cwd"!==i&&(e||this.fm.selected()).length||n?0:-1},this.exec=function(i,s){var l,c,d=this.fm,p=e.Deferred().done(function(){d.trigger("hide",{items:h,opts:s})}).fail(function(e){d.error(e)}),u=s||{},h=u.targets?u.targets:i||d.selected(),f=[];if(t=d.storage("hide")||{},e.isPlainObject(t)||(t={}),e.isPlainObject(t.items)||(t.items={}),("shortcut"===s._currentType||!h.length||"navbar"!==s._currentType&&"navbar"!==a&&h[0]===d.cwd().hash)&&(t.show?u.hide=!0:Object.keys(t.items).length&&(u.show=!0)),u.reset&&(u.show=!0,n=0),u.show||u.hide){if(u.show?t.show=!0:delete t.show,u.show)return d.storage("hide",u.reset?null:t),o.title=d.i18n("hideHidden"),o.update(u.reset?-1:void 0,o.title),e.each(t.items,function(e){var t=d.file(e,!0);t&&(d.searchStatus.state||!t.phash||d.file(t.phash))&&f.push(t)}),f.length&&(d.updateCache({added:f}),d.add({added:f})),u.reset&&(t={items:{}}),p.resolve();h=Object.keys(t.items)}return h.length&&(e.each(h,function(e,n){var i;t.items[n]||(i=d.file(n),i&&(r[n]=i.i18||i.name),t.items[n]=r[n]?r[n]:n)}),n=Object.keys(t.items).length,l=this.files(h),d.storage("hide",t),d.remove({removed:h}),t.show&&this.exec(void 0,{hide:!0}),u.hide||(c={},c.undo={cmd:"hide",callback:function(){var t=d.storage("hide");t&&(e.each(h,function(e,n){delete t.items[n]}),n=Object.keys(t.items).length,d.storage("hide",t),d.trigger("hide",{items:h,opts:{}}),o.update(n?0:-1)),d.updateCache({added:l}),d.add({added:l})}},c.redo={cmd:"hide",callback:function(){return d.exec("hide",void 0,{targets:h})}})),"rejected"==p.state()?p:p.resolve(c)}},(i.prototype.commands.home=function(){this.title="Home",this.alwaysEnabled=!0,this.updateOnSelect=!1,this.shortcuts=[{pattern:"ctrl+home ctrl+shift+up",description:"Home"}],this.getstate=function(){var e=this.fm.root(),t=this.fm.cwd().hash;return e&&t&&e!=t?0:-1},this.exec=function(){return this.fm.exec("open",this.fm.root())}}).prototype={forceLoad:!0},(i.prototype.commands.info=function(){var t=this.fm,n="elfinder-spinner",i="elfinder-info-button",a={calc:t.i18n("calc"),size:t.i18n("size"),unknown:t.i18n("unknown"),path:t.i18n("path"),aliasfor:t.i18n("aliasfor"),modify:t.i18n("modify"),perms:t.i18n("perms"),locked:t.i18n("locked"),dim:t.i18n("dim"),kind:t.i18n("kind"),files:t.i18n("files"),folders:t.i18n("folders"),roots:t.i18n("volumeRoots"),items:t.i18n("items"),yes:t.i18n("yes"),no:t.i18n("no"),link:t.i18n("link"),owner:t.i18n("owner"),group:t.i18n("group"),perm:t.i18n("perm"),getlink:t.i18n("getLink")},o=function(e,t){return t?e.replace(/\u200B/g,""):e.replace(/(\/|\\)/g,"$1​")};this.items=["size","aliasfor","path","link","dim","modify","perms","locked","owner","group","perm"],this.options.custom&&Object.keys(this.options.custom).length&&e.each(this.options.custom,function(e,t){t.label&&this.items.push(t.label)}),this.tpl={main:'
          {title}
          {content}
          ',itemTitle:'{name}{kind}',groupTitle:"{items}: {num}",row:'{label} : {value}',spinner:'{text} '},this.alwaysEnabled=!0,this.updateOnSelect=!1,this.shortcuts=[{pattern:"ctrl+i"}],this.init=function(){e.each(a,function(e,n){a[e]=t.i18n(n)})},this.getstate=function(){return 0},this.exec=function(t){var r=this.files(t);r.length||(r=this.files([this.fm.cwd().hash]));var s,l,c,d,p,u,h,f,m,g=this,v=this.fm,b=this.options,y=this.tpl,w=y.row,x=r.length,k=[],C=y.main,z="{label}",T="{value}",A=[],j=null,O={title:v.i18n("selectionInfo"),width:"auto",close:function(){e(this).elfinderdialog("destroy"),j&&"pending"===j.state()&&j.reject(),e.grep(A,function(e){e&&"pending"===e.state()&&e.reject()})}},S=[],I=function(e,t,i){E.find("."+n+"-"+t).parent().html(e).addClass(i||"")},M=v.namespace+"-info-"+e.map(r,function(e){return e.hash}).join("-"),E=v.getUI().find("#"+M),F=[],D="",U="elfinder-font-mono elfinder-info-hash",P=[],q=v.ui.notify;if(q.is(":hidden")&&q.children(".elfinder-notify").length&&q.elfinderdialog("open").height("auto"),!x)return e.Deferred().reject();if(E.length)return E.elfinderdialog("toTop"),e.Deferred().resolve();if(f=v.storage("infohides")||v.arrayFlip(b.hideItems,!0),1===x){if(c=r[0],c.icon&&(D=" "+v.getIconStyle(c)),C=C.replace("{dirclass}",c.csscls?v.escape(c.csscls):"").replace("{class}",v.mime2class(c.mime)).replace("{style}",D),d=y.itemTitle.replace("{name}",v.escape(c.i18||c.name)).replace("{kind}",''+v.mime2kind(c)+""),l=v.tmb(c),c.read?"directory"!=c.mime||c.alias?s=v.formatSize(c.size):(s=y.spinner.replace("{text}",a.calc).replace("{name}","size"),S.push(c.hash)):s=a.unknown,!f.size&&k.push(w.replace(z,a.size).replace(T,s)),!f.aleasfor&&c.alias&&k.push(w.replace(z,a.aliasfor).replace(T,c.alias)),f.path||((h=v.path(c.hash,!0))?k.push(w.replace(z,a.path).replace(T,o(v.escape(h))).replace("{class}","elfinder-info-path")):(k.push(w.replace(z,a.path).replace(T,y.spinner.replace("{text}",a.calc).replace("{name}","path")).replace("{class}","elfinder-info-path")),A.push(v.path(c.hash,!0,{notify:null}).fail(function(){I(a.unknown,"path")}).done(function(e){I(o(e),"path")})))),!f.link&&c.read){var R,H=v.escape(c.name);if("1"==c.url)k.push(w.replace(z,a.link).replace(T,'"));else{if(c.url)R=c.url;else if("directory"===c.mime)if(b.nullUrlDirLinkSelf&&null===c.url){var _=window.location;R=_.pathname+_.search+"#elf_"+c.hash}else""!==c.url&&v.option("url",!v.isRoot(c)&&c.phash||c.hash)&&(R=v.url(c.hash));else R=v.url(c.hash);R&&k.push(w.replace(z,a.link).replace(T,''+H+""))}}f.dim||(c.dim?k.push(w.replace(z,a.dim).replace(T,c.dim)):c.mime.indexOf("image")!==-1&&(c.width&&c.height?k.push(w.replace(z,a.dim).replace(T,c.width+"x"+c.height)):c.size&&"0"!==c.size&&(k.push(w.replace(z,a.dim).replace(T,y.spinner.replace("{text}",a.calc).replace("{name}","dim"))),A.push(v.request({data:{cmd:"dim",target:c.hash},preventDefault:!0}).fail(function(){I(a.unknown,"dim")}).done(function(e){if(I(e.dim||a.unknown,"dim"),e.dim){var t=e.dim.split("x"),n=v.file(c.hash);n.width=t[0],n.height=t[1]}}))))),!f.modify&&k.push(w.replace(z,a.modify).replace(T,v.formatDate(c))),!f.perms&&k.push(w.replace(z,a.perms).replace(T,v.formatPermissions(c))),!f.locked&&k.push(w.replace(z,a.locked).replace(T,c.locked?a.yes:a.no)),!f.owner&&c.owner&&k.push(w.replace(z,a.owner).replace(T,c.owner)),!f.group&&c.group&&k.push(w.replace(z,a.group).replace(T,c.group)),!f.perm&&c.perm&&k.push(w.replace(z,a.perm).replace(T,v.formatFileMode(c.perm))),window.ArrayBuffer&&(v.options.cdns.sparkmd5||v.options.cdns.jssha)&&"directory"!==c.mime&&c.size>0&&(!b.showHashMaxsize||c.size<=b.showHashMaxsize)&&(P=[],e.each(v.storage("hashchekcer")||b.showHashAlgorisms,function(e,t){c[t]?k.push(w.replace(z,v.i18n(t)).replace(T,c[t]).replace("{class}",U)):(k.push(w.replace(z,v.i18n(t)).replace(T,y.spinner.replace("{text}",a.calc).replace("{name}",t))),P.push(t))}),P.length&&(m=e('
          '),A.push(v.getContentsHashes(c.hash,P,b.showHashOpts,{progressBar:m}).progress(function(t){e.each(P,function(e,n){t[n]&&I(t[n],n,U)})}).always(function(){e.each(P,function(e,t){I(a.unknown,t)})})))),b.custom&&e.each(b.custom,function(t,n){f[n.label]||n.mimes&&!e.grep(n.mimes,function(e){return c.mime===e||0===c.mime.indexOf(e+"/")}).length||n.hashRegex&&!c.hash.match(n.hashRegex)||(k.push(w.replace(z,v.i18n(n.label)).replace(T,n.tpl.replace("{id}",M))),n.action&&"function"==typeof n.action&&F.push(n.action))})}else C=C.replace("{class}","elfinder-cwd-icon-group"),d=y.groupTitle.replace("{items}",a.items).replace("{num}",x),p=e.grep(r,function(e){return"directory"==e.mime}).length,p?(u=e.grep(r,function(e){return!("directory"!==e.mime||e.phash&&!e.isroot)}).length,p-=u,k.push(w.replace(z,a.kind).replace(T,u===x||p===x?a[u?"roots":"folders"]:e.map({roots:u,folders:p,files:x-u-p},function(e,t){return e?a[t]+" "+e:null}).join(", "))),!f.size&&k.push(w.replace(z,a.size).replace(T,y.spinner.replace("{text}",a.calc).replace("{name}","size"))),S=e.map(r,function(e){return e.hash})):(s=0,e.each(r,function(e,t){var n=parseInt(t.size);n>=0&&s>=0?s+=n:s="unknown"}),k.push(w.replace(z,a.kind).replace(T,a.files)),!f.size&&k.push(w.replace(z,a.size).replace(T,v.formatSize(s))));return C=C.replace("{title}",d).replace("{content}",k.join("").replace(/{class}/g,"")),E=g.fmDialog(C,O),E.attr("id",M).one("mousedown",".elfinder-info-path",function(){e(this).html(o(e(this).html(),!0))}),P.length&&m.appendTo(E.find("."+n+"-"+P[0]).parent()),v.UA.Mobile&&e.fn.tooltip&&E.children(".ui-dialog-content .elfinder-info-title").tooltip({classes:{"ui-tooltip":"elfinder-ui-tooltip ui-widget-shadow"},tooltipClass:"elfinder-ui-tooltip ui-widget-shadow",track:!0}),c&&"1"==c.url&&E.on("click","."+n+"-url",function(){e(this).parent().html(y.spinner.replace("{text}",v.i18n("ntfurl")).replace("{name}","url")),v.request({data:{cmd:"url",target:c.hash},preventDefault:!0}).fail(function(){I(H,"url")}).done(function(e){if(e.url){I(''+H+""||H,"url");var t=v.file(c.hash);t.url=e.url}else I(H,"url")})}),l&&e("").on("load",function(){E.find(".elfinder-cwd-icon").addClass(l.className).css("background-image","url('"+l.url+"')")}).attr("src",l.url),S.length&&(j=v.getSize(S).done(function(e){I(e.formated,"size")}).fail(function(){I(a.unknown,"size")})),F.length&&e.each(F,function(e,t){try{t(c,v,E)}catch(n){v.debug("error",n)}}),e.Deferred().resolve()}}).prototype={forceLoad:!0},i.prototype.commands.mkdir=function(){var t,n=this.fm,i=this;this.value="",this.disableOnSearch=!0,this.updateOnSelect=!1,this.syncTitleOnChange=!0,this.mime="directory",this.prefix="untitled folder",this.exec=function(a,o){var r;return a&&a.length&&o&&o._currentType&&"navbar"===o._currentType?(this.origin=o._currentType,this.data={target:a[0]}):(r=n.cwd().hash===a[0],this.origin=t&&!r?t:"cwd",delete this.data),a||this.options.intoNewFolderToolbtn||n.getUI("cwd").trigger("unselectall"),this.move=this.value===n.i18n("cmdmkdirin"),e.proxy(n.res("mixin","make"),i)()},this.shortcuts=[{pattern:"ctrl+shift+n"}],this.init=function(){this.options.intoNewFolderToolbtn&&(this.syncTitleOnChange=!0)},n.bind("select contextmenucreate closecontextmenu",function(e){var a=(e.data?e.data.selected||e.data.targets:null)||n.selected();i.className="mkdir",t=e.data&&a.length?e.data.origin||e.data.type||"":"",i.options.intoNewFolderToolbtn||""!==t||(t="cwd"),a.length&&"navbar"!==t&&"cwd"!==t&&n.cwd().hash!==a[0]?(i.title=n.i18n("cmdmkdirin"),i.className+=" elfinder-button-icon-mkdirin"):i.title=n.i18n("cmdmkdir"),"closecontextmenu"!==e.type?i.update(void 0,i.title):requestAnimationFrame(function(){i.update(void 0,i.title)})}),this.getstate=function(i){var a=n.cwd(),o="navbar"===t||i&&i[0]!==a.hash?this.files(i||n.selected()):[],r=o.length;return"navbar"===t?r&&o[0].write&&o[0].read?0:-1:!a.write||r&&e.grep(o,function(e){return!(!e.read||e.locked)}).length!=r?-1:0}},i.prototype.commands.mkfile=function(){var t=this;this.disableOnSearch=!0,this.updateOnSelect=!1,this.mime="text/plain",this.prefix="untitled file.txt",this.variants=[],this.getTypeName=function(e,n){var i,a=t.fm;return i=(i=a.messages["kind"+a.kinds[e]])?a.i18n(["extentiontype",n.toUpperCase(),i]):a.i18n(["extentionfile",n.toUpperCase()])},this.fm.bind("open reload canMakeEmptyFile",function(){var n=t.fm,i=n.getCommand("edit").getMkfileHides();t.variants=[],n.mimesCanMakeEmpty&&e.each(n.mimesCanMakeEmpty,function(e,a){a&&!i[e]&&n.uploadMimeCheck(e)&&t.variants.push([e,t.getTypeName(e,a)])}),t.change()}),this.getstate=function(){return this.fm.cwd().write?0:-1},this.exec=function(n,i){var a,o,r=t.fm;if(a=r.mimesCanMakeEmpty[i]){if(r.uploadMimeCheck(i))return this.mime=i,this.prefix=r.i18n(["untitled file",a]),e.proxy(r.res("mixin","make"),t)();o=["errMkfile",t.getTypeName(i,a)]}return e.Deferred().reject(o)}},i.prototype.commands.netmount=function(){var t,n=this,i=!1;this.alwaysEnabled=!0,this.updateOnSelect=!1,this.drivers=[],this.handlers={load:function(){var t=n.fm;t.cookieEnabled&&t.one("open",function(){n.drivers=t.netDrivers,n.drivers.length&&e.each(n.drivers,function(){var e=n.options[this];e&&(i=!0,e.integrateInfo&&t.trigger("helpIntegration",Object.assign({cmd:"netmount"},e.integrateInfo)))})})}},this.getstate=function(){return i?0:-1},this.exec=function(){var i,a=n.fm,o=e.Deferred(),r=n.options,s=function(){var s,l=function(){c.protocol.trigger("change","winfocus")},c={protocol:e("").on("change",function(e,n){var o=this.value;t.find(".elfinder-netmount-tr").hide(),t.find(".elfinder-netmount-tr-"+o).show(),i&&i.children(".ui-dialog-buttonpane:first").find("button").show(),"function"==typeof r[o].select&&r[o].select(a,e,n)}).addClass("ui-corner-all")},d={title:a.i18n("netMountDialogTitle"),resizable:!0,modal:!0,destroyOnClose:!1,open:function(){e(window).on("focus."+a.namespace,l),c.protocol.trigger("change")},close:function(){"pending"==o.state()&&o.reject(),e(window).off("focus."+a.namespace,l)},buttons:{}},p=function(){var i,s=c.protocol.val(),l={cmd:"netmount",protocol:s},d=r[s];return e.each(t.find("input.elfinder-netmount-inputs-"+s),function(t,n){var i,a;a=e(n),a.is(":radio,:checkbox")?a.is(":checked")&&(i=e.trim(a.val())):i=e.trim(a.val()),i&&(l[n.name]=i)}),l.host?(l.mnt2res&&(i=!0),a.request({data:l,notify:{type:"netmount",cnt:1,hideCnt:!0}}).done(function(e){var t;e.added&&e.added.length&&(i&&c.protocol.trigger("change","reset"),e.added[0].phash&&(t=a.file(e.added[0].phash))&&(t.dirs||(t.dirs=1,a.change({changed:[t]}))),a.one("netmountdone",function(){a.exec("open",e.added[0].hash)})),o.resolve()}).fail(function(e){d.fail&&"function"==typeof d.fail&&d.fail(a,a.parseError(e)),o.reject(e)}),void n.dialog.elfinderdialog("close")):a.trigger("error",{error:"errNetMountHostReq",opts:{modal:!0}})},u=e('
          ').on("keydown","input",function(t){var n,i=!0;t.keyCode===e.ui.keyCode.ENTER&&(e.each(u.find("input:visible:not(.elfinder-input-optional)"),function(){if(""===e(this).val())return i=!1,n=e(this),!1}),i?p():n.trigger("focus"))}),h=e("
          ");return t=e('
          ').append(e("").append(e(""+a.i18n("protocol")+"")).append(e("").append(c.protocol))),e.each(n.drivers,function(n,i){r[i]&&(c.protocol.append('"),e.each(r[i].inputs,function(n,o){o.attr("name",n),"hidden"!=o.attr("type")?(o.addClass("ui-corner-all elfinder-netmount-inputs-"+i),t.append(e("").addClass("elfinder-netmount-tr elfinder-netmount-tr-"+i).append(e(""+a.i18n(n)+"")).append(e("").append(o)))):(o.addClass("elfinder-netmount-inputs-"+i),h.append(o))}),r[i].protocol=c.protocol)}),t.append(h),t.find(".elfinder-netmount-tr").hide(),t.find(".elfinder-netmount-tr-"+n.drivers[0]).show(),d.buttons[a.i18n("btnMount")]=p,d.buttons[a.i18n("btnCancel")]=function(){n.dialog.elfinderdialog("close")},t.find("select,input").addClass("elfinder-tabstop"),s=n.fmDialog(u.append(t),d).ready(function(){c.protocol.trigger("change"),s.elfinderdialog("posInit")}),i=s.closest(".ui-dialog"),s};return n.dialog?n.dialog.elfinderdialog("open"):n.dialog=s(),o.promise()},n.fm.bind("netmount",function(e){var i=e.data||null,a=n.options,o=function(){a[i.protocol]&&"function"==typeof a[i.protocol].done&&(a[i.protocol].done(n.fm,i),t.find("select,input").addClass("elfinder-tabstop"),n.dialog.elfinderdialog("tabstopsInit"))};i&&i.protocol&&(i.mode&&"redirect"===i.mode?n.fm.request({data:{cmd:"netmount",protocol:i.protocol,host:i.host,user:"init",pass:"return",options:i.options},preventDefault:!0}).done(function(e){i=JSON.parse(e.body),o()}):o())})},i.prototype.commands.netunmount=function(){this.alwaysEnabled=!0,this.updateOnSelect=!1,this.drivers=[],this.handlers={load:function(){this.drivers=this.fm.netDrivers}},this.getstate=function(e){var t,n=this.fm;return e&&this.drivers.length&&!this._disabled&&(t=n.file(e[0]))&&t.netkey?0:-1},this.exec=function(t){var n=this,i=this.fm,a=e.Deferred().fail(function(e){e&&i.error(e)}),o=i.file(t[0]),r=function(t){var n,a=[];return i.leafRoots&&(n=[],e.each(i.leafRoots,function(a,o){var r,s=i.parents(a);(r=e.inArray(t,s))!==-1&&(r=s.length-r,e.each(o,function(e,t){n.push({i:r,hash:t})}))}),n.length&&(n.sort(function(e,t){return e.i").hide().appendTo(e("body"));if(t.UA.Mobile||!h){if(u)h?p.attr("target","_blank"):p.attr("download",a.name),p.attr("href",n).get(0).click();else if(i=window.open(n),!i)return g.reject("errPopup")}else{if(m="string"==typeof w.method&&"get"===w.method.toLowerCase(),!m&&0===n.indexOf(t.options.url)&&t.customData&&Object.keys(t.customData).length&&!a.mime.match(/^(?:video|audio)/)&&(n=""),"window"===x?(s=c=Math.round(2*screen.availWidth/3),l=d=Math.round(2*screen.availHeight/3),parseInt(a.width)&&parseInt(a.height)?(s=parseInt(a.width),l=parseInt(a.height)):a.dim&&(o=a.dim.split("x"),s=parseInt(o[0]),l=parseInt(o[1])),c>=s&&d>=l?(c=s,d=l):s-c>l-d?d=Math.round(l*(c/s)):c=Math.round(s*(d/l)),r="width="+c+",height="+d,i=window.open(n,f,r+",top=50,left=50,scrollbars=yes,resizable=yes,titlebar=no")):("tabs"===x&&(f=a.hash),i=window.open("about:blank",f)),!i)return g.reject("errPopup");if(""===n){var v=document.createElement("form");v.action=t.options.url,v.method="POST",v.target=f,v.style.display="none";var b=Object.assign({},t.customData,{cmd:"file",target:a.hash,_t:a.ts||parseInt(+new Date/1e3)});e.each(b,function(e,t){var n=document.createElement("input");n.name=e,n.value=t,v.appendChild(n)}),document.body.appendChild(v),v.submit()}else"window"!==x&&(i.location=n);e(i).trigger("focus")}p.remove()};try{p=new RegExp(t.option("dispInlineRegex"),"i")}catch(k){p=!1}for(u="string"==typeof e("").get(0).download,b=v.length;b--;){if(f="elf_open_window",a=v[b],!a.read)return g.reject(["errOpen",a.name,"errPerm"]);h=p&&a.mime.match(p),t.openUrl(a.hash,!h,y)}return g.resolve(n)};if(b>1)t.confirm({title:"openMulti",text:["openMultiConfirm",b+""],accept:{label:"cmdopen",callback:function(){k()}},cancel:{label:"btnCancel",callback:function(){g.reject()}},buttons:t.getCommand("zipdl")&&t.isCommandEnabled("zipdl",t.cwd().hash)?[{label:"cmddownload",callback:function(){t.exec("download",n),g.reject()}}]:[]});else{if(f=t.storage("selectAction")||w.selectAction,f&&(e.each(f.split("/"),function(){var e=this.valueOf();return("open"===e||!(m=t.getCommand(e))||!m.enabled())&&void(m=null)}),m))return t.exec(m.name);k()}return g}}).prototype={forceLoad:!0},i.prototype.commands.opendir=function(){this.alwaysEnabled=!0,this.getstate=function(){var e,t=this.fm.selected(),n=t.length;return 1!==n?-1:(e=this.fm.getUI("workzone"),e.hasClass("elfinder-search-result")?0:-1)},this.exec=function(t){var n,i=this.fm,a=e.Deferred(),o=this.files(t),r=o.length;return r&&o[0].phash?(n=o[0].phash,i.trigger("searchend",{noupdate:!0}),i.request({data:{cmd:"open",target:n},notify:{type:"open",cnt:1,hideCnt:!0},syncOnFail:!1}),a):a.reject()}},i.prototype.commands.opennew=function(){var t=this.fm;this.shortcuts=[{pattern:("function"==typeof t.options.getFileCallback?"shift+":"")+"ctrl+enter"}],this.getstate=function(e){var t=this.files(e),n=t.length;return 1===n&&"directory"===t[0].mime&&t[0].read?0:-1},this.exec=function(t){var n,i,a,o,r=e.Deferred(),s=this.files(t),l=s.length,c=this.options;return 1===l&&(n=s[0])&&"directory"===n.mime?(i=window.location,a=c.url?c.url:i.pathname,c.useOriginQuery&&(a.match(/\?/)?i.search&&(a+="&"+i.search.substr(1)):a+=i.search),a+="#elf_"+n.hash,o=window.open(a,"_blank"),setTimeout(function(){o.focus()},1e3),r.resolve()):r.reject()}},i.prototype.commands.paste=function(){this.updateOnSelect=!1,this.handlers={changeclipboard:function(){this.update()}},this.shortcuts=[{pattern:"ctrl+v shift+insert"}],this.getstate=function(e){if(this._disabled)return-1;if(e){if(Array.isArray(e)){if(1!=e.length)return-1;e=this.fm.file(e[0])}}else e=this.fm.cwd();return this.fm.clipboard().length&&"directory"==e.mime&&e.write?0:-1},this.exec=function(t,n){var i,a,o,r=this,s=r.fm,l=n||{},c=t?this.files(t)[0]:s.cwd(),d=s.clipboard(),p=d.length,u=!!p&&d[0].cut,h=l._cmd?l._cmd:u?"move":"copy",f="err"+h.charAt(0).toUpperCase()+h.substr(1),m=[],g=[],v=e.Deferred().fail(function(e){e&&s.error(e)}).always(function(){s.unlockfiles({files:e.map(d,function(e){return e.hash})})}),b=function(t){return t.length&&s._commands.duplicate?s.exec("duplicate",t):e.Deferred().resolve()},y=function(t){var n,i=e.Deferred(),a=[],o={},d=function(t,n){for(var i=[],a=t.length;a--;)e.inArray(t[a].name,n)!==-1&&i.unshift(a);return i},p=function(e){var n=a[e],o=t[n],r=e==a.length-1;o&&s.confirm({title:s.i18n(h+"Files"),text:["errExists",o.name,"restore"===h?"confirmRest":"confirmRepl"],all:!r,accept:{label:"btnYes",callback:function(n){r||n?m(t):p(++e)}},reject:{label:"btnNo",callback:function(n){var i;if(n)for(i=a.length;e{title}',s=e('
          '),l=e('
            '),c=e('
            '),d=(e("base").length?document.location.href.replace(/#.*$/,""):"",function(t){e("#"+a.namespace+"-preference-tab-"+t).trigger("mouseover").trigger("click"),n=t}),p=a.res("class","tabsactive"),u=function(){var u=i.options.categories||{language:["language"],theme:["theme"],toolbar:["toolbarPref"],workspace:["iconSize","columnPref","selectAction","makefileTypes","useStoredEditor","editorMaximized","useFullscreen","showHidden"],dialog:["autoFocusDialog"],selectionInfo:["infoItems","hashChecker"],reset:["clearBrowserData"],all:!0},h=i.options.prefs||["language","theme","toolbarPref","iconSize","columnPref","selectAction","makefileTypes","useStoredEditor","editorMaximized","useFullscreen","showHidden","infoItems","hashChecker","autoFocusDialog","clearBrowserData"];a.cookieEnabled||delete u.language,h=a.arrayFlip(h,!0),a.options.getFileCallback&&delete h.selectAction,a.UA.Fullscreen||delete h.useFullscreen,h.language&&(h.language=function(){var t=e("").on("change",function(){var t=e(this).val();a.storage("lang",t),e("#"+a.id).elfinder("reload")}),n=[],o=i.options.langs||{ar:"العربية",bg:"Български",ca:"Català",cs:"Čeština",da:"Dansk",de:"Deutsch",el:"Ελληνικά",en:"English",es:"Español",fa:"فارسی",fo:"Føroyskt",fr:"Français",fr_CA:"Français (Canada)",he:"עברית",hr:"Hrvatski",hu:"Magyar",id:"Bahasa Indonesia",it:"Italiano",ja:"日本語",ko:"한국어",nl:"Nederlands",no:"Norsk",pl:"Polski",pt_BR:"Português",ro:"Română",ru:"Pусский",si:"සිංහල",sk:"Slovenčina",sl:"Slovenščina",sr:"Srpski",sv:"Svenska",tr:"Türkçe",ug_CN:"ئۇيغۇرچە",uk:"Український",vi:"Tiếng Việt",zh_CN:"简体中文",zh_TW:"正體中文"};return a.cookieEnabled?(e.each(o,function(e,t){n.push('")}),t.append(n.join("")).val(a.lang)):e()}()),h.theme&&(h.theme=function(){var t=a.options.themes?Object.keys(a.options.themes).length:0;if(0===t||1===t&&a.options.themes["default"])return null;var n=e("").on("change",function(){var t=e(this).val();a.changeTheme(t).storage("theme",t)}),i={image:'',link:'$2',data:'
            $1
            $2
            '},o=["image","description","author","email","license"],r=e('').text(a.i18n("default")).on("click",function(e){n.val("default").trigger("change")}),s=e('
            ').on("click","button",function(){var t=e(this).data("themeid");n.val(t).trigger("change")});return a.options.themes["default"]||n.append('"),e.each(a.options.themes,function(t,r){var l,c=e('"),d=e('
            '+a.i18n(t)+'
            ');n.append(c),s.append(d),l=setTimeout(function(){d.find("span.elfinder-spinner").replaceWith(a.i18n(["errRead",t]))},1e4),a.getTheme(t).always(function(){l&&clearTimeout(l)}).done(function(r){var s,l=e(),p=e("
            ");s=r.link?i.link.replace(/\$1/g,r.link).replace(/\$3/g,a.i18n("website")):"$2",r.name&&c.html(a.i18n(r.name)),d.children("legend").html(s.replace(/\$2/g,a.i18n(r.name)||t)),e.each(o,function(o,s){var l,c=i[s]||i.data;r[s]&&(l=c.replace(/\$0/g,a.escape(s)).replace(/\$1/g,a.i18n(s)).replace(/\$2/g,a.i18n(r[s])),"image"===s&&r.link&&(l=e(l).on("click",function(){n.val(t).trigger("change")}).attr("title",a.i18n("select"))),p.append(l))}),l=l.add(p),l=l.add(e('
            ').append(e('').data("themeid",t).html(a.i18n("select")))),d.find("span.elfinder-spinner").replaceWith(l)}).fail(function(){d.find("span.elfinder-spinner").replaceWith(a.i18n(["errRead",t]))})}),e("
            ").append(n.val(a.theme&&a.theme.id?a.theme.id:"default"),r,s)}()),h.toolbarPref&&(h.toolbarPref=function(){var t=e.map(a.options.uiOptions.toolbar,function(t){return e.isArray(t)?t:null}),n=[],i=a.storage("toolbarhides")||{};return e.each(t,function(){var e=this,t=a.i18n("cmd"+e);t==="cmd"+e&&(t=a.i18n(e)),n.push('")}),e(n.join(" ")).on("change","input",function(){var t=e(this).val(),n=e(this).is(":checked");n||i[t]?n&&i[t]&&delete i[t]:i[t]=!0,a.storage("toolbarhides",i),a.trigger("toolbarpref")})}()),h.iconSize&&(h.iconSize=function(){var t=a.options.uiOptions.cwd.iconsView.sizeMax||3,n=a.storage("iconsize")||a.options.uiOptions.cwd.iconsView.size||0,i=e('
            ').slider({classes:{"ui-slider-handle":"elfinder-tabstop"},value:n,max:t,slide:function(e,t){a.getUI("cwd").trigger("iconpref",{size:t.value})},change:function(e,t){a.storage("iconsize",t.value)}});return a.getUI("cwd").on("iconpref",function(e,t){i.slider("option","value",t.size)}),i}()),h.columnPref&&(h.columnPref=function(){var t=a.options.uiOptions.cwd.listView.columns,n=[],i=a.storage("columnhides")||{};return e.each(t,function(){var e=this,t=a.getColumnName(e);n.push('")}),e(n.join(" ")).on("change","input",function(){var t=e(this).val(),n=e(this).is(":checked");n||i[t]?n&&i[t]&&delete i[t]:i[t]=!0,a.storage("columnhides",i),a.trigger("columnpref",{repaint:!0})})}()),h.selectAction&&(h.selectAction=function(){var t=e("").on("change",function(){var t=e(this).val();a.storage("selectAction","default"===t?null:t)}),n=[],o=i.options.selectActions,r=a.getCommand("open").options.selectAction||"open";return e.inArray(r,o)===-1&&o.unshift(r),e.each(o,function(t,i){var o=e.map(i.split("/"),function(e){var t=a.i18n("cmd"+e);return t==="cmd"+e&&(t=a.i18n(e)),t});n.push('")}),t.append(n.join("")).val(a.storage("selectAction")||r)}()),h.makefileTypes&&(h.makefileTypes=function(){var t=a.getCommand("edit").getMkfileHides(),n=function(){var n=[];return t=a.getCommand("edit").getMkfileHides(),e.each(a.mimesCanMakeEmpty,function(e,i){var o=a.getCommand("mkfile").getTypeName(e,i);n.push('")}),n.join(" ")},i=e("
            ").on("change","input",function(){var n=e(this).val(),i=e(this).is(":checked");i||t[n]?i&&t[n]&&delete t[n]:t[n]=!0,a.storage("mkfileHides",t),a.trigger("canMakeEmptyFile")}).append(n()),o=e("
            ").append(e('').on("keydown",function(t){t.keyCode===e.ui.keyCode.ENTER&&e(this).next().trigger("click")}),e('').html(a.i18n("add")).on("click",function(){var t,n=e(this).prev(),i=n.val(),o=a.getUI("toast"),r=function(){return o.appendTo(n.closest(".ui-dialog")),a.toast({msg:a.i18n("errUsupportType"),mode:"warning",onHidden:function(){1===o.children().length&&o.appendTo(a.getUI())}}),n.trigger("focus"),!1};if(!i.match(/\//)){if(i=a.arrayFlip(a.mimeTypes)[i],!i)return r();n.val(i)}return a.mimeIsText(i)&&a.mimeTypes[i]?(a.trigger("canMakeEmptyFile",{mimes:[i],unshift:!0}),t={},t[i]=a.mimeTypes[i],a.storage("mkfileTextMimes",Object.assign(t,a.storage("mkfileTextMimes")||{})),n.val(""),o.appendTo(n.closest(".ui-dialog")),void a.toast({msg:a.i18n(["complete",i+" ("+t[i]+")"]),onHidden:function(){1===o.children().length&&o.appendTo(a.getUI())}})):r()}),e('').html(a.i18n("reset")).on("click",function(){a.one("canMakeEmptyFile",{done:function(){i.empty().append(n())}}),a.trigger("canMakeEmptyFile",{resetTexts:!0})}));return a.bind("canMakeEmptyFile",{done:function(e){e.data&&e.data.mimes&&e.data.mimes.length&&i.empty().append(n())}}),e("
            ").append(i,o)}()),h.useStoredEditor&&(h.useStoredEditor=e('').prop("checked",function(){var e=a.storage("useStoredEditor");return e?e>0:a.options.commandsOptions.edit.useStoredEditor}()).on("change",function(t){a.storage("useStoredEditor",e(this).is(":checked")?1:-1)})),h.editorMaximized&&(h.editorMaximized=e('').prop("checked",function(){var e=a.storage("editorMaximized");return e?e>0:a.options.commandsOptions.edit.editorMaximized}()).on("change",function(t){a.storage("editorMaximized",e(this).is(":checked")?1:-1)})),h.useFullscreen&&(h.useFullscreen=e('').prop("checked",function(){var e=a.storage("useFullscreen");return e?e>0:"screen"===a.options.commandsOptions.fullscreen.mode}()).on("change",function(t){a.storage("useFullscreen",e(this).is(":checked")?1:-1)})),h.showHidden&&!function(){var t,n=function(){var n,i=a.storage("hide"),o=[];i&&i.items&&e.each(i.items,function(e,t){o.push(a.escape(t))}),r.prop("disabled",!o.length)[o.length?"removeClass":"addClass"]("ui-state-disabled"),n=o.length?o.join("\n"):"",h.showHidden.attr("title",n),t&&h.showHidden.tooltip("option","content",n.replace(/\n/g,"
            ")).tooltip("close")},i=e('').prop("checked",function(){var e=a.storage("hide");return e&&e.show}()).on("change",function(t){var n={};n[e(this).is(":checked")?"show":"hide"]=!0,a.exec("hide",void 0,n)}),o=e('').append(a.i18n("reset")).on("click",function(){a.exec("hide",void 0,{reset:!0}),e(this).parent().find("input:first").prop("checked",!1),n()}),r=e().add(i).add(o);h.showHidden=e("
            ").append(i,o),a.bind("hide",function(e){var t=e.data;t.opts&&(t.opts.show||t.opts.hide)||n()}),a.UA.Mobile&&e.fn.tooltip&&(t=!0,h.showHidden.tooltip({classes:{"ui-tooltip":"elfinder-ui-tooltip ui-widget-shadow"},tooltipClass:"elfinder-ui-tooltip ui-widget-shadow",track:!0}).css("user-select","none"),o.css("user-select","none")),n()}(),h.infoItems&&(h.infoItems=function(){var t=a.getCommand("info").items,n=[],i=a.storage("infohides")||a.arrayFlip(a.options.commandsOptions.info.hideItems,!0);return e.each(t,function(){var e=this,t=a.i18n(e);n.push('")}),e(n.join(" ")).on("change","input",function(){var t=e(this).val(),n=e(this).is(":checked");n||i[t]?n&&i[t]&&delete i[t]:i[t]=!0,a.storage("infohides",i),a.trigger("infopref",{repaint:!0})})}()),h.hashChecker&&a.hashCheckers.length&&(h.hashChecker=function(){var t=[],n=a.arrayFlip(a.storage("hashchekcer")||a.options.commandsOptions.info.showHashAlgorisms,!0);return e.each(a.hashCheckers,function(){var e=this,i=a.i18n(e);t.push('")}),e(t.join(" ")).on("change","input",function(){var t=e(this).val(),i=e(this).is(":checked");i?n[t]=!0:n[t]&&delete n[t],a.storage("hashchekcer",e.grep(a.hashCheckers,function(e){return n[e]}))})}()),h.autoFocusDialog&&(h.autoFocusDialog=e('').prop("checked",function(){var e=a.storage("autoFocusDialog");return e?e>0:a.options.uiOptions.dialog.focusOnMouseOver}()).on("change",function(t){a.storage("autoFocusDialog",e(this).is(":checked")?1:-1)})),h.clearBrowserData&&(h.clearBrowserData=e("").text(a.i18n("reset")).button().on("click",function(t){t.preventDefault(),a.storage(),e("#"+a.id).elfinder("reload")})),e.each(u,function(t,i){var s,d;i===!0?d=1:i&&(s=e(),e.each(i,function(t,n){var i,o,r,l="";(i=h[n])&&(d=2,o=a.i18n(n),r=e(i).filter('input[type="checkbox"]'),r.length||(r=e(i).find('input[type="checkbox"]')),1===r.length?(r.attr("id")||r.attr("id","elfinder-preference-"+n+"-checkbox"),o='"):r.length>1&&(l=" elfinder-preference-checkboxes"),s=s.add(e('
            '+o+"
            ")).add(e('
            ').append(i)))})),d&&(l.append(r[o](/\{id\}/g,t)[o](/\{title\}/,a.i18n(t))[o](/\{class\}/,n===t?"elfinder-focus":"")),2===d&&c.append(e('
            ').hide().append(e("
            ").append(s))))}),l.on("click","a",function(t){var n=e(t.target),i=n.attr("href");t.preventDefault(),t.stopPropagation(),l.children().removeClass(p),n.removeClass("ui-state-hover").parent().addClass(p),i.match(/all$/)?c.addClass("elfinder-preference-taball").children().show():(c.removeClass("elfinder-preference-taball").children().hide(),e(i).show())}).on("focus blur","a",function(t){e(this).parent().toggleClass("ui-state-focus","focusin"===t.type)}).on("mouseenter mouseleave","li",function(t){e(this).toggleClass("ui-state-hover","mouseenter"===t.type)}),c.find("a,input,select,button").addClass("elfinder-tabstop"),s.append(l,c),t=i.fmDialog(s,{title:i.title,width:i.options.width||600,height:i.options.height||400,maxWidth:"window",maxHeight:"window",autoOpen:!1,destroyOnClose:!1,allowMinimize:!1,open:function(){n&&d(n),n=null},resize:function(){c.height(t.height()-l.outerHeight(!0)-(c.outerHeight(!0)-c.height())-5)}}).on("click",function(e){e.stopPropagation()}).css({overflow:"hidden"}),t.closest(".ui-dialog").css({overflow:"hidden"}).addClass("elfinder-bg-translucent"),n="all"};this.shortcuts=[{pattern:"ctrl+comma",description:this.title}],this.alwaysEnabled=!0,this.getstate=function(){return 0},this.exec=function(n,i){return!t&&u(),i&&(i.tab?d(i.tab):"cwd"===i._currentType&&d("workspace")),t.elfinderdialog("open"),e.Deferred().resolve()}},(i.prototype.commands.quicklook=function(){var t,n,i,a,o,r,s,l,c,d,p=this,u=p.fm,h=0,f=1,m=2,g=3,v=4,b=h,y=Element.update?"quicklookupdate":"update",w="elfinder-quicklook-navbar-icon",x="elfinder-quicklook-fullscreen",k="elfinder-quicklook-info-wrapper",C=function(t){e(document).trigger(e.Event("keydown",{keyCode:t,ctrlKey:!1,shiftKey:!1,altKey:!1,metaKey:!1}))},z=function(e){var t=u.getUI().offset(),n=function(){var t=e.find(".elfinder-cwd-file-wrapper");return t.length?t:e}(),i=n.offset()||{top:0,left:0};return{opacity:0,width:n.width(),height:n.height()-30,top:i.top-t.top,left:i.left-t.left}},T=function(){var i=p.options.contain||u.options.dialogContained,a=i?u.getUI():e(window),o=u.getUI().offset(),r=Math.min(t,a.width()-10),s=Math.min(n,a.height()-80);return{opacity:1,width:r,height:s,top:parseInt((a.height()-s-60)/2+(i?0:a.scrollTop()-o.top)),left:parseInt((a.width()-r)/2+(i?0:a.scrollLeft()-o.left))}},A={},j=function(e,t){var n=t||e.substr(0,e.indexOf("/")),i=A[n]?A[n]:A[n]=document.createElement(n),a=!1;try{a=i.canPlayType&&i.canPlayType(e)}catch(o){}return!(!a||""===a||"no"==a)},O=window.navigator.platform.indexOf("Win")!=-1,S=!1,I=!1,M=!1,E=null,F=e.ui.keyCode.LEFT,D=e.ui.keyCode.RIGHT,U="mousemove touchstart "+("onwheel"in document?"wheel":"onmousewheel"in document?"mousewheel":"DOMMouseScroll"),P=e(''),q=e("
            "),R=e('
            '),H=e('
            '),_=e('
            ').on("click touchstart",function(t){if(!M){var n=p.window,i=n.hasClass(x),o=e(window),r=function(){p.preview.trigger("changesize")};t.stopPropagation(),t.preventDefault(),i?(G="",L(),n.toggleClass(x).css(n.data("position")),o.trigger(p.resize).off(p.resize,r),V.off("mouseenter mouseleave"),H.off(U)):(n.toggleClass(x).data("position",{left:n.css("left"),top:n.css("top"),width:n.width(),height:n.height(),display:"block"}).removeAttr("style"),e(window).on(p.resize,r).trigger(p.resize),H.on(U,function(e){I||("mousemove"!==e.type&&"touchstart"!==e.type||(L(),E=setTimeout(function(){(u.UA.Mobile||V.parent().find(".elfinder-quicklook-navbar:hover").length<1)&&V.fadeOut("slow",function(){H.show()})},3e3)),H.is(":visible")&&(W(),H.data("tm",setTimeout(function(){H.show()},3e3))))}).show().trigger("mousemove"),V.on("mouseenter mouseleave",function(e){I||("mouseenter"===e.type?L():H.trigger("mousemove"))})),u.zIndex&&n.css("z-index",u.zIndex+1),u.UA.Mobile?V.attr("style",G):V.attr("style",G).draggable(i?"destroy":{start:function(){I=!0,M=!0,H.show(),L()},stop:function(){I=!1,G=p.navbar.attr("style"),requestAnimationFrame(function(){M=!1})}}),e(this).toggleClass(w+"-fullscreen-off");var s=n;a.is(".ui-resizable")&&(s=s.add(a)),s.resizable(i?"enable":"disable").removeClass("ui-state-disabled"),n.trigger("viewchange")}}),N=function(){p.update(void 0,function(){var t=p.fm,n=t.selectedFiles(),i=n.length,a=(p.docked(),function(){var a=0;return e.each(n,function(e,t){var n=parseInt(t.ts);a>=0?n>a&&(a=n):a="unknown"}),{hash:n[0].hash+"/"+ +new Date,name:t.i18n("items")+": "+i,mime:"group",size:J,ts:a,files:e.map(n,function(e){return e.hash}),getSize:!0}});return i||(i=1,n=[t.cwd()]),1===i?n[0]:a()}())},L=function(){p.window.hasClass(x)&&(E&&clearTimeout(E),E=null,V.stop(!0,!0).css("display","block"),W())},W=function(){H.data("tm")&&clearTimeout(H.data("tm")),H.removeData("tm"),H.hide()},B=e('
            ').on("click touchstart",function(e){return!M&&C(F),!1}),$=e('
            ').on("click touchstart",function(e){return!M&&C(D),!1}),V=e('
            ').append(B).append(_).append($).append('
            ').append(e('
            ').on("click touchstart",function(e){return!M&&p.window.trigger("close"),!1})),K=e('').on("mousedown",function(e){e.stopPropagation(),p.window.trigger("close")}),X=e('').on("mousedown",function(e){e.stopPropagation(),p.docked()?p.window.trigger("navdockout"):p.window.trigger("navdockin")}),J=''+u.i18n("calc")+'',G="",Y=!0;this.flags={},this.cover=H,this.evUpdate=y,(this.navbar=V)._show=L,this.resize="resize."+u.namespace,this.info=e("
            ").addClass(k).append(q).append(R),this.autoPlay=function(){return!!p.opened()&&!!p.options[p.docked()?"dockAutoplay":"autoplay"]},this.preview=e('
            ').on("change",function(){L(),V.attr("style",G),p.docked()&&V.hide(),p.preview.attr("style","").removeClass("elfinder-overflow-auto"),p.info.attr("style","").hide(),p.cover.removeClass("elfinder-quicklook-coverbg"),q.removeAttr("class").attr("style",""),R.html("")}).on(y,function(t){var n,i,a=(p.preview,t.file),r='
            {value}
            ',s=function(){var s=p.window.css("overflow","hidden");i=u.escape(a.i18||a.name),!a.read&&t.stopImmediatePropagation(),p.window.data("hash",a.hash),p.preview.off("changesize").trigger("change").children().remove(),P.html(i),B.css("visibility",""),$.css("visibility",""),a.hash===u.cwdId2Hash(o.find("[id]:not(.elfinder-cwd-parent):first").attr("id"))&&B.css("visibility","hidden"),a.hash===u.cwdId2Hash(o.find("[id]:last").attr("id"))&&$.css("visibility","hidden"),"directory"===a.mime?c=[a.hash]:"group"===a.mime&&a.getSize&&(c=a.files),R.html(r.replace(/\{value\}/,i)+r.replace(/\{value\}/,u.mime2kind(a))+r.replace(/\{value\}/,c.length?J:u.formatSize(a.size))+r.replace(/\{value\}/,u.i18n("modify")+": "+u.formatDate(a))),c.length&&(l=u.getSize(c).done(function(e){R.find("span.elfinder-spinner").parent().html(e.formated)}).fail(function(){R.find("span.elfinder-spinner").parent().html(u.i18n("unknown"))}).always(function(){l=null}),l._hash=a.hash),q.addClass("elfinder-cwd-icon ui-corner-all "+u.mime2class(a.mime)),a.icon&&q.css(u.getIconStyle(a,!0)),p.info.attr("class",k),a.csscls&&p.info.addClass(a.csscls),a.read&&(n=u.tmb(a))&&e("").hide().appendTo(p.preview).on("load",function(){q.addClass(n.className).css("background-image","url('"+n.url+"')"),e(this).remove()}).attr("src",n.url),p.info.delay(100).fadeIn(10),p.window.hasClass(x)&&H.trigger("mousemove"),s.css("overflow","")},c=[];a&&!Object.keys(a).length&&(a=u.cwd()),a&&l&&"pending"===l.state()&&l._hash!==a.hash&&l.reject(),a&&(t.forceUpdate||p.window.data("hash")!==a.hash)?s():t.stopImmediatePropagation()}),this.window=e('
            ').hide().addClass(u.UA.Touch?"elfinder-touch":"").on("click",function(e){var t=this;e.stopPropagation(),b===m&&requestAnimationFrame(function(){b===m&&u.toFront(t)})}).append(e('
            ').append(e('').append(K,X),P),this.preview,p.info.hide(),H.hide(),V).draggable({handle:"div.elfinder-quicklook-titlebar"}).on("open",function(e,t){var n=p.window,i=p.value,a=u.getUI("cwd"),o=function(e){b=e,p.update(1,p.value),p.change(),n.trigger("resize."+u.namespace)};Y||b!==h?b===v&&(u.getUI("navdock").data("addNode")(c),o(g),p.preview.trigger("changesize"),u.storage("previewDocked","1"),0===u.getUI("navdock").width()&&n.trigger("navdockout")):(i&&i.hash!==r&&(a=u.cwdHash2Elm(i.hash.split("/",2)[0])),G="",V.attr("style",""),b=f,a.trigger("scrolltoview"),W(),n.css(t||z(a)).show().animate(T(),550,function(){o(m),L()}),u.toFront(n))}).on("close",function(e,t){var n,i=p.window,a=p.preview.trigger("change"),r=(p.value,(i.data("hash")||"").split("/",2)[0]),s=function(e,n){b=e,n&&u.toHide(i),a.children().remove(),p.update(0,p.value),i.data("hash",""),t&&t.resolve()};p.opened()&&(l&&"pending"===l.state()&&l.reject(),p.docked()?(c=u.getUI("navdock").data("removeNode")(p.window.attr("id"),"detach"),s(v),u.storage("previewDocked","2")):(b=f,i.hasClass(x)&&_.click(),r&&(n=o.find("#"+r)).length?i.animate(z(n),500,function(){a.off("changesize"),s(h,!0)}):s(h,!0)))}).on("navdockin",function(e,t){var n=p.window,a=u.getUI("navdock"),o=s||a.width(),r=t||{};Y&&(r.init=!0),b=g,i=n.attr("style"),n.toggleClass("ui-front").removeClass("ui-widget").draggable("disable").resizable("disable").removeAttr("style").css({width:"100%",height:o,boxSizing:"border-box",paddingBottom:0,zIndex:"unset"}),V.hide(),X.toggleClass("ui-icon-plusthick ui-icon-minusthick elfinder-icon-full elfinder-icon-minimize"),u.toHide(n,!0),a.data("addNode")(n,r),p.preview.trigger("changesize"),u.storage("previewDocked","1")}).on("navdockout",function(t){var n=p.window,a=u.getUI("navdock"),o=(e.Deferred(),z(p.preview));s=n.outerHeight(),a.data("removeNode")(n.attr("id"),u.getUI()),n.toggleClass("ui-front").addClass("ui-widget").draggable("enable").resizable("enable").attr("style",i),X.toggleClass("ui-icon-plusthick ui-icon-minusthick elfinder-icon-full elfinder-icon-minimize"),b=h,n.trigger("open",o),u.storage("previewDocked","0")}).on("resize."+u.namespace,function(){p.preview.trigger("changesize")}),this.alwaysEnabled=!0,this.value=null,this.handlers={select:function(e,t){d&&cancelAnimationFrame(d),e.data&&e.data.selected&&e.data.selected.length?p.opened()&&N():d=requestAnimationFrame(function(){p.opened()&&N()})},error:function(){p.window.is(":visible")&&p.window.trigger("close")},"searchshow searchhide":function(){this.opened()&&this.window.trigger("close")},navbarshow:function(){requestAnimationFrame(function(){p.docked()&&p.preview.trigger("changesize")})},destroy:function(){p.window.remove()}},this.shortcuts=[{pattern:"space"}],this.support={audio:{ogg:j("audio/ogg;"),webm:j("audio/webm;"),mp3:j("audio/mpeg;"),wav:j("audio/wav;"),m4a:j("audio/mp4;")||j("audio/x-m4a;")||j("audio/aac;"),flac:j("audio/flac;"),amr:j("audio/amr;")},video:{ogg:j("video/ogg;"),webm:j("video/webm;"),mp4:j("video/mp4;"),mkv:j("video/x-matroska;")||j("video/webm;"),"3gp":j("video/3gpp;")||j("video/mp4;"),m3u8:j("application/x-mpegURL","video")||j("application/vnd.apple.mpegURL","video"),mpd:j("application/dash+xml","video")}},A={},this.closed=function(){return b==h||b==v},this.opened=function(){return b==m||b==g},this.docked=function(){return b==g},this.addIntegration=function(e){requestAnimationFrame(function(){u.trigger("helpIntegration",Object.assign({cmd:"quicklook"},e))})},this.init=function(){var i,l=this.options,c=this.window,d=this.preview;t=l.width>0?parseInt(l.width):450,n=l.height>0?parseInt(l.height):300,"auto"!==l.dockHeight&&(s=parseInt(l.dockHeight),s||(s=void 0)),u.one("load",function(){S=u.getUI("navdock").data("dockEnabled"),!S&&X.hide(),a=u.getUI(),o=u.getUI("cwd"),u.zIndex&&c.css("z-index",u.zIndex+1),c.appendTo(a),e(document).on("keydown."+u.namespace,function(t){t.keyCode==e.ui.keyCode.ESCAPE&&p.opened()&&!p.docked()&&c.hasClass("elfinder-frontmost")&&c.trigger("close")}),c.resizable({handles:"se",minWidth:350,minHeight:120,resize:function(){d.trigger("changesize")}}),p.change(function(){p.opened()&&p.value&&(p.value.tmb&&1==p.value.tmb&&(p.value=Object.assign({},u.file(p.value.hash))),d.trigger(e.Event(y,{file:p.value})))}),d.on(y,function(e){var t,n,a;if(t=e.file){if(n=t.hash,a=u.searchStatus.mixed&&u.searchStatus.state>1,"directory"!==t.mime)if(parseInt(t.size)||t.mime.match(l.mimeRegexNotEmptyCheck)){if(p.dispInlineRegex=i,a||u.optionsByHashes[n])try{p.dispInlineRegex=new RegExp(u.option("dispInlineRegex",n),"i")}catch(e){try{p.dispInlineRegex=new RegExp(u.isRoot(t)?u.options.dispInlineRegex:u.option("dispInlineRegex",t.phash),"i")}catch(e){p.dispInlineRegex=/^$/}}}else e.stopImmediatePropagation();else p.dispInlineRegex=/^$/;p.info.show()}else e.stopImmediatePropagation()}),e.each(u.commands.quicklook.plugins||[],function(e,t){"function"==typeof t&&new t(p)})}).one("open",function(){var e,t=Number(u.storage("previewDocked")||l.docked);S&&t>=1&&(e=p.window,p.exec(),e.trigger("navdockin",{init:!0}),2===t?e.trigger("close"):(p.update(void 0,u.cwd()),p.change())),Y=!1}).bind("open",function(){r=u.cwd().hash,p.value=u.cwd();try{i=new RegExp(u.option("dispInlineRegex"),"i")}catch(e){i=/^$/}}).bind("change",function(t){t.data&&t.data.changed&&p.opened()&&e.each(t.data.changed,function(){if(p.window.data("hash")===this.hash)return p.window.data("hash",null),p.preview.trigger(y),!1})}).bind("navdockresizestart navdockresizestop",function(e){H["navdockresizestart"===e.type?"show":"hide"]()})},this.getstate=function(){return p.opened()?1:0},this.exec=function(){return p.closed()&&N(),p.enabled()&&p.window.trigger(p.opened()?"close":"open"),e.Deferred().resolve()},this.hideinfo=function(){this.info.stop(!0,!0).hide()}}).prototype={forceLoad:!0},i.prototype.commands.quicklook.plugins=[function(t){var n,i,a=["image/jpeg","image/png","image/gif","image/svg+xml","image/x-ms-bmp"],o=t.fm.returnBytes(t.options.getDimThreshold||0),r=t.preview;n=new Image,n.onload=n.onerror=function(){2==n.height&&a.push("image/webp")},n.src="data:image/webp;base64,UklGRjoAAABXRUJQVlA4IC4AAACyAgCdASoCAAIALmk0mk0iIiIiIgBoSygABc6WWgAA/veff/0PP8bA//LwYAAA",e.each(navigator.mimeTypes,function(t,n){var i=n.type;0===i.indexOf("image/")&&e.inArray(i,a)&&a.push(i)}),r.on(t.evUpdate,function(n){var s,l,c,d,p=t.fm,u=n.file,h=!1,f=null,m=function(e){var t=p.file(u.hash);t.width=e[0],t.height=e[1]},g=function(){var e,t,n,i,a;f&&f.state&&"pending"===f.state()&&f.reject(),h||(h=!0,e=s.get(0),t=u.width&&u.height?{w:u.width,h:u.height}:e.naturalWidth?null:{w:s.width(),h:s.height()},t&&s.removeAttr("width").removeAttr("height"),n=u.width||e.naturalWidth||e.width||s.width(),i=u.height||e.naturalHeight||e.height||s.height(),u.width&&u.height||m([n,i]),t&&s.width(t.w).height(t.h),a=(n/i).toFixed(2),r.on("changesize",function(){var e,t,n=parseInt(r.width()),i=parseInt(r.height());a<(n/i).toFixed(2)?(t=i,e=Math.floor(t*a)):(e=n,t=Math.floor(e/a)),s.width(e).height(t).css("margin-top",t'+p.i18n("nowLoading")+'
          ').appendTo(t.info.find(".elfinder-quicklook-info")),c=e('
          ').appendTo(l),s=e("").hide().appendTo(r).on("load",function(){v(),g()}).on("error",function(){l.remove()}),d=p.openUrl(u.hash,!1,function(e){s.attr("src",e)},{progressBar:c}),r.one("change",function(){d&&d.state&&"pending"===d.state()&&d.reject()}),u.width&&u.height?g():u.size>o&&(f=p.request({data:{cmd:"dim",target:u.hash},preventDefault:!0}).done(function(e){if(e.dim){var t=e.dim.split("x");u.width=t[0],u.height=t[1],m(t),g()}})))})},function(t){var n=t.fm,i="image/tiff",a=t.preview;window.Worker&&window.Uint8Array&&a.on(t.evUpdate,function(o){var r,s,l,c,d,p=o.file,u=function(e){c&&c.terminate(),r.remove(),n.debug("error",e)},h=function(e){var t=n.file(p.hash);t.width=e[0],t.height=e[1]};p.mime===i&&(o.stopImmediatePropagation(),r=e('
          '+n.i18n("nowLoading")+'
          ').appendTo(t.info.find(".elfinder-quicklook-info")),s=e('
          ').appendTo(r),a.one("change",function(){c&&c.terminate(),r.remove()}),d=n.getContents(p.hash,"arraybuffer",{progressBar:s}).done(function(i){if(i){l=e("
          ").css({width:"100%",height:"100%"}).hide().appendTo(a);try{c=n.getWorker(),c.onmessage=function(n){var i,o,s,d,u=n.data;c&&c.terminate(),i=document.createElement("canvas"),o=i.getContext("2d"),i.width=u.width,i.height=u.height,s=o.createImageData(u.width,u.height),s.data.set(new Uint8Array(u.image)),o.putImageData(s,0,0),l.append(i).show(),r.remove(),d=(u.width/u.height).toFixed(2),a.on("changesize",function(){var t,n,o=parseInt(a.width()),r=parseInt(a.height());d<(o/r).toFixed(2)?(n=r,t=Math.floor(n*d)):(t=o,n=Math.floor(t/d)),e(i).width(t).height(n).css("margin-top",n'+i.i18n("nowLoading")+'').appendTo(t.info.find(".elfinder-quicklook-info")),d=e('
          ').appendTo(c),h=i.openUrl(f.hash,"sameorigin",function(t){t&&(l=e("").hide().appendTo(o),n?r(t,l,c):(p=window.define,u=window.require,window.require=null,window.define=null,i.loadScript([i.options.cdns.psd],function(){n=require("psd"),p?window.define=p:delete window.define,u?window.require=u:delete window.require,r(t,l,c)})))},{progressBar:d}),o.one("change",function(){h&&h.state&&"pending"===h.state()&&h.reject()}))})},function(t){var n=t.fm,i=n.arrayFlip(["text/html","application/xhtml+xml"]),a=t.preview;a.on(t.evUpdate,function(o){var r,s,l,c=o.file;i[c.mime]&&t.dispInlineRegex.test(c.mime)&&(!t.options.getSizeMax||c.size<=t.options.getSizeMax)&&(o.stopImmediatePropagation(),s=e('
          '+n.i18n("nowLoading")+'
          ').appendTo(t.info.find(".elfinder-quicklook-info")),l=e('
          ').appendTo(s),a.one("change",function(){"pending"==r.state()&&r.reject()}).addClass("elfinder-overflow-auto"),r=n.request({data:{cmd:"get",target:c.hash,conv:1,_t:c.ts},options:{type:"get",cache:!0},preventDefault:!0,progressBar:l}).done(function(n){t.hideinfo();var i=e('').appendTo(a)[0].contentWindow.document;i.open(),i.write(n.content),i.close()}).always(function(){s.remove()}))})},function(t){var n=t.fm,i=n.arrayFlip(["text/x-markdown"]),a=t.preview,o=null,r=function(n,i){t.hideinfo();var r=e('').appendTo(a)[0].contentWindow.document;r.open(),r.write(o(n.content)),r.close(),i.remove()},s=function(e){o=!1,e.remove()};a.on(t.evUpdate,function(l){var c,d,p,u=l.file;i[u.mime]&&n.options.cdns.marked&&o!==!1&&t.dispInlineRegex.test(u.mime)&&(!t.options.getSizeMax||u.size<=t.options.getSizeMax)&&(l.stopImmediatePropagation(),d=e('
          '+n.i18n("nowLoading")+'
          ').appendTo(t.info.find(".elfinder-quicklook-info")),p=e('
          ').appendTo(d),a.one("change",function(){"pending"==c.state()&&c.reject()}).addClass("elfinder-overflow-auto"),c=n.request({data:{cmd:"get",target:u.hash,conv:1,_t:u.ts},options:{type:"get",cache:!0},preventDefault:!0,progressBar:p}).done(function(e){o||window.marked?(o||(o=window.marked),r(e,d)):n.loadScript([n.options.cdns.marked],function(t){o=t||window.marked||!1,delete window.marked,o?r(e,d):s(d)},{tryRequire:!0,error:function(){s(d)}})}).fail(function(){s(d)}))})},function(t){if(t.options.viewerjs){var n=t.fm,i=t.preview,a=t.options.viewerjs,o=a.url?n.arrayFlip(a.mimes||[]):[],r=t.window,s=t.navbar,l=function(){s.css("bottom",r.hasClass("elfinder-quicklook-fullscreen")?"30px":"")};a.url&&i.on("update",function(s){var c,d,p,u,h=s.file;!o[h.mime]||"application/pdf"===h.mime&&a.pdfNative&&t.flags.pdfNative||(s.stopImmediatePropagation(),d=e('
          '+n.i18n("nowLoading")+'
          ').appendTo(t.info.find(".elfinder-quicklook-info")),p=e('
          ').appendTo(d),u=n.openUrl(h.hash,"sameorigin",function(n){n&&(c=e('').css("background-color","transparent").on("load",function(){t.hideinfo(),d.remove(),c.css("background-color","#fff")}).on("error",function(){d.remove(),c.remove()}).appendTo(i).attr("src",a.url+"#"+n),r.on("viewchange.viewerjs",l),l(),i.one("change",function(){r.off("viewchange.viewerjs"),d.remove(),c.off("load").remove()}))},{progressBar:p}),i.one("change",function(){u&&u.state&&"pending"===u.state()&&u.reject()}))})}},function(t){var n=t.fm,i="application/pdf",a=t.preview,o=!1,r="";n.UA.Safari&&"mac"===n.OS&&!n.UA.iOS||n.UA.IE||n.UA.Firefox?o=!0:e.each(navigator.plugins,function(t,n){e.each(n,function(e,t){if(t.type===i)return!(o=!0)})}),t.flags.pdfNative=o,o&&("undefined"==typeof t.options.pdfToolbar||t.options.pdfToolbar||(r="#toolbar=0"),a.on(t.evUpdate,function(s){var l,c=s.file;o&&c.mime===i&&t.dispInlineRegex.test(c.mime)&&(s.stopImmediatePropagation(),l=n.openUrl(c.hash,!1,function(i){i&&(t.hideinfo(),t.cover.addClass("elfinder-quicklook-coverbg"),e('').on("error",function(e){o=!1,t.update(void 0,n.cwd()),t.update(void 0,c)}).appendTo(a))}),a.one("change",function(){l&&l.state&&"pending"===l.state()&&l.reject()}))}))},function(t){var n=t.fm,i="application/x-shockwave-flash",a=t.preview,o=!1;e.each(navigator.plugins,function(t,n){e.each(n,function(e,t){if(t.type===i)return!(o=!0)})}),o&&a.on(t.evUpdate,function(o){var r,s,l=o.file;l.mime===i&&t.dispInlineRegex.test(l.mime)&&(o.stopImmediatePropagation(),s=n.openUrl(l.hash,!1,function(n){n&&(t.hideinfo(),r=e('').appendTo(a))}),a.one("change",function(){s&&s.state&&"pending"===s.state()&&s.reject()}))})},function(t){var n,i,a,o,r,s,l=t.fm,c=t.preview,d={"audio/mpeg":"mp3","audio/mpeg3":"mp3","audio/mp3":"mp3","audio/x-mpeg3":"mp3","audio/x-mp3":"mp3","audio/x-wav":"wav","audio/wav":"wav","audio/x-m4a":"m4a","audio/aac":"m4a","audio/mp4":"m4a","audio/x-mp4":"m4a","audio/ogg":"ogg","audio/webm":"webm","audio/flac":"flac","audio/x-flac":"flac","audio/amr":"amr"},p=t.window,u=t.navbar,h="string"==typeof t.options.mediaControlsList&&t.options.mediaControlsList?' controlsList="'+l.escape(t.options.mediaControlsList)+'"':"",f=function(){u.css("bottom",p.hasClass("elfinder-quicklook-fullscreen")?"50px":"")},m=function(t,i){return e('').on("change",function(e){e.stopPropagation()}).on("error",function(e){n&&n.data("hash")===i&&b()}).data("hash",i).appendTo(c)},g=function(t){var n,i=e.Deferred(),o=e.Deferred().done(function(){var e;e=l.getContents(t,"arraybuffer",{progressBar:s}).done(function(e){try{var t=a.toWAV(new Uint8Array(e));t?i.resolve(URL.createObjectURL(new Blob([t],{type:"audio/x-wav"}))):i.reject()}catch(n){i.reject()}}).fail(function(){i.reject()}),c.one("change",function(){e&&e.state&&"pending"===e.state()&&e.reject()})}).fail(function(){a=!1,i.reject()});return window.TextEncoder&&window.URL&&URL.createObjectURL&&"undefined"==typeof a?(n=window.AMR,delete window.AMR,l.loadScript([l.options.cdns.amr],function(){a=!!window.AMR&&window.AMR,window.AMR=n,o[a?"resolve":"reject"]()},{error:function(){o.reject()}})):o[a?"resolve":"reject"](),i},v=function(e){var t,i=n.data("hash");o&&(t=e.play()),t&&t["catch"]&&t["catch"](function(t){e.paused||n&&n.data("hash")===i&&b()})},b=function(){if(n&&n.parent().length){var e=n[0],t=n.children("source").attr("src");p.off("viewchange.audio");try{e.pause(),n.empty(),t.match(/^blob:/)&&URL.revokeObjectURL(t),e.src="",e.load()}catch(i){}n.remove(),n=null}};c.on(t.evUpdate,function(u){var h,b,y=u.file,w=d[y.mime];d[y.mime]&&t.dispInlineRegex.test(y.mime)&&((h=t.support.audio[w])||"amr"===w)&&(o=t.autoPlay(),i=y.hash,h?(u.stopImmediatePropagation(),r=e('
          '+l.i18n("nowLoading")+'
          ').appendTo(t.info.find(".elfinder-quicklook-info")),s=e('
          ').appendTo(r),b=l.openUrl(i,!1,function(e){r.remove(),e?(n=m(e,i),v(n[0]),p.on("viewchange.audio",f),f()):n.remove()},{progressBar:s}),c.one("change",function(){b&&b.state&&"pending"===b.state()&&b.reject()})):l.options.cdns.amr&&"amr"===w&&a!==!1&&(u.stopImmediatePropagation(),r=e('
          '+l.i18n("nowLoading")+'
          ').appendTo(t.info.find(".elfinder-quicklook-info")),s=e('
          ').appendTo(r),n=m("",i),g(y.hash).done(function(e){if(r.remove(),i===y.hash){var t=n[0];try{n.children("source").attr("src",e),t.pause(),t.load(),v(t),p.on("viewchange.audio",f),f()}catch(a){URL.revokeObjectURL(e),n.remove()}}else URL.revokeObjectURL(e)}).fail(function(){n.remove()})))}).one("change",b)},function(t){var n,i,a,o,r,s,l,c,d,p,u=t.fm,h=t.preview,f={"video/mp4":"mp4","video/x-m4v":"mp4","video/quicktime":"mp4","video/mpeg":"mpeg","video/ogg":"ogg","application/ogg":"ogg","video/webm":"webm","video/x-matroska":"mkv","video/3gpp":"3gp","application/vnd.apple.mpegurl":"m3u8","application/x-mpegurl":"m3u8","application/dash+xml":"mpd","video/x-flv":"flv","video/x-msvideo":"avi"},m=t.window,g=t.navbar,v="string"==typeof t.options.mediaControlsList&&t.options.mediaControlsList?' controlsList="'+u.escape(t.options.mediaControlsList)+'"':"",b=function(){u.UA.iOS?m.hasClass("elfinder-quicklook-fullscreen")?(h.css("height","-webkit-calc(100% - 50px)"),g._show()):h.css("height",""):g.css("bottom",m.hasClass("elfinder-quicklook-fullscreen")?"50px":"")},y=function(i,a){var r,s=function(e){l>1&&(c&&clearTimeout(c),c=setTimeout(function(){!r&&T(!0)},800))},l=0;o=null,a=a||{},t.hideinfo(),n=e('').on("change",function(e){e.stopPropagation()}).on("timeupdate progress",s).on("canplay",function(){r=!0}).data("hash",i.hash),n[0].addEventListener("error",function(e){a.src&&u.convAbsUrl(a.src)===u.convAbsUrl(e.target.src)&&(++l,s())},!0),a.src&&n.append(''),n.appendTo(h),m.on("viewchange.video",b),b()},w=function(e){var t,a;a=u.openUrl(e.hash,!1,function(a){d.remove(),a&&(y(e),t=new i,t.loadSource(a),t.attachMedia(n[0]),l&&t.on(i.Events.MANIFEST_PARSED,function(){z(n[0])}))},{progressBar:p}),h.one("change",function(){a&&a.state&&"pending"===a.state()&&a.reject()})},x=function(e){var t;t=u.openUrl(e.hash,!1,function(t){var i;d.remove(),t&&(y(e),o=window.dashjs.MediaPlayer().create(),i=o.getDebug(),i.setLogLevel?i.setLogLevel(dashjs.Debug.LOG_LEVEL_FATAL):i.setLogToBrowserConsole&&i.setLogToBrowserConsole(!1),o.initialize(n[0],t,l),o.on("error",function(e){T(!0)}))},{progressBar:p}),h.one("change",function(){t&&t.state&&"pending"===t.state()&&t.reject()})},k=function(e){var t;return r.isSupported()?(t=u.openUrl(e.hash,!1,function(t){if(d.remove(),t){var i=r.createPlayer({type:"flv",url:t});y(e),i.on(r.Events.ERROR,function(){i.destroy(),T(!0)}),i.attachMediaElement(n[0]),i.load(),z(i)}},{progressBar:p}),void h.one("change",function(){t&&t.state&&"pending"===t.state()&&t.reject()})):void(r=!1)},C=function(e){var t;t=u.openUrl(e.hash,!1,function(t){d.remove(),t&&(y(e),n[0].src=t,s(n[0],{src:t}))},{progressBar:p}),h.one("change",function(){t&&t.state&&"pending"===t.state()&&t.reject()})},z=function(e){var t,i=n.data("hash");l&&(t=e.play()),t&&t["catch"]&&t["catch"](function(t){e.paused||n&&n.data("hash")===i&&T(!0)})},T=function(e){if(c&&clearTimeout(c),n&&n.parent().length){var i=n[0];m.off("viewchange.video"),o&&o.reset();try{i.pause(),n.empty(),i.src="",i.load()}catch(a){}n.remove(),n=null}e&&t.info.show()};h.on(t.evUpdate,function(o){var c,m,g=o.file,v=g.mime.toLowerCase(),b=f[v];f[v]&&t.dispInlineRegex.test(g.mime)&&(l=t.autoPlay(),d=e('
          '+u.i18n("nowLoading")+'
          '),p=e('
          ').appendTo(d),t.support.video[b]&&("m3u8"!==b||u.UA.Safari)?(o.stopImmediatePropagation(),d.appendTo(t.info.find(".elfinder-quicklook-info")),m=u.openUrl(g.hash,!1,function(e){d.remove(),e&&(y(g,{src:e}),z(n[0]))},{progressBar:p}),h.one("change",function(){m&&m.state&&"pending"===m.state()&&m.reject()})):i!==!1&&u.options.cdns.hls&&"m3u8"===b?(o.stopImmediatePropagation(),d.appendTo(t.info.find(".elfinder-quicklook-info")),i?w(g):(c=window.Hls,delete window.Hls,u.loadScript([u.options.cdns.hls],function(e){i=e||window.Hls||!1,window.Hls=c,i&&w(g)},{tryRequire:!0,error:function(){i=!1}}))):a!==!1&&u.options.cdns.dash&&"mpd"===b?(o.stopImmediatePropagation(),d.appendTo(t.info.find(".elfinder-quicklook-info")),a?x(g):u.loadScript([u.options.cdns.dash],function(){a=!!window.dashjs,a&&x(g)},{tryRequire:!0,error:function(){a=!1}})):r!==!1&&u.options.cdns.flv&&"flv"===b?(o.stopImmediatePropagation(),d.appendTo(t.info.find(".elfinder-quicklook-info")),r?k(g):(c=window.flvjs,delete window.flvjs,u.loadScript([u.options.cdns.flv],function(e){r=e||window.flvjs||!1,window.flvjs=c,r&&k(g)},{tryRequire:!0,error:function(){r=!1}}))):u.options.cdns.videojs&&(o.stopImmediatePropagation(),d.appendTo(t.info.find(".elfinder-quicklook-info")),s?C(g):u.loadScript([u.options.cdns.videojs+"/video.min.js"],function(e){s=e||window.videojs||!1,s&&C(g)},{tryRequire:!0,error:function(){s=!1}}).loadCss([u.options.cdns.videojs+"/video-js.min.css"])))}).one("change",T)},function(t){var n,i=t.preview,a=[],o=t.window,r=t.navbar;e.each(navigator.plugins,function(t,n){e.each(n,function(e,t){(0===t.type.indexOf("audio/")||0===t.type.indexOf("video/"))&&a.push(t.type)})}),a=t.fm.arrayFlip(a),i.on(t.evUpdate,function(s){var l,c,d,p,u=s.file,h=u.mime,f=function(){r.css("bottom",o.hasClass("elfinder-quicklook-fullscreen")?"50px":"")};a[u.mime]&&t.dispInlineRegex.test(u.mime)&&(s.stopImmediatePropagation(),d=e('
          '+fm.i18n("nowLoading")+'
          ').appendTo(t.info.find(".elfinder-quicklook-info")),p=e('
          ').appendTo(d),c=t.fm.openUrl(u.hash,!1,function(a){d.remove(),a&&((l=0===h.indexOf("video/"))&&t.hideinfo(),n=e('').appendTo(i),o.on("viewchange.embed",f),f())},{progressBar:p}),i.one("change",function(){c&&c.state&&"pending"===c.state()&&c.reject()}))}).one("change",function(){n&&n.parent().length&&(o.off("viewchange.embed"),n.remove(),n=null)})},function(t){var n=t.fm,i=n.arrayFlip(["application/zip","application/x-gzip","application/x-tar","application/x-bzip2"]),a=t.preview,o=n.returnBytes(t.options.unzipMaxSize||0),r=!(!n.options.cdns.zlibUnzip||!n.options.cdns.zlibGunzip),s=!!n.options.cdns.bzip2;window.Worker&&window.Uint8Array&&window.DataView&&a.on(t.evUpdate,function(l){var c=l.file,d="application/x-tar"===c.mime,p="application/x-bzip2"===c.mime,u="application/zip"===c.mime||"application/x-gzip"===c.mime;if(i[c.mime]&&(!o||c.size<=o)&&(d||p&&s||u&&r)){var h,f,m,g,v=function(){h=n.getContents(c.hash,"arraybuffer",{progressBar:g}).fail(function(){m.remove()}).done(function(e){var t=function(e){f&&f.terminate(),m.remove(),u?r=!1:p&&(s=!1),n.debug("error",e)};try{f=n.getWorker(),f.onmessage=function(e){f&&f.terminate(),m.remove(),!e.data||e.data.error?new Error(e.data&&e.data.error?e.data.error:""):b(e.data.files)},f.onerror=t,"application/x-tar"===c.mime?f.postMessage({scripts:[n.getWorkerUrl("quicklook.unzip.js")],data:{type:"tar",bin:e}}):"application/zip"===c.mime?f.postMessage({scripts:[n.options.cdns.zlibUnzip,n.getWorkerUrl("quicklook.unzip.js")],data:{type:"zip",bin:e}}):"application/x-gzip"===c.mime?f.postMessage({scripts:[n.options.cdns.zlibGunzip,n.getWorkerUrl("quicklook.unzip.js")],data:{type:"gzip",bin:e}}):"application/x-bzip2"===c.mime&&f.postMessage({scripts:[n.options.cdns.bzip2,n.getWorkerUrl("quicklook.unzip.js")],data:{type:"bzip2",bin:e}})}catch(i){t(i)}})},b=function(i){var o,r,s,l=0;i&&i.length&&(i=e.map(i,function(e){return n.decodeRawString(e)}),i.sort(),r=n.escape(i.join("\n").replace(/\{formatSize\((\d+)\)\}/g,function(e,t){return l+=parseInt(t),n.formatSize(t)})),o=""+n.escape(c.mime)+" ("+n.formatSize(c.size)+" / "+n.formatSize(l)+")
          ",s=e('
          '+o+'
          '+r+"
          ").on("touchstart",function(t){e(this)["scroll"+("ltr"===n.direction?"Right":"Left")]()>5&&(t.originalEvent._preventSwipeX=!0)}).appendTo(a),t.hideinfo()),m.remove()};l.stopImmediatePropagation(),m=e('
          '+n.i18n("nowLoading")+'
          ').appendTo(t.info.find(".elfinder-quicklook-info")),g=e('
          ').appendTo(m),a.one("change",function(){"pending"===h.state()&&h.reject(),f&&f.terminate(),m.remove()}),v()}})},function(t){var n,i=t.fm,a=i.arrayFlip(["application/x-rar"]),o=t.preview;window.DataView&&o.on(t.evUpdate,function(r){var s=r.file;if(a[s.mime]&&i.options.cdns.rar&&n!==!1){var l,c,d,p,u,h,f=function(a){if(p)return void l.remove();try{d=n({file:a,type:2,xhrHeaders:i.customHeaders,xhrFields:i.xhrFields},function(n){l.remove();var a,r,c=[];return p||n?void(n&&i.debug("error",n)):(e.each(d.entries,function(){c.push(this.path+(this.size?" ("+i.formatSize(this.size)+")":""))}),void(c.length&&(c=e.map(c,function(e){return i.decodeRawString(e)}),c.sort(),a=""+i.escape(s.mime)+" ("+i.formatSize(s.size)+")
          ",r=e('
          '+a+'
          '+i.escape(c.join("\n"))+"
          ").on("touchstart",function(t){e(this)["scroll"+("ltr"===i.direction?"Right":"Left")]()>5&&(t.originalEvent._preventSwipeX=!0)}).appendTo(o),t.hideinfo())))})}catch(r){l.remove()}},m=function(){n=!1,l.remove()};r.stopImmediatePropagation(),l=e('
          '+i.i18n("nowLoading")+'
          ').appendTo(t.info.find(".elfinder-quicklook-info")),c=e('
          ').appendTo(l),o.one("change",function(){d&&(d.abort=!0),l.remove(),p=!0}),h=i.openUrl(s.hash,"sameorigin",function(e){e&&(n?f(e):(window.RarArchive&&(u=window.RarArchive,delete window.RarArchive),i.loadScript([i.options.cdns.rar],function(){i.hasRequire?require(["rar"],function(t){n=t,f(e)},m):(n=window.RarArchive)?(u?window.RarArchive=u:delete window.RarArchive,f(e)):m()},{tryRequire:!0,error:m})))},{progressBar:c,temporary:!0}),o.one("change",function(){h&&h.state&&"pending"===h.state()&&h.reject()})}})},function(t){var n,i=t.fm,a=i.arrayFlip(t.options.sharecadMimes||[]),o=t.preview;t.window;t.options.sharecadMimes.length&&t.addIntegration({title:"ShareCAD.org CAD and 3D-Models viewer",link:"https://sharecad.org/DWGOnlinePlugin"}),o.on(t.evUpdate,function(r){var s=r.file;if(a[s.mime.toLowerCase()]&&i.option("onetimeUrl",s.hash)){var l,c,d;t.window;r.stopImmediatePropagation(),"1"==s.url&&(o.hide(),e('
          ").appendTo(t.info.find(".elfinder-quicklook-info")).on("click",function(){var n=e(this);n.html(''),i.request({data:{cmd:"url",target:s.hash},preventDefault:!0,progressBar:c}).always(function(){n.html("")}).done(function(e){var n=i.file(s.hash);s.url=n.url=e.url||"",s.url&&o.trigger({type:t.evUpdate,file:s,forceUpdate:!0})})})),""!==s.url&&"1"!=s.url&&(o.one("change",function(){l.remove(),n.off("load").remove(),n=null}).addClass("elfinder-overflow-auto"),l=e('
          '+i.i18n("nowLoading")+'
          ').appendTo(t.info.find(".elfinder-quicklook-info")),c=e('
          ').appendTo(l),d=i.convAbsUrl(i.url(s.hash)),n=e('').css("background-color","transparent").appendTo(o).on("load",function(){t.hideinfo(),l.remove(),t.preview.after(t.info),e(this).css("background-color","#fff").show()}).on("error",function(){l.remove(),t.preview.after(t.info)}).attr("src","//sharecad.org/cadframe/load?url="+encodeURIComponent(d)),t.info.after(t.preview))}})},function(t){var n,i,a,o,r,s=t.fm,l={"application/vnd.google-earth.kml+xml":!0,"application/vnd.google-earth.kmz":!0},c=t.preview;t.options.googleMapsApiKey&&(t.addIntegration({title:"Google Maps",link:"https://www.google.com/intl/"+s.lang.replace("_","-")+"/help/terms_maps.html"}),n=window.google&&google.maps,i=function(e,i,a){var r=t.options.googleMapsOpts.maps;s.forExternalUrl(e.hash,{progressBar:a}).done(function(e){if(e)try{new n.KmlLayer(e,Object.assign({map:new n.Map(i.get(0),r)},t.options.googleMapsOpts.kml)),t.hideinfo()}catch(a){o()}else o()})},a=window.gm_authFailure,o=function(){r=null},r="https://maps.googleapis.com/maps/api/js?key="+t.options.googleMapsApiKey,window.gm_authFailure=function(){o(),a&&a()},c.on(t.evUpdate,function(a){var o=a.file;if(r&&l[o.mime.toLowerCase()]){var d,p,u,h=(t.window,"1"==o.url&&!s.option("onetimeUrl",o.hash));a.stopImmediatePropagation(),d=e('
          '+s.i18n("nowLoading")+'
          ').appendTo(t.info.find(".elfinder-quicklook-info")),p=e('
          ').appendTo(d),h&&(c.hide(),e('
          ").appendTo(t.info.find(".elfinder-quicklook-info")).on("click",function(){var n=e(this);n.html(''),s.request({data:{cmd:"url",target:o.hash},preventDefault:!0,progressBar:p}).always(function(){d.remove(),n.html("")}).done(function(e){var n=s.file(o.hash);o.url=n.url=e.url||"",o.url&&c.trigger({type:t.evUpdate,file:o,forceUpdate:!0})})})),""===o.url||h||(u=e('
          ').appendTo(c),c.one("change",function(){u.remove(),u=null}),n?i(o,u,p):s.loadScript([r],function(){n=window.google&&google.maps,n&&i(o,u,p)}))}}))},function(t){var n,i,a=t.fm,o=Object.assign(a.arrayFlip(t.options.googleDocsMimes||[],"g"),a.arrayFlip(t.options.officeOnlineMimes||[],"m")),r=t.preview,s=(t.window,t.navbar),l={g:"docs.google.com/gview?embedded=true&url=",m:"view.officeapps.live.com/op/embed.aspx?wdStartOn=0&src="},c={g:"56px",m:"24px"},d={xls:5242880,xlsb:5242880,xlsx:5242880,xlsm:5242880,other:10485760};t.options.googleDocsMimes.length&&(i=!0,t.addIntegration({title:"Google Docs Viewer",link:"https://docs.google.com/"})),t.options.officeOnlineMimes.length&&(i=!0,t.addIntegration({title:"MS Online Doc Viewer",link:"https://products.office.com/office-online/view-office-documents-online"})),i&&r.on(t.evUpdate,function(i){var p,u,h=i.file;if(h.size<=26214400&&(p=o[h.mime])){var f,m,g,v=t.window,b=function(){s.css("bottom",v.hasClass("elfinder-quicklook-fullscreen")?c[p]:"")},y=a.mimeTypes[h.mime],w="1"==h.url&&!a.option("onetimeUrl",h.hash);"m"===p&&(d[y]&&h.size>d[y]||h.size>d.other)&&(p="g"),w&&(r.hide(),e('
          ").appendTo(t.info.find(".elfinder-quicklook-info")).on("click",function(){var n=e(this);n.html(''),a.request({data:{cmd:"url",target:h.hash},preventDefault:!0}).always(function(){n.html("")}).done(function(e){var n=a.file(h.hash);h.url=n.url=e.url||"",h.url&&r.trigger({type:t.evUpdate,file:h,forceUpdate:!0})})})),""===h.url||w||(i.stopImmediatePropagation(),r.one("change",function(){u&&u.status&&"pending"===u.status()&&u.reject(),v.off("viewchange.googledocs"),f.remove(),n.off("load").remove(),n=null}).addClass("elfinder-overflow-auto"),f=e('
          '+a.i18n("nowLoading")+'
          ').appendTo(t.info.find(".elfinder-quicklook-info")),m=e('
          ').appendTo(f),n=e('').css("background-color","transparent").appendTo(r),u=a.forExternalUrl(h.hash,{progressBar:m}).done(function(i){var a=function(){try{!n||n.attr("src")&&!n.get(0).contentWindow.document||(n.attr("src","https://"+l[p]+encodeURIComponent(i)),g=setTimeout(a,2e3))}catch(e){}};i?(h.ts&&(i+=(i.match(/\?/)?"&":"?")+"_t="+h.ts),n.on("load",function(){g&&clearTimeout(g),t.hideinfo(),f.remove(),t.preview.after(t.info),e(this).css("background-color","#fff").show()}).on("error",function(){g&&clearTimeout(g),f.remove(),t.preview.after(t.info)}),a()):(f.remove(),n.remove())}),v.on("viewchange.googledocs",b),b(),t.info.after(t.preview))}})},function(t){"use strict";var n,i,a=t.fm,o=t.preview,r=parseInt(t.options.textInitialLines)||150,s=parseInt(t.options.prettifyMaxLines)||500,l=function(){c=function(){return!1},i&&(window.PR=i),n=!1},c=function(e){a.options.cdns.prettify?(c=function(e){return setTimeout(function(){p(e)},100),"pending"},window.PR&&(i=window.PR),a.loadScript([a.options.cdns.prettify+(a.options.cdns.prettify.match(/\?/)?"&":"?")+"autorun=false"],function(t){n=t||window.PR,"object"==typeof n?(c=function(){return!0},i?window.PR=i:delete window.PR,d(e)):l()},{tryRequire:!0,error:l})):l()},d=function(e){e&&!e.hasClass("prettyprinted")&&(e.css("cursor","wait"),requestAnimationFrame(function(){n.prettyPrint&&n.prettyPrint(null,e.get(0)),e.css("cursor","")}))},p=function(e){var t=c(e);t===!0&&d(e)};o.on(t.evUpdate,function(i){var l,c,d,u,h=i.file;h.mime;a.mimeIsText(h.mime)&&(!t.options.getSizeMax||h.size<=t.options.getSizeMax)&&n!==!1&&(i.stopImmediatePropagation(),c=e('
          '+a.i18n("nowLoading")+'
          ').appendTo(t.info.find(".elfinder-quicklook-info")),d=e('
          ').appendTo(c),o.one("change",function(){"pending"==l.state()&&l.reject(),u&&u.remove()}),l=a.request({data:{cmd:"get",target:h.hash,conv:h.encoding||1,_t:h.ts},options:{type:"get",cache:!0},preventDefault:!0,progressBar:d}).done(function(n){var i,l,c,d,u,f=new RegExp("^(data:"+h.mime.replace(/([.+])/g,"\\$1")+";base64,)","i"),m=n.content;"string"==typeof m&&(t.hideinfo(),window.atob&&(u=m.match(f))&&(m=atob(m.substr(u[1].length))),d=m.match(/([^\r\n]{1,100}[\r\n]*)/g),l=d.length-r,l>10?i=d.splice(0,r).join(""):l=0,c=e('
          '),l&&c.append(e('

          '+a.i18n("linesLeft",a.toLocaleString(l))+"
          ").on("click",function(){var t=c.scrollTop();e(this).remove(),c.children("pre").removeClass("prettyprinted").text(m).scrollTop(t),d.length<=s&&p(c)})),c.children("pre").text(i||m),c.on("touchstart",function(t){e(this)["scroll"+("ltr"===a.direction?"Right":"Left")]()>5&&(t.originalEvent._preventSwipeX=!0)}).appendTo(o),n.toasts&&Array.isArray(n.toasts)&&e.each(n.toasts,function(){this.msg&&a.toast(this)}),p(c))}).always(function(n){var i,r,s;(i=a.getCommand("edit"))&&(s=[],n&&n.encoding&&s.push({value:n.encoding}),s.push({value:"UTF-8"}),r=i.getEncSelect(s),r.on("change",function(){h.encoding=r.val(),a.cache(h,"change"),o.trigger({type:t.evUpdate,file:h,forceUpdate:!0})}),u=e('
          ').append(r),t.window.append(u)),c.remove()}))})}],(i.prototype.commands.reload=function(){"use strict";var t=this,n=!1;this.alwaysEnabled=!0,this.updateOnSelect=!0,this.shortcuts=[{pattern:"ctrl+shift+r f5"}],this.getstate=function(){return 0},this.init=function(){this.fm.bind("search searchend",function(){n="search"==this.type})},this.fm.bind("contextmenu",function(){var n=t.fm;n.options.sync>=1e3&&(t.extra={icon:"accept",node:e("").attr({title:n.i18n("autoSync")}).on("click touchstart",function(t){"touchstart"===t.type&&t.originalEvent.touches.length>1||(t.stopPropagation(),t.preventDefault(),e(this).parent().toggleClass("ui-state-disabled",n.options.syncStart).parent().removeClass("ui-state-hover"),n.options.syncStart=!n.options.syncStart,n.autoSync(n.options.syncStart?null:"stop"))}).on("ready",function(){e(this).parent().toggleClass("ui-state-disabled",!n.options.syncStart).css("pointer-events","auto")})})}),this.exec=function(){var t=this.fm;if(!n){var i=t.sync(),a=setTimeout(function(){t.notify({type:"reload",cnt:1,hideCnt:!0}),i.always(function(){t.notify({type:"reload",cnt:-1})})},t.notifyDelay);return i.always(function(){clearTimeout(a),t.trigger("reload")})}e("div.elfinder-toolbar > div."+t.res("class","searchbtn")+" > span.ui-icon-search").click()}}).prototype={forceLoad:!0},i.prototype.commands.rename=function(){"use strict";this.alwaysEnabled=!0,this.syncTitleOnChange=!0;var t=this,n=t.fm,i=function(t,i,a,o){var r,s=i?[a.hash].concat(i):[a.hash],l=s.length,c={};if(n.lockfiles({files:s}),n.isRoot(a)&&!a.netkey){if((r=n.storage("rootNames"))||(r={}),""===o){if(!r[a.hash])return t&&t.reject(),void n.unlockfiles({files:s}).trigger("selectfiles",{files:s});a.name=a._name,a.i18=a._i18,delete r[a.hash],delete a._name,delete a._i18}else"undefined"==typeof a._name&&(a._name=a.name,a._i18=a.i18),a.name=r[a.hash]=o,delete a.i18;return n.storage("rootNames",r),c={changed:[a]},n.updateCache(c),n.change(c),t&&t.resolve(c),void n.unlockfiles({files:s}).trigger("selectfiles",{files:s})}c={cmd:"rename",name:o,target:a.hash},l>1&&(c.targets=i,o.match(/\*/)&&(c.q=o)),n.request({data:c,notify:{type:"rename",cnt:l},navigate:{}}).fail(function(e){var i=n.parseError(e);t&&t.reject(),i&&Array.isArray(i)&&"errRename"===i[0]||n.sync()}).done(function(i){var r;i.added&&i.added.length&&1===l&&(i.undo={cmd:"rename",callback:function(){return n.request({data:{cmd:"rename",target:i.added[0].hash,name:a.name},notify:{type:"undo",cnt:1}})}},i.redo={cmd:"rename",callback:function(){return n.request({data:{cmd:"rename",target:a.hash,name:o},notify:{type:"rename",cnt:1}})}}),t&&t.resolve(i),(r=n.cwd().hash)&&r!==a.hash||n.exec("open",e.map(i.added,function(e){return"directory"===e.mime?e.hash:null})[0])}).always(function(){n.unlockfiles({files:s}).trigger("selectfiles",{files:s})})},a=function(e,t){var i,a,o,r=t||n.selected(),s=n.splitFileExtention(e),l=n.file(r[0]),c=n.file(r[1]);return i=s[1]?"."+s[1]:"",s[1]&&"*"===s[0]?(a='"'+n.splitFileExtention(l.name)[0]+i+'", ',a+='"'+n.splitFileExtention(c.name)[0]+i+'"'):s[0].length>1&&("*"===s[0].substr(-1)?(o=s[0].substr(0,s[0].length-1),a='"'+o+l.name+'", ',a+='"'+o+c.name+'"'):"*"===s[0].substr(0,1)&&(o=s[0].substr(1),a='"'+n.splitFileExtention(l.name)[0]+o+i+'", ',a+='"'+n.splitFileExtention(c.name)[0]+o+i+'"')),a||(a='"'+s[0]+"1"+i+'", "'+s[0]+"2"+i+'"'),r.length>2&&(a+=" ..."),a},o=function(){var o,r=n.selected(),s='',l=function(t,i){return e('").prepend(t)},c=e(''),d=e(s),p=e(s),u=e(s),h=e(s),f=e("
          ").append(l(d,"plusNumber"),l(p,"asPrefix"),l(u,"asSuffix"),l(h,"changeExtention")),m=e('
          '),g=e('
          ').append(e('
          ').append(c),e('
          ').append(f),m),v={ +title:n.i18n("batchRename"),modal:!0,destroyOnClose:!0,width:Math.min(380,n.getUI().width()-20),buttons:{},open:function(){c.on("input",y).trigger("focus")}},b=function(){var e=c.val(),t=n.splitFileExtention(n.file(r[0]).name)[1];return(""!==e||d.is(":checked"))&&(p.is(":checked")?e+="*":u.is(":checked")?e="*"+e+"."+t:h.is(":checked")?e="*."+e:t&&(e+="."+t)),e},y=function(){var e=b();""!==e?m.html(n.i18n(["renameMultiple",r.length,a(e)])):m.empty()},w=f.find("input:radio").on("change",y);v.buttons[n.i18n("btnApply")]=function(){var e,t,a=b();""!==a&&(o.elfinderdialog("close"),t=r,e=n.file(t.shift()),i(void 0,t,e,a))},v.buttons[n.i18n("btnCancel")]=function(){o.elfinderdialog("close")},e.fn.checkboxradio?w.checkboxradio({create:function(e,t){this===d.get(0)&&d.prop("checked",!0).change()}}):f.buttonset({create:function(e,t){d.prop("checked",!0).change()}}),o=t.fmDialog(g,v)};this.noChangeDirOnRemovedCwd=!0,this.shortcuts=[{pattern:"f2"+("mac"==n.OS?" enter":"")},{pattern:"shift+f2",description:"batchRename",callback:function(){n.selected().length>1&&o()}}],this.getstate=function(i){var a,r,s,l,c,d,p=this.files(i),u=p.length;return u?(u>1&&p[0].phash&&(a=p[0].phash,r=n.splitFileExtention(p[0].name)[1].toLowerCase(),s=p[0].mime),1===u&&(d=n.isRoot(p[0])),c=1===u&&(n.cookieEnabled&&d||!p[0].locked)||n.api>2.103&&u===e.grep(p,function(e){return!(l||e.locked||e.phash!==a||n.isRoot(e)||s!==e.mime&&r!==n.splitFileExtention(e.name)[1].toLowerCase())||(l&&(l=!0),!1)}).length?0:-1,!d&&0===c&&n.option("disabledFlip",p[0].hash).rename&&(c=-1),c!==-1&&u>1?t.extra={icon:"preference",node:e("").attr({title:n.i18n("batchRename")}).on("click touchstart",function(e){"touchstart"===e.type&&e.originalEvent.touches.length>1||(e.stopPropagation(),e.preventDefault(),n.getUI().trigger("click"),o())})}:delete t.extra,c):-1},this.exec=function(t,o){var r,s=(n.getUI("cwd"),t||!!n.selected().length&&n.selected()||[n.cwd().hash]),l=s.length,c=n.file(s.shift()),d=".elfinder-cwd-filename",p=o||{},u=n.cwd().hash==c.hash,h="navbar"===p._currentType||"files"===p._currentType?p._currentType:u?"navbar":"files",f="files"!==h,m=n[f?"navHash2Elm":"cwdHash2Elm"](c.hash),g=!f&&"list"!=n.storage("view"),v=function(){requestAnimationFrame(function(){x&&x.trigger("blur")})},b=function(){T.is(":hidden")||T.elfinderoverlay("hide").off("click close",A),z.removeClass("ui-front").css("position","").off("unselect."+n.namespace,v),g?C&&C.css("max-height",""):f||z.css("width","").parent("td").css("overflow","")},y=e.Deferred().fail(function(e){var t=x.parent(),i=n.escape(c.i18||c.name);x.off(),g&&(i=i.replace(/([_.])/g,"​$1")),requestAnimationFrame(function(){f?x.replaceWith(i):t.length?(x.remove(),t.html(i)):m.find(d).html(i)}),e&&n.error(e)}).always(function(){b(),n.unbind("resize",j),n.enable()}),w=function(t){var o=e.trim(x.val()),r=(n.splitFileExtention(o),!0),d=function(){x.off(),b(),f?x.replaceWith(n.escape(o)):C.html(n.escape(o)),i(y,s,c,o)};if(T.is(":hidden")||z.css("z-index",""),""===o){if(!n.isRoot(c))return A();f?x.replaceWith(n.escape(c.name)):C.html(n.escape(c.name))}if(!O&&z.length){if(x.off("blur"),1===l&&o===c.name)return y.reject();if(n.options.validName&&n.options.validName.test)try{r=n.options.validName.test(o)}catch(t){r=!1}if("."===o||".."===o||!r)return O=!0,n.error("directory"===c.mime?"errInvDirname":"errInvName",{modal:!0,close:function(){setTimeout(k,120)}}),!1;if(1===l&&n.fileByName(o,c.phash))return O=!0,n.error(["errExists",o],{modal:!0,close:function(){setTimeout(k,120)}}),!1;1===l?d():(n.confirm({title:"cmdrename",text:["renameMultiple",l,a(o,[c.hash].concat(s))],accept:{label:"btnYes",callback:d},cancel:{label:"btnCancel",callback:function(){setTimeout(function(){O=!0,k()},120)}}}),setTimeout(function(){n.trigger("unselectfiles",{files:n.selected()}).trigger("selectfiles",{files:[c.hash].concat(s)})},120))}},x=e(g?"":'').on("keyup text",function(){g?(this.style.height="1px",this.style.height=this.scrollHeight+"px"):r&&(this.style.width=r+"px",this.scrollWidth>r&&(this.style.width=this.scrollWidth+10+"px"))}).on("keydown",function(t){t.stopImmediatePropagation(),t.keyCode==e.ui.keyCode.ESCAPE?y.reject():t.keyCode==e.ui.keyCode.ENTER&&(t.preventDefault(),x.trigger("blur"))}).on("mousedown click dblclick",function(e){e.stopPropagation(),"dblclick"===e.type&&e.preventDefault()}).on("blur",w).on("dragenter dragleave dragover drop",function(e){e.stopPropagation()}),k=function(){var e=n.splitFileExtention(x.val())[0];O||!n.UA.Mobile||n.UA.iOS||(T.on("click close",A).elfinderoverlay("show"),z.css("z-index",T.css("z-index")+1)),!n.enabled()&&n.enable(),O&&(O=!1,x.on("blur",w)),x.trigger("focus").trigger("select"),x[0].setSelectionRange&&x[0].setSelectionRange(0,e.length)},C=f?m.contents().filter(function(){return 3==this.nodeType&&e(this).parent().attr("id")===n.navHash2Id(c.hash)}):m.find(d),z=C.parent(),T=n.getUI("overlay"),A=function(e){T.is(":hidden")||z.css("z-index",""),O||(y.reject(),e&&(e.stopPropagation(),e.preventDefault()))},j=function(){m.trigger("scrolltoview",{blink:!1})},O=!1;return z.addClass("ui-front").css("position","relative").on("unselect."+n.namespace,v),n.bind("resize",j),f?C.replaceWith(x.val(c.name)):(g?C.css("max-height","none"):f||(r=z.width(),z.width(r-15).parent("td").css("overflow","visible")),C.empty().append(x.val(c.name))),l>1&&n.api<=2.103?y.reject():c&&C.length?c.locked&&!n.isRoot(c)?y.reject(["errLocked",c.name]):(n.one("select",function(){x.parent().length&&c&&e.inArray(c.hash,n.selected())===-1&&x.trigger("blur")}),x.trigger("keyup"),k(),y):y.reject("errCmdParams",this.title)},n.bind("select contextmenucreate closecontextmenu",function(e){var i,a=(e.data?e.data.selected||e.data.targets:null)||n.selected();a&&1===a.length&&(i=n.file(a[0]))&&n.isRoot(i)?t.title=n.i18n("kindAlias")+" ("+n.i18n("preference")+")":t.title=n.i18n("cmdrename"),"closecontextmenu"!==e.type?t.update(void 0,t.title):requestAnimationFrame(function(){t.update(void 0,t.title)})}).remove(function(t){var i;t.data&&t.data.removed&&(i=n.storage("rootNames"))&&(e.each(t.data.removed,function(e,t){i[t]&&delete i[t]}),n.storage("rootNames",i))})},i.prototype.commands.resize=function(){"use strict";var t=this.fm,n=0,i=function(t,n,i){var a=[{x:t/2,y:n/2},{x:-t/2,y:n/2},{x:-t/2,y:-n/2},{x:t/2,y:-n/2}],o=[],r={x:Number.MAX_VALUE,y:Number.MAX_VALUE},s={x:Number.MIN_VALUE,y:Number.MIN_VALUE};return e.each(a,function(e,t){o.push({x:t.x*Math.cos(i)-t.y*Math.sin(i),y:t.x*Math.sin(i)+t.y*Math.cos(i)})}),e.each(o,function(e,t){r.x=Math.min(r.x,t.x),r.y=Math.min(r.y,t.y),s.x=Math.max(s.x,t.x),s.y=Math.max(s.y,t.y)}),{width:s.x-r.x,height:s.y-r.y}};this.updateOnSelect=!1,this.getstate=function(){var e=t.selectedFiles();return 1==e.length&&e[0].read&&e[0].write&&e[0].mime.indexOf("image/")!==-1?0:-1},this.resizeRequest=function(n,i,a){var o=i||t.file(n.target),r=(o?o.tmb:null,t.isCommandEnabled("resize",n.target));if(r&&(!o||o&&o.read&&o.write&&o.mime.indexOf("image/")!==-1))return t.request({data:Object.assign(n,{cmd:"resize"}),notify:{type:"resize",cnt:1}}).fail(function(e){a&&a.reject(e)}).done(function(){n.quality&&t.storage("jpgQuality",n.quality===t.option("jpgQuality")?null:n.quality),a&&a.resolve()});var s;return s=o?o.mime.indexOf("image/")===-1?["errResize",o.name,"errUsupportType"]:["errResize",o.name,"errPerm"]:["errResize",n.target,"errPerm"],a?a.reject(s):t.error(s),e.Deferred().reject(s)},this.exec=function(a){var o,r,s,l,c=this,d=this.files(a),p=e.Deferred(),u=t.api>1,h=this.options,f=650,m=t.getUI(),g=e().controlgroup?"controlgroup":"buttonset",v="undefined"==typeof h.grid8px||"disable"!==h.grid8px,b=Array.isArray(h.presetSize)?h.presetSize:[],y="elfinder-dialog-active",w=t.res("class","editing"),x=function(a,o,r){var d,x,k,C,z,T="image/jpeg"===a.mime,A=e('
          '),j='',O='
          ',S='
          ',I=null,M=!1,E=function(){M=!0},F=function(){M&&(M=!1,D.trigger("change"))},D=e('
          ').on("focus","input[type=text],input[type=number]",function(){e(this).trigger("select")}).on("change",function(){I&&cancelAnimationFrame(I),I=requestAnimationFrame(function(){var e,n,a,o,r,s,c,d,p,u,h,f;at&&!M&&(a=at.data("canvas"))&&(e=D.children("div.elfinder-resize-control-panel:visible"),n=e.find("input.elfinder-resize-quality"),n.is(":visible")&&(o=at.data("ctx"),r=at.get(0),e.hasClass("elfinder-resize-uiresize")?(d=a.width=X.val(),p=a.height=J.val(),o.drawImage(r,0,0,d,p)):e.hasClass("elfinder-resize-uicrop")?(s=G.val(),c=Y.val(),d=Q.val(),p=Z.val(),a.width=d,a.height=p,o.drawImage(r,s,c,d,p,0,0,d,p)):(u=te.val(),h=te.val()*Math.PI/180,f=i(fe,me,h),d=a.width=f.width,p=a.height=f.height,o.save(),u%90!==0&&(o.fillStyle=de.val()||"#FFF",o.fillRect(0,0,d,p)),o.translate(d/2,p/2),o.rotate(h),o.drawImage(r,-r.width/2,-r.height/2,fe,me),o.restore()),a.toBlob(function(e){e&&(l=e.size,n.next("span").text(" ("+t.formatSize(e.size)+")"))},"image/jpeg",Math.max(Math.min(n.val(),100),1)/100)))})}).on("mouseup","input",function(t){e(t.target).trigger("change")}),U=e('
          ').on("touchmove",function(t){e(t.target).hasClass("touch-punch")&&(t.stopPropagation(),t.preventDefault())}),P=e('
          '+t.i18n("ntfloadimg")+"
          "),q=e('
          '),R=e('
          '),H=e('
          '),_=e('
          '),N=e('
          '),L=e("").attr("title",t.i18n("rotate-cw")).append(e('')),W=e("").attr("title",t.i18n("rotate-ccw")).append(e('')),B=e(""),$=e('").on("mouseenter mouseleave",function(t){e(this).toggleClass("ui-state-hover","mouseenter"==t.type)}).on("click",function(){d.exec("open",f).done(function(){d.one("opendone",function(){d.trigger("selectfiles",{files:e.map(t.added,function(e){return e.hash})})})})})):d.trigger("selectfiles",{files:e.map(t.added,function(e){return e.hash})}),d.toast({msg:d.i18n(["complete",d.i18n("cmdupload")]),extNode:n}))}}).progress(function(){w.notifyWith(this,Array.from(arguments))})},v=function(e){i.elfinderdialog("close"),h&&(e.target=h[0]),g(e)},b=function(){var t=m.hash,n=e.map(d.files(t),function(e){return"directory"===e.mime&&e.write?e:null});return n.length?e('
          ').on("click",function(t){t.stopPropagation(),t.preventDefault(),n=d.sortFiles(n);var a=e(this),o=(d.cwd(),i.closest("div.ui-dialog")),r=function(e,t){return{label:d.escape(e.i18||e.name),icon:t,remain:!1,callback:function(){var t=o.children(".ui-dialog-titlebar:first").find("span.elfinder-upload-target");h=[e.hash],t.html(" - "+d.escape(e.i18||e.name)),a.trigger("focus")},options:{className:h&&h.length&&e.hash===h[0]?"ui-state-active":"",iconClass:e.csscls||"",iconImg:e.icon||""}}},s=[r(m,"opendir"),"|"];e.each(n,function(e,t){s.push(r(t,"dir"))}),a.trigger("blur"),d.trigger("contextmenu",{raw:s,x:t.pageX||e(this).offset().left,y:t.pageY||e(this).offset().top,prevNode:o,fitHeight:!0})}).append(''):e()},y=function(n,i){var a=e('").on("click",function(){d.UA.IE&&setTimeout(function(){o.css("display","none").css("position","relative"),requestAnimationFrame(function(){o.css("display","").css("position","")})},100)}).on("change",function(){v({input:a.get(0),type:"files"})}).on("dragover",function(e){e.originalEvent.dataTransfer.dropEffect="copy"}),o=e("
          ").append(a).on("click",function(e){e.stopPropagation()});return e('
          '+d.i18n(i)+"
          ").append(o).on("click",function(e){e.stopPropagation(),e.preventDefault(),a.trigger("click")}).on("mouseenter mouseleave",function(n){e(this).toggleClass(t,"mouseenter"===n.type)})},w=e.Deferred();return r=function(t){t.stopPropagation(),t.preventDefault();var n,i=!1,a="",o=null,r="",s=null,l=t._target||null,c=t.dataTransfer||null,p=c.items&&c.items.length&&c.items[0].kind?c.items[0].kind:"";if(c){try{if(o=c.getData("elfinderfrom"),o&&(r=window.location.href+d.cwd().hash,!l&&o===r||l===r))return void w.reject()}catch(t){}if("file"===p&&(c.items[0].getAsEntry||c.items[0].webkitGetAsEntry))i=c,a="data";else if("string"!==p&&c.files&&c.files.length&&e.inArray("Text",c.types)===-1)i=c.files,a="files";else{try{(s=c.getData("text/html"))&&s.match(/<(?:img|a)/i)&&(i=[s],a="html")}catch(t){}i||((s=c.getData("text"))?(i=[s],a="text"):c&&c.files&&(p="file"))}}i?g({files:i,type:a,target:l,dropEvt:t}):(n=["errUploadNoFiles"],"file"===p&&n.push("errFolderUpload"),d.error(n),w.reject())},!h&&n?(n.input||n.files?(n.type="files",g(n)):n.dropEvt&&r(n.dropEvt),w):(s=function(t){var n,i=t.originalEvent||t,a=[],o=[];if(i.clipboardData){if(i.clipboardData.items&&i.clipboardData.items.length){o=i.clipboardData.items;for(var r=0;r').append(y("multiple","selectForUpload")),!d.UA.Mobile&&function(e){return"undefined"!=typeof e.webkitdirectory||"undefined"!=typeof e.directory}(document.createElement("input"))&&i.append(y("multiple webkitdirectory directory","selectFolder")),m.dirs&&(m.hash===p||d.navHash2Elm(m.hash).hasClass("elfinder-subtree-loaded")?b().appendTo(i):(l=e('
          ').append('').appendTo(i),d.request({cmd:"tree",target:m.hash}).done(function(){d.one("treedone",function(){l.replaceWith(b()),c.elfinderdialog("tabstopsInit")})}).fail(function(){l.remove()}))),d.dragUpload?a=e('
          ').on("paste",function(e){s(e)}).on("mousedown click",function(){e(this).trigger("focus")}).on("focus",function(){this.innerHTML=""}).on("mouseover",function(){e(this).addClass(t)}).on("mouseout",function(){e(this).removeClass(t)}).on("dragenter",function(n){n.stopPropagation(),n.preventDefault(),e(this).addClass(t)}).on("dragleave",function(n){n.stopPropagation(),n.preventDefault(),e(this).removeClass(t)}).on("dragover",function(n){n.stopPropagation(),n.preventDefault(),n.originalEvent.dataTransfer.dropEffect="copy",e(this).addClass(t)}).on("drop",function(e){i.elfinderdialog("close"),h&&(e.originalEvent._target=h[0]),r(e.originalEvent)}).prependTo(i).after('
          '+d.i18n("or")+"
          ")[0]:o=e('
          '+d.i18n("dropFilesBrowser")+"
          ").on("paste drop",function(e){s(e)}).on("mousedown click",function(){e(this).trigger("focus")}).on("focus",function(){this.innerHTML=""}).on("dragenter mouseover",function(){e(this).addClass(t)}).on("dragleave mouseout",function(){e(this).removeClass(t)}).prependTo(i).after('
          '+d.i18n("or")+"
          ")[0],c=this.fmDialog(i,{title:this.title+''+(m?" - "+d.escape(m.i18||m.name):"")+"",modal:!0,resizable:!1,destroyOnClose:!0,propagationEvents:["mousemove","mouseup","click"],close:function(){var e=d.getUI("contextmenu");e.is(":visible")&&e.click()}}),w)}},i.prototype.commands.view=function(){"use strict";var t,n=this,i=this.fm;this.value=i.viewType,this.alwaysEnabled=!0,this.updateOnSelect=!1,this.options={ui:"viewbutton"},this.getstate=function(){return 0},this.extra={icon:"menu",node:e("").attr({title:i.i18n("viewtype")}).on("click touchstart",function(t){if(!("touchstart"===t.type&&t.originalEvent.touches.length>1)){var n=e(this);t.stopPropagation(),t.preventDefault(),i.trigger("contextmenu",{raw:getSubMenuRaw(),x:n.offset().left,y:n.offset().top})}})},this.exec=function(){var e=this,t="list"==this.value?"icons":"list";return i.storage("view",t),i.lazy(function(){i.viewchange(),e.update(void 0,t),this.resolve()})},i.bind("init",function(){t=function(){var e,t=i.getUI("cwd"),a=[],o=i.options.uiOptions.cwd.iconsView.sizeNames,r=i.options.uiOptions.cwd.iconsView.sizeMax;for(e=0;e<=r;e++)a.push({label:i.i18n(o[e]||"Size-"+e+" icons"),icon:"view",callback:function(e){return function(){t.trigger("iconpref",{size:e}),i.storage("iconsize",e),"list"===n.value&&n.exec()}}(e)});return a.push("|"),a.push({label:i.i18n("viewlist"),icon:"view-list",callback:function(){"list"!==n.value&&n.exec()}}),a}()}).bind("contextmenucreate",function(){n.extra={icon:"menu",node:e("").attr({title:i.i18n("cmdview")}).on("click touchstart",function(a){if(!("touchstart"===a.type&&a.originalEvent.touches.length>1)){var o,r,s=e(this);t.concat();for(o="list"===n.value?t.length-1:parseInt(i.storage("iconsize")||0),r=0;r') + .html('' + fm.i18n('ntfloadimg') + '') + .hide() + .appendTo(this), + setup = function() { + node.attr('id', id+'-img') + .attr('src', url || content) + .css({'height':'', 'max-width':'100%', 'max-height':'100%', 'cursor':'pointer'}) + .data('loading', function(done) { + var btns = node.closest('.elfinder-dialog').find('button,.elfinder-titlebar-button'); + btns.prop('disabled', !done)[done? 'removeClass' : 'addClass']('ui-state-disabled'); + node.css('opacity', done? '' : '0.3'); + spnr[done? 'hide' : 'show'](); + return node; + }); + }, + url; + + if (!content.match(/^data:/)) { + fm.openUrl(file.hash, false, function(v) { + url = v; + node.attr('_src', content); + setup(); + }); + } else { + setup(); + } + }, + imgBase64 = function(node, mime) { + var style = node.attr('style'), + img, canvas, ctx, data; + try { + // reset css for getting image size + node.attr('style', ''); + // img node + img = node.get(0); + // New Canvas + canvas = document.createElement('canvas'); + canvas.width = img.width; + canvas.height = img.height; + // restore css + node.attr('style', style); + // Draw Image + canvas.getContext('2d').drawImage(img, 0, 0); + // To Base64 + data = canvas.toDataURL(mime); + } catch(e) { + data = node.attr('src'); + } + return data; + }, + iframeClose = function(ifm) { + var $ifm = $(ifm), + dfd = $.Deferred().always(function() { + $ifm.off('load', load); + }), + ab = 'about:blank', + chk = function() { + tm = setTimeout(function() { + var src; + try { + src = base.contentWindow.location.href; + } catch(e) { + src = null; + } + if (src === ab) { + dfd.resolve(); + } else if (--cnt > 0){ + chk(); + } else { + dfd.reject(); + } + }, 500); + }, + load = function() { + tm && clearTimeout(tm); + dfd.resolve(); + }, + cnt = 20, // 500ms * 20 = 10sec wait + tm; + $ifm.one('load', load); + ifm.src = ab; + chk(); + return dfd; + }; + + // check getfile callback function + if (getfile) { + getfile = getfile[1]; + if (getfile === 'ckeditor') { + elFinder.prototype._options.getFileCallback = function(file, fm) { + window.opener.CKEDITOR.tools.callFunction((function() { + var reParam = new RegExp('(?:[\?&]|&)CKEditorFuncNum=([^&]+)', 'i'), + match = window.location.search.match(reParam); + return (match && match.length > 1) ? match[1] : ''; + })(), fm.convAbsUrl(file.url)); + fm.destroy(); + window.close(); + }; + } + } + + // return editors Array + return [ + { + // tui.image-editor - https://github.com/nhnent/tui.image-editor + info : { + id: 'tuiimgedit', + name: 'TUI Image Editor', + iconImg: 'img/editor-icons.png 0 -48', + dataScheme: true, + schemeContent: true, + openMaximized: true, + canMakeEmpty: false, + integrate: { + title: 'TOAST UI Image Editor', + link: 'http://ui.toast.com/tui-image-editor/' + } + }, + // MIME types to accept + mimes : ['image/jpeg', 'image/png', 'image/gif', 'image/svg+xml', 'image/x-ms-bmp'], + // HTML of this editor + html : '
          ', + // called on initialization of elFinder cmd edit (this: this editor's config object) + setup : function(opts, fm) { + if (fm.UA.ltIE8 || fm.UA.Mobile) { + this.disabled = true; + } else { + this.opts = Object.assign({ + version: 'v3.9.0' + }, opts.extraOptions.tuiImgEditOpts || {}, { + iconsPath : fm.baseUrl + 'img/tui-', + theme : {} + }); + if (!fm.isSameOrigin(this.opts.iconsPath)) { + this.disabled = true; + fm.debug('warning', 'Setting `commandOptions.edit.extraOptions.tuiImgEditOpts.iconsPath` MUST follow the same origin policy.'); + } + } + }, + // Initialization of editing node (this: this editors HTML node) + init : function(id, file, content, fm) { + this.data('url', content); + }, + load : function(base) { + var self = this, + fm = this.fm, + dfrd = $.Deferred(), + cdns = fm.options.cdns, + ver = self.confObj.opts.version, + init = function(editor) { + var $base = $(base), + bParent = $base.parent(), + opts = self.confObj.opts, + iconsPath = opts.iconsPath, + tmpContainer = $('
          ').appendTo(bParent), + tmpDiv = [ + $('
          ').appendTo(tmpContainer), + $('
          ').appendTo(tmpContainer) + ], + iEditor = new editor(base, { + includeUI: { + loadImage: { + path: $base.data('url'), + name: self.file.name + }, + theme: Object.assign(opts.theme, { + 'menu.normalIcon.path': iconsPath + 'icon-d.svg', + 'menu.normalIcon.name': 'icon-d', + 'menu.activeIcon.path': iconsPath + 'icon-b.svg', + 'menu.activeIcon.name': 'icon-b', + 'menu.disabledIcon.path': iconsPath + 'icon-a.svg', + 'menu.disabledIcon.name': 'icon-a', + 'menu.hoverIcon.path': iconsPath + 'icon-c.svg', + 'menu.hoverIcon.name': 'icon-c', + 'submenu.normalIcon.path': iconsPath + 'icon-d.svg', + 'submenu.normalIcon.name': 'icon-d', + 'submenu.activeIcon.path': iconsPath + 'icon-c.svg', + 'submenu.activeIcon.name': 'icon-c' + }), + initMenu: 'filter', + menuBarPosition: 'bottom' + }, + cssMaxWidth: Math.max(300, bParent.width()), + cssMaxHeight: Math.max(200, bParent.height() - (tmpDiv[0].height() + tmpDiv[1].height() + 3 /*margin*/)), + usageStatistics: false + }), + canvas = $base.find('canvas:first').get(0), + zoom = function(v) { + if (typeof v !== 'undefined') { + var c = $(canvas), + w = parseInt(c.attr('width')), + h = parseInt(c.attr('height')), + a = w / h, + mw, mh; + if (v === 0) { + mw = w; + mh = h; + } else { + mw = parseInt(c.css('max-width')) + Number(v); + mh = mw / a; + if (mw > w && mh > h) { + mw = w; + mh = h; + } + } + per.text(Math.round(mw / w * 100) + '%'); + iEditor.resizeCanvasDimension({width: mw, height: mh}); + // continually change more + if (zoomMore) { + setTimeout(function() { + zoomMore && zoom(v); + }, 50); + } + } + }, + zup = $('').data('val', 10), + zdown = $('').data('val', -10), + per = $('').css('width', '4em').text('%').attr('title', '100%').data('val', 0), + quty, qutyTm, zoomTm, zoomMore; + + tmpContainer.remove(); + $base.removeData('url').data('mime', self.file.mime); + // jpeg quality controls + if (self.file.mime === 'image/jpeg') { + $base.data('quality', fm.storage('jpgQuality') || fm.option('jpgQuality')); + quty = $('') + .attr('min', '1') + .attr('max', '100') + .attr('title', '1 - 100') + .on('change', function() { + var q = quty.val(); + $base.data('quality', q); + qutyTm && cancelAnimationFrame(qutyTm); + qutyTm = requestAnimationFrame(function() { + canvas.toBlob(function(blob) { + blob && quty.next('span').text(' (' + fm.formatSize(blob.size) + ')'); + }, 'image/jpeg', Math.max(Math.min(q, 100), 1) / 100); + }); + }) + .val($base.data('quality')); + $('
          ') + .append( + $('').html(fm.i18n('quality') + ' : '), quty, $('') + ) + .prependTo($base.parent().next()); + } else if (self.file.mime === 'image/svg+xml') { + $base.closest('.ui-dialog').trigger('changeType', { + extention: 'png', + mime : 'image/png', + keepEditor: true + }); + } + // zoom scale controls + $('
          ') + .append( + zdown, per, zup + ) + .attr('title', fm.i18n('scale')) + .on('click', 'span,button', function() { + zoom($(this).data('val')); + }) + .on('mousedown mouseup mouseleave', 'span', function(e) { + zoomMore = false; + zoomTm && clearTimeout(zoomTm); + if (e.type === 'mousedown') { + zoomTm = setTimeout(function() { + zoomMore = true; + zoom($(e.target).data('val')); + }, 500); + } + }) + .prependTo($base.parent().next()); + + // wait canvas ready + setTimeout(function() { + dfrd.resolve(iEditor); + if (quty) { + quty.trigger('change'); + iEditor.on('redoStackChanged undoStackChanged', function() { + quty.trigger('change'); + }); + } + // show initial scale + zoom(null); + }, 100); + + // show color slider (maybe TUI-Image-Editor's bug) + // see https://github.com/nhn/tui.image-editor/issues/153 + $base.find('.tui-colorpicker-palette-container').on('click', '.tui-colorpicker-palette-preview', function() { + $(this).closest('.color-picker-control').height('auto').find('.tui-colorpicker-slider-container').toggle(); + }); + $base.on('click', function() { + $base.find('.tui-colorpicker-slider-container').hide(); + }); + }, + loader; + + if (!self.confObj.editor) { + loader = $.Deferred(); + fm.loadCss([ + cdns.tui + '/tui-color-picker/latest/tui-color-picker.css', + cdns.tui + '/tui-image-editor/'+ver+'/tui-image-editor.css' + ]); + if (fm.hasRequire) { + require.config({ + paths : { + 'fabric/dist/fabric.require' : cdns.fabric + '/fabric.require.min', // for fabric < 2.0.1 + 'fabric' : cdns.fabric + '/fabric.min', // for fabric >= 2.0.1 + 'tui-code-snippet' : cdns.tui + '/tui.code-snippet/latest/tui-code-snippet.min', + 'tui-color-picker' : cdns.tui + '/tui-color-picker/latest/tui-color-picker.min', + 'tui-image-editor' : cdns.tui + '/tui-image-editor/'+ver+'/tui-image-editor.min' + } + }); + require(['tui-image-editor'], function(ImageEditor) { + loader.resolve(ImageEditor); + }); + } else { + fm.loadScript([ + cdns.fabric + '/fabric.min.js', + cdns.tui + '/tui.code-snippet/latest/tui-code-snippet.min.js' + ], function() { + fm.loadScript([ + cdns.tui + '/tui-color-picker/latest/tui-color-picker.min.js' + ], function() { + fm.loadScript([ + cdns.tui + '/tui-image-editor/'+ver+'/tui-image-editor.min.js' + ], function() { + loader.resolve(window.tui.ImageEditor); + }, { + loadType: 'tag' + }); + }, { + loadType: 'tag' + }); + }, { + loadType: 'tag' + }); + } + loader.done(function(editor) { + self.confObj.editor = editor; + init(editor); + }); + } else { + init(self.confObj.editor); + } + return dfrd; + }, + getContent : function(base) { + var editor = this.editor, + fm = editor.fm, + $base = $(base), + quality = $base.data('quality'); + if (editor.instance) { + if ($base.data('mime') === 'image/jpeg') { + quality = quality || fm.storage('jpgQuality') || fm.option('jpgQuality'); + quality = Math.max(0.1, Math.min(1, quality / 100)); + } + return editor.instance.toDataURL({ + format: getExtention($base.data('mime'), fm, true), + quality: quality + }); + } + }, + save : function(base) { + var $base = $(base), + quality = $base.data('quality'), + hash = $base.data('hash'), + file; + this.instance.deactivateAll(); + if (typeof quality !== 'undefined') { + this.fm.storage('jpgQuality', quality); + } + if (hash) { + file = this.fm.file(hash); + $base.data('mime', file.mime); + } + } + }, + { + // Photopea advanced image editor + info : { + id : 'photopea', + name : 'Photopea', + iconImg : 'img/editor-icons.png 0 -160', + single: true, + noContent: true, + arrayBufferContent: true, + openMaximized: true, + // Disable file types that cannot be saved on Photopea. + canMakeEmpty: ['image/jpeg', 'image/png', 'image/gif', 'image/svg+xml', 'image/x-ms-bmp', 'image/tiff', /*'image/x-adobe-dng',*/ 'image/webp', /*'image/x-xcf',*/ 'image/vnd.adobe.photoshop', 'application/pdf', 'image/x-portable-pixmap', 'image/x-sketch', 'image/x-icon', 'image/vnd-ms.dds', /*'application/x-msmetafile'*/], + integrate: { + title: 'Photopea', + link: 'https://www.photopea.com/learn/' + } + }, + mimes : ['image/jpeg', 'image/png', 'image/gif', 'image/svg+xml', 'image/x-ms-bmp', 'image/tiff', 'image/x-adobe-dng', 'image/webp', 'image/x-xcf', 'image/vnd.adobe.photoshop', 'application/pdf', 'image/x-portable-pixmap', 'image/x-sketch', 'image/x-icon', 'image/vnd-ms.dds', 'application/x-msmetafile'], + html : '', + // setup on elFinder bootup + setup : function(opts, fm) { + if (fm.UA.IE || fm.UA.Mobile) { + this.disabled = true; + } + }, + // Initialization of editing node (this: this editors HTML node) + init : function(id, file, dum, fm) { + var orig = 'https://www.photopea.com', + ifm = $(this).hide() + //.css('box-sizing', 'border-box') + .on('load', function() { + //spnr.remove(); + ifm.show(); + }) + .on('error', function() { + spnr.remove(); + ifm.show(); + }), + editor = this.editor, + confObj = editor.confObj, + spnr = $('
          ') + .html('' + fm.i18n('nowLoading') + '') + .appendTo(ifm.parent()), + saveMimes = fm.arrayFlip(confObj.info.canMakeEmpty), + getType = function(mime) { + var ext = getExtention(mime, fm), + extmime = ext2mime[ext]; + + if (!confObj.mimesFlip[extmime]) { + ext = ''; + } else if (ext === 'jpeg') { + ext = 'jpg'; + } + if (!ext || !saveMimes[extmime]) { + ext = 'psd'; + extmime = ext2mime[ext]; + ifm.closest('.ui-dialog').trigger('changeType', { + extention: ext, + mime : extmime, + keepEditor: true + }); + } + return ext; + }, + mime = file.mime, + liveMsg, type, quty; + + if (!confObj.mimesFlip) { + confObj.mimesFlip = fm.arrayFlip(confObj.mimes, true); + } + if (!confObj.liveMsg) { + confObj.liveMsg = function(ifm, spnr, file) { + var wnd = ifm.get(0).contentWindow, + phase = 0, + data = null, + dfdIni = $.Deferred().done(function() { + spnr.remove(); + phase = 1; + wnd.postMessage(data, orig); + }), + dfdGet; + + this.load = function() { + return fm.getContents(file.hash, 'arraybuffer').done(function(d) { + data = d; + }); + }; + + this.receive = function(e) { + var ev = e.originalEvent, + state; + if (ev.origin === orig && ev.source === wnd) { + if (ev.data === 'done') { + if (phase === 0) { + dfdIni.resolve(); + } else if (phase === 1) { + phase = 2; + ifm.trigger('contentsloaded'); + } else { + if (dfdGet && dfdGet.state() === 'pending') { + dfdGet.reject('errDataEmpty'); + } + } + } else if (ev.data === 'Save') { + editor.doSave(); + } else { + if (dfdGet && dfdGet.state() === 'pending') { + if (typeof ev.data === 'object') { + dfdGet.resolve('data:' + mime + ';base64,' + fm.arrayBufferToBase64(ev.data)); + } else { + dfdGet.reject('errDataEmpty'); + } + } + } + } + }; + + this.getContent = function() { + var type, q; + if (phase > 1) { + dfdGet && dfdGet.state() === 'pending' && dfdGet.reject(); + dfdGet = null; + dfdGet = $.Deferred(); + if (phase === 2) { + phase = 3; + dfdGet.resolve('data:' + mime + ';base64,' + fm.arrayBufferToBase64(data)); + data = null; + return dfdGet; + } + if (ifm.data('mime')) { + mime = ifm.data('mime'); + type = getType(mime); + } + if (q = ifm.data('quality')) { + type += ':' + (q / 100); + } + wnd.postMessage('app.activeDocument.saveToOE("' + type + '")', orig); + return dfdGet; + } + }; + }; + } + + ifm.parent().css('padding', 0); + type = getType(file.mime); + liveMsg = editor.liveMsg = new confObj.liveMsg(ifm, spnr, file); + $(window).on('message.' + fm.namespace, liveMsg.receive); + liveMsg.load().done(function() { + var d = JSON.stringify({ + files : [], + environment : { + lang: fm.lang.replace(/_/g, '-'), + customIO: {"save": "app.echoToOE(\"Save\");"} + } + }); + ifm.attr('src', orig + '/#' + encodeURI(d)); + }).fail(function(err) { + err && fm.error(err); + editor.initFail = true; + }); + + // jpeg quality controls + if (file.mime === 'image/jpeg' || file.mime === 'image/webp') { + ifm.data('quality', fm.storage('jpgQuality') || fm.option('jpgQuality')); + quty = $('') + .attr('min', '1') + .attr('max', '100') + .attr('title', '1 - 100') + .on('change', function() { + var q = quty.val(); + ifm.data('quality', q); + }) + .val(ifm.data('quality')); + $('
          ') + .append( + $('').html(fm.i18n('quality') + ' : '), quty, $('') + ) + .prependTo(ifm.parent().next()); + } + }, + load : function(base) { + var dfd = $.Deferred(), + self = this, + fm = this.fm, + $base = $(base); + if (self.initFail) { + dfd.reject(); + } else { + $base.on('contentsloaded', function() { + dfd.resolve(self.liveMsg); + }); + } + return dfd; + }, + getContent : function() { + return this.editor.liveMsg? this.editor.liveMsg.getContent() : void(0); + }, + save : function(base, liveMsg) { + var $base = $(base), + quality = $base.data('quality'), + hash = $base.data('hash'), + file; + if (typeof quality !== 'undefined') { + this.fm.storage('jpgQuality', quality); + } + if (hash) { + file = this.fm.file(hash); + $base.data('mime', file.mime); + } else { + $base.removeData('mime'); + } + }, + // On dialog closed + close : function(base, liveMsg) { + $(base).attr('src', ''); + liveMsg && $(window).off('message.' + this.fm.namespace, liveMsg.receive); + } + }, + { + // Pixo is cross-platform image editor + info : { + id : 'pixo', + name : 'Pixo Editor', + iconImg : 'img/editor-icons.png 0 -208', + dataScheme: true, + schemeContent: true, + single: true, + canMakeEmpty: false, + integrate: { + title: 'Pixo Editor', + link: 'https://pixoeditor.com/privacy-policy/' + } + }, + // MIME types to accept + mimes : ['image/jpeg', 'image/png', 'image/gif', 'image/svg+xml', 'image/x-ms-bmp'], + // HTML of this editor + html : '
          ', + // called on initialization of elFinder cmd edit (this: this editor's config object) + setup : function(opts, fm) { + if (fm.UA.ltIE8 || !opts.extraOptions || !opts.extraOptions.pixo || !opts.extraOptions.pixo.apikey) { + this.disabled = true; + } else { + this.editorOpts = opts.extraOptions.pixo; + } + }, + // Initialization of editing node (this: this editors HTML node) + init : function(id, file, content, fm) { + initImgTag.call(this, id, file, content, fm); + }, + // Get data uri scheme (this: this editors HTML node) + getContent : function() { + return $(this).children('img:first').attr('src'); + }, + // Launch Pixo editor when dialog open + load : function(base) { + var self = this, + fm = this.fm, + $base = $(base), + node = $base.children('img:first'), + dialog = $base.closest('.ui-dialog'), + elfNode = fm.getUI(), + dfrd = $.Deferred(), + container = $('#elfinder-pixo-container'), + init = function(onload) { + var opts; + + if (!container.length) { + container = $('
          ').css({ + position: 'fixed', + top: 0, + right: 0, + width: '100%', + height: $(window).height(), + overflow: 'hidden' + }).hide().appendTo(elfNode.hasClass('elfinder-fullscreen')? elfNode : 'body'); + // bind switch fullscreen event + elfNode.on('resize.'+fm.namespace, function(e, data) { + e.preventDefault(); + e.stopPropagation(); + data && data.fullscreen && container.appendTo(data.fullscreen === 'on'? elfNode : 'body'); + }); + fm.bind('destroy', function() { + editor && editor.cancelEditing(); + container.remove(); + }); + } else { + // always moves to last + container.appendTo(container.parent()); + } + node.on('click', launch); + // Constructor options + opts = Object.assign({ + type: 'child', + parent: container.get(0), + output: {format: 'png'}, + onSave: function(arg) { + // Check current file.hash, all callbacks are called on multiple instances + var mime = arg.toBlob().type, + ext = getExtention(mime, fm), + draw = function(url) { + node.one('load error', function() { + node.data('loading') && node.data('loading')(true); + }) + .attr('crossorigin', 'anonymous') + .attr('src', url); + }, + url = arg.toDataURL(); + node.data('loading')(); + delete base._canvas; + if (node.data('ext') !== ext) { + changeImageType(url, self.file.mime).done(function(res, cv) { + if (cv) { + base._canvas = canvas = cv; + quty.trigger('change'); + qBase && qBase.show(); + } + draw(res); + }).fail(function() { + dialog.trigger('changeType', { + extention: ext, + mime : mime + }); + draw(url); + }); + } else { + draw(url); + } + }, + onClose: function() { + dialog.removeClass(fm.res('class', 'preventback')); + fm.toggleMaximize(container, false); + container.hide(); + fm.toFront(dialog); + } + }, self.confObj.editorOpts); + // trigger event 'editEditorPrepare' + self.trigger('Prepare', { + node: base, + editorObj: Pixo, + instance: void(0), + opts: opts + }); + // make editor instance + editor = new Pixo.Bridge(opts); + dfrd.resolve(editor); + $base.on('saveAsFail', launch); + if (onload) { + onload(); + } + }, + launch = function() { + dialog.addClass(fm.res('class', 'preventback')); + fm.toggleMaximize(container, true); + fm.toFront(container); + container.show().data('curhash', self.file.hash); + editor.edit(node.get(0)); + node.data('loading')(true); + }, + qBase, quty, qutyTm, canvas, editor; + + node.data('loading')(); + + // jpeg quality controls + if (self.file.mime === 'image/jpeg') { + quty = $('') + .attr('min', '1') + .attr('max', '100') + .attr('title', '1 - 100') + .on('change', function() { + var q = quty.val(); + qutyTm && cancelAnimationFrame(qutyTm); + qutyTm = requestAnimationFrame(function() { + if (canvas) { + canvas.toBlob(function(blob) { + blob && quty.next('span').text(' (' + fm.formatSize(blob.size) + ')'); + }, 'image/jpeg', Math.max(Math.min(q, 100), 1) / 100); + } + }); + }) + .val(fm.storage('jpgQuality') || fm.option('jpgQuality')); + qBase = $('
          ') + .hide() + .append( + $('').html(fm.i18n('quality') + ' : '), quty, $('') + ) + .prependTo($base.parent().next()); + $base.data('quty', quty); + } + + // load script then init + if (typeof Pixo === 'undefined') { + fm.loadScript(['https://pixoeditor.com:8443/editor/scripts/bridge.m.js'], function() { + init(launch); + }, {loadType: 'tag'}); + } else { + init(); + launch(); + } + return dfrd; + }, + // Convert content url to data uri scheme to save content + save : function(base) { + var self = this, + $base = $(base), + node = $base.children('img:first'), + q; + if (base._canvas) { + if ($base.data('quty')) { + q = $base.data('quty').val(); + q && this.fm.storage('jpgQuality', q); + } + node.attr('src', base._canvas.toDataURL(self.file.mime, q? Math.max(Math.min(q, 100), 1) / 100 : void(0))); + } else if (node.attr('src').substr(0, 5) !== 'data:') { + node.attr('src', imgBase64(node, this.file.mime)); + } + }, + close : function(base, editor) { + editor && editor.destroy(); + } + }, + { + // ACE Editor + // called on initialization of elFinder cmd edit (this: this editor's config object) + setup : function(opts, fm) { + if (fm.UA.ltIE8 || !fm.options.cdns.ace) { + this.disabled = true; + } + }, + // `mimes` is not set for support everything kind of text file + info : { + id : 'aceeditor', + name : 'ACE Editor', + iconImg : 'img/editor-icons.png 0 -96' + }, + load : function(textarea) { + var self = this, + fm = this.fm, + dfrd = $.Deferred(), + cdn = fm.options.cdns.ace, + start = function() { + var editor, editorBase, mode, + ta = $(textarea), + taBase = ta.parent(), + dialog = taBase.parent(), + id = textarea.id + '_ace', + ext = self.file.name.replace(/^.+\.([^.]+)|(.+)$/, '$1$2').toLowerCase(), + // MIME/mode map + mimeMode = { + 'text/x-php' : 'php', + 'application/x-php' : 'php', + 'text/html' : 'html', + 'application/xhtml+xml' : 'html', + 'text/javascript' : 'javascript', + 'application/javascript' : 'javascript', + 'text/css' : 'css', + 'text/x-c' : 'c_cpp', + 'text/x-csrc' : 'c_cpp', + 'text/x-chdr' : 'c_cpp', + 'text/x-c++' : 'c_cpp', + 'text/x-c++src' : 'c_cpp', + 'text/x-c++hdr' : 'c_cpp', + 'text/x-shellscript' : 'sh', + 'application/x-csh' : 'sh', + 'text/x-python' : 'python', + 'text/x-java' : 'java', + 'text/x-java-source' : 'java', + 'text/x-ruby' : 'ruby', + 'text/x-perl' : 'perl', + 'application/x-perl' : 'perl', + 'text/x-sql' : 'sql', + 'text/xml' : 'xml', + 'application/docbook+xml' : 'xml', + 'application/xml' : 'xml' + }; + + // set base height + taBase.height(taBase.height()); + + // set basePath of ace + ace.config.set('basePath', cdn); + + // Base node of Ace editor + editorBase = $('
          ').text(ta.val()).insertBefore(ta.hide()); + + // Editor flag + ta.data('ace', true); + + // Aceeditor instance + editor = ace.edit(id); + + // Ace editor configure + editor.$blockScrolling = Infinity; + editor.setOptions({ + theme: 'ace/theme/monokai', + fontSize: '14px', + wrap: true, + }); + ace.config.loadModule('ace/ext/modelist', function() { + // detect mode + mode = ace.require('ace/ext/modelist').getModeForPath('/' + self.file.name).name; + if (mode === 'text') { + if (mimeMode[self.file.mime]) { + mode = mimeMode[self.file.mime]; + } + } + // show MIME:mode in title bar + taBase.prev().children('.elfinder-dialog-title').append(' (' + self.file.mime + ' : ' + mode.split(/[\/\\]/).pop() + ')'); + editor.setOptions({ + mode: 'ace/mode/' + mode + }); + if (dfrd.state() === 'resolved') { + dialog.trigger('resize'); + } + }); + ace.config.loadModule('ace/ext/language_tools', function() { + ace.require('ace/ext/language_tools'); + editor.setOptions({ + enableBasicAutocompletion: true, + enableSnippets: true, + enableLiveAutocompletion: false + }); + }); + ace.config.loadModule('ace/ext/settings_menu', function() { + ace.require('ace/ext/settings_menu').init(editor); + }); + + // Short cuts + editor.commands.addCommand({ + name : "saveFile", + bindKey: { + win : 'Ctrl-s', + mac : 'Command-s' + }, + exec: function(editor) { + self.doSave(); + } + }); + editor.commands.addCommand({ + name : "closeEditor", + bindKey: { + win : 'Ctrl-w|Ctrl-q', + mac : 'Command-w|Command-q' + }, + exec: function(editor) { + self.doCancel(); + } + }); + + editor.resize(); + + // TextArea button and Setting button + $('
          ').css('float', 'left') + .append( + $('').html(self.fm.i18n('TextArea')) + .button() + .on('click', function(){ + if (ta.data('ace')) { + ta.removeData('ace'); + editorBase.hide(); + ta.val(editor.session.getValue()).show().trigger('focus'); + $(this).text('AceEditor'); + } else { + ta.data('ace', true); + editorBase.show(); + editor.setValue(ta.hide().val(), -1); + editor.focus(); + $(this).html(self.fm.i18n('TextArea')); + } + }) + ) + .append( + $('') + .button({ + icons: { + primary: 'ui-icon-gear', + secondary: 'ui-icon-triangle-1-e' + }, + text: false + }) + .on('click', function(){ + editor.showSettingsMenu(); + $('#ace_settingsmenu') + .css('font-size', '80%') + .find('div[contains="setOptions"]').hide().end() + .parent().appendTo($('#elfinder')); + }) + ) + .prependTo(taBase.next()); + + // trigger event 'editEditorPrepare' + self.trigger('Prepare', { + node: textarea, + editorObj: ace, + instance: editor, + opts: {} + }); + + //dialog.trigger('resize'); + dfrd.resolve(editor); + }; + + // check ace & start + if (!self.confObj.loader) { + self.confObj.loader = $.Deferred(); + self.fm.loadScript([ cdn+'/ace.js' ], function() { + self.confObj.loader.resolve(); + }, void 0, {obj: window, name: 'ace'}); + } + self.confObj.loader.done(start); + + return dfrd; + }, + close : function(textarea, instance) { + instance && instance.destroy(); + }, + save : function(textarea, instance) { + instance && $(textarea).data('ace') && (textarea.value = instance.session.getValue()); + }, + focus : function(textarea, instance) { + instance && $(textarea).data('ace') && instance.focus(); + }, + resize : function(textarea, instance, e, data) { + instance && instance.resize(); + } + }, + { + // CodeMirror + // called on initialization of elFinder cmd edit (this: this editor's config object) + setup : function(opts, fm) { + if (fm.UA.ltIE10 || !fm.options.cdns.codemirror) { + this.disabled = true; + } + }, + // `mimes` is not set for support everything kind of text file + info : { + id : 'codemirror', + name : 'CodeMirror', + iconImg : 'img/editor-icons.png 0 -176' + }, + load : function(textarea) { + var fm = this.fm, + cmUrl = fm.convAbsUrl(fm.options.cdns.codemirror), + dfrd = $.Deferred(), + self = this, + start = function(CodeMirror) { + var ta = $(textarea), + base = ta.parent(), + editor, editorBase, opts; + + // set base height + base.height(base.height()); + + // CodeMirror configure options + opts = { + lineNumbers: true, + lineWrapping: true, + extraKeys : { + 'Ctrl-S': function() { self.doSave(); }, + 'Ctrl-Q': function() { self.doCancel(); }, + 'Ctrl-W': function() { self.doCancel(); } + } + }; + + // trigger event 'editEditorPrepare' + self.trigger('Prepare', { + node: textarea, + editorObj: CodeMirror, + instance: void(0), + opts: opts + }); + + // CodeMirror configure + editor = CodeMirror.fromTextArea(textarea, opts); + + // return editor instance + dfrd.resolve(editor); + + // Auto mode set + var info, m, mode, spec; + if (! info) { + info = CodeMirror.findModeByMIME(self.file.mime); + } + if (! info && (m = self.file.name.match(/.+\.([^.]+)$/))) { + info = CodeMirror.findModeByExtension(m[1]); + } + if (info) { + CodeMirror.modeURL = useRequire? 'codemirror/mode/%N/%N.min' : cmUrl + '/mode/%N/%N.min.js'; + mode = info.mode; + spec = info.mime; + editor.setOption('mode', spec); + CodeMirror.autoLoadMode(editor, mode); + // show MIME:mode in title bar + base.prev().children('.elfinder-dialog-title').append(' (' + spec + (mode != 'null'? ' : ' + mode : '') + ')'); + } + + // editor base node + editorBase = $(editor.getWrapperElement()).css({ + // fix CSS conflict to SimpleMDE + padding: 0, + border: 'none' + }); + ta.data('cm', true); + + // fit height to base + editorBase.height('100%'); + + // TextArea button and Setting button + $('
          ').css('float', 'left') + .append( + $('').html(self.fm.i18n('TextArea')) + .button() + .on('click', function(){ + if (ta.data('cm')) { + ta.removeData('cm'); + editorBase.hide(); + ta.val(editor.getValue()).show().trigger('focus'); + $(this).text('CodeMirror'); + } else { + ta.data('cm', true); + editorBase.show(); + editor.setValue(ta.hide().val()); + editor.refresh(); + editor.focus(); + $(this).html(self.fm.i18n('TextArea')); + } + }) + ) + .prependTo(base.next()); + }; + // load script then start + if (!self.confObj.loader) { + self.confObj.loader = $.Deferred(); + if (useRequire) { + require.config({ + packages: [{ + name: 'codemirror', + location: cmUrl, + main: 'codemirror.min' + }], + map: { + 'codemirror': { + 'codemirror/lib/codemirror': 'codemirror' + } + } + }); + require([ + 'codemirror', + 'codemirror/addon/mode/loadmode.min', + 'codemirror/mode/meta.min' + ], function(CodeMirror) { + self.confObj.loader.resolve(CodeMirror); + }); + } else { + self.fm.loadScript([ + cmUrl + '/codemirror.min.js' + ], function() { + self.fm.loadScript([ + cmUrl + '/addon/mode/loadmode.min.js', + cmUrl + '/mode/meta.min.js' + ], function() { + self.confObj.loader.resolve(CodeMirror); + }); + }, {loadType: 'tag'}); + } + self.fm.loadCss(cmUrl + '/codemirror.css'); + } + self.confObj.loader.done(start); + return dfrd; + }, + close : function(textarea, instance) { + instance && instance.toTextArea(); + }, + save : function(textarea, instance) { + instance && $(textarea).data('cm') && (textarea.value = instance.getValue()); + }, + focus : function(textarea, instance) { + instance && $(textarea).data('cm') && instance.focus(); + }, + resize : function(textarea, instance, e, data) { + instance && instance.refresh(); + } + }, + { + // SimpleMDE + // called on initialization of elFinder cmd edit (this: this editor's config object) + setup : function(opts, fm) { + if (fm.UA.ltIE10 || !fm.options.cdns.simplemde) { + this.disabled = true; + } + }, + info : { + id : 'simplemde', + name : 'SimpleMDE', + iconImg : 'img/editor-icons.png 0 -80' + }, + exts : ['md'], + load : function(textarea) { + var self = this, + fm = this.fm, + base = $(textarea).parent(), + dfrd = $.Deferred(), + cdn = fm.options.cdns.simplemde, + start = function(SimpleMDE) { + var h = base.height(), + delta = base.outerHeight(true) - h + 14, + editor, editorBase, opts; + + // fit height function + textarea._setHeight = function(height) { + var h = height || base.height(), + ctrH = 0, + areaH; + base.children('.editor-toolbar,.editor-statusbar').each(function() { + ctrH += $(this).outerHeight(true); + }); + areaH = h - ctrH - delta; + editorBase.height(areaH); + editor.codemirror.refresh(); + return areaH; + }; + + // set base height + base.height(h); + + opts = { + element: textarea, + autofocus: true + }; + + // trigger event 'editEditorPrepare' + self.trigger('Prepare', { + node: textarea, + editorObj: SimpleMDE, + instance: void(0), + opts: opts + }); + + // make editor + editor = new SimpleMDE(opts); + dfrd.resolve(editor); + + // editor base node + editorBase = $(editor.codemirror.getWrapperElement()); + + // fit height to base + editorBase.css('min-height', '50px') + .children('.CodeMirror-scroll').css('min-height', '50px'); + textarea._setHeight(h); + }; + + // check SimpleMDE & start + if (!self.confObj.loader) { + self.confObj.loader = $.Deferred(); + self.fm.loadCss(cdn+'/simplemde.min.css'); + if (useRequire) { + require([ + cdn+'/simplemde.min.js' + ], function(SimpleMDE) { + self.confObj.loader.resolve(SimpleMDE); + }); + } else { + self.fm.loadScript([cdn+'/simplemde.min.js'], function() { + self.confObj.loader.resolve(SimpleMDE); + }, {loadType: 'tag'}); + } + } + self.confObj.loader.done(start); + + return dfrd; + }, + close : function(textarea, instance) { + instance && instance.toTextArea(); + instance = null; + }, + save : function(textarea, instance) { + instance && (textarea.value = instance.value()); + }, + focus : function(textarea, instance) { + instance && instance.codemirror.focus(); + }, + resize : function(textarea, instance, e, data) { + instance && textarea._setHeight(); + } + }, + { + // CKEditor for html file + info : { + id : 'ckeditor', + name : 'CKEditor', + iconImg : 'img/editor-icons.png 0 0' + }, + exts : ['htm', 'html', 'xhtml'], + setup : function(opts, fm) { + var confObj = this; + if (!fm.options.cdns.ckeditor) { + confObj.disabled = true; + } else { + confObj.ckeOpts = {}; + if (opts.extraOptions) { + confObj.ckeOpts = Object.assign({}, opts.extraOptions.ckeditor || {}); + if (opts.extraOptions.managerUrl) { + confObj.managerUrl = opts.extraOptions.managerUrl; + } + } + } + }, + load : function(textarea) { + var self = this, + fm = this.fm, + dfrd = $.Deferred(), + init = function() { + var base = $(textarea).parent(), + dlg = base.closest('.elfinder-dialog'), + h = base.height(), + reg = /([&?]getfile=)[^&]+/, + loc = self.confObj.managerUrl || window.location.href.replace(/#.*$/, ''), + name = 'ckeditor', + opts; + + // make manager location + if (reg.test(loc)) { + loc = loc.replace(reg, '$1' + name); + } else { + loc += '?getfile=' + name; + } + // set base height + base.height(h); + + // CKEditor configure options + opts = { + startupFocus : true, + fullPage: true, + allowedContent: true, + filebrowserBrowseUrl : loc, + toolbarCanCollapse: true, + toolbarStartupExpanded: !fm.UA.Mobile, + removePlugins: 'resize', + extraPlugins: 'colorbutton,justify,docprops', + on: { + 'instanceReady' : function(e) { + var editor = e.editor; + editor.resize('100%', h); + // re-build on dom move + dlg.one('beforedommove.'+fm.namespace, function() { + editor.destroy(); + }).one('dommove.'+fm.namespace, function() { + self.load(textarea).done(function(editor) { + self.instance = editor; + }); + }); + // return editor instance + dfrd.resolve(e.editor); + } + } + }; + + // trigger event 'editEditorPrepare' + self.trigger('Prepare', { + node: textarea, + editorObj: CKEDITOR, + instance: void(0), + opts: opts + }); + + // CKEditor configure + CKEDITOR.replace(textarea.id, Object.assign(opts, self.confObj.ckeOpts)); + CKEDITOR.on('dialogDefinition', function(e) { + var dlg = e.data.definition.dialog; + dlg.on('show', function(e) { + fm.getUI().append($('.cke_dialog_background_cover')).append(this.getElement().$); + }); + dlg.on('hide', function(e) { + $('body:first').append($('.cke_dialog_background_cover')).append(this.getElement().$); + }); + }); + }; + + if (!self.confObj.loader) { + self.confObj.loader = $.Deferred(); + window.CKEDITOR_BASEPATH = fm.options.cdns.ckeditor + '/'; + $.getScript(fm.options.cdns.ckeditor + '/ckeditor.js', function() { + self.confObj.loader.resolve(); + }); + } + self.confObj.loader.done(init); + return dfrd; + }, + close : function(textarea, instance) { + instance && instance.destroy(); + }, + save : function(textarea, instance) { + instance && (textarea.value = instance.getData()); + }, + focus : function(textarea, instance) { + instance && instance.focus(); + }, + resize : function(textarea, instance, e, data) { + var self; + if (instance) { + if (instance.status === 'ready') { + instance.resize('100%', $(textarea).parent().height()); + } + } + } + }, + { + // CKEditor5 balloon mode for html file + info : { + id : 'ckeditor5', + name : 'CKEditor5', + iconImg : 'img/editor-icons.png 0 -16' + }, + exts : ['htm', 'html', 'xhtml'], + html : '
          ', + setup : function(opts, fm) { + var confObj = this; + // check cdn and ES6 support + if (!fm.options.cdns.ckeditor5 || typeof window.Symbol !== 'function' || typeof Symbol() !== 'symbol') { + confObj.disabled = true; + } else { + confObj.ckeOpts = {}; + if (opts.extraOptions) { + // @deprecated option extraOptions.ckeditor5Mode + if (opts.extraOptions.ckeditor5Mode) { + confObj.ckeditor5Mode = opts.extraOptions.ckeditor5Mode; + } + confObj.ckeOpts = Object.assign({}, opts.extraOptions.ckeditor5 || {}); + if (confObj.ckeOpts.mode) { + confObj.ckeditor5Mode = confObj.ckeOpts.mode; + delete confObj.ckeOpts.mode; + } + if (opts.extraOptions.managerUrl) { + confObj.managerUrl = opts.extraOptions.managerUrl; + } + } + } + fm.bind('destroy', function() { + confObj.editor = null; + }); + }, + // Prepare on before show dialog + prepare : function(base, dialogOpts, file) { + $(base).height(base.editor.fm.getUI().height() - 100); + }, + init : function(id, file, data, fm) { + var m = data.match(/^([\s\S]*]*>)([\s\S]+)(<\/body>[\s\S]*)$/i), + header = '', + body = '', + footer =''; + this.css({ + width: '100%', + height: '100%', + 'box-sizing': 'border-box' + }); + if (m) { + header = m[1]; + body = m[2]; + footer = m[3]; + } else { + body = data; + } + this.data('data', { + header: header, + body: body, + footer: footer + }); + this._setupSelEncoding(data); + }, + load : function(editnode) { + var self = this, + fm = this.fm, + dfrd = $.Deferred(), + mode = self.confObj.ckeditor5Mode || 'decoupled-document', + lang = (function() { + var l = fm.lang.toLowerCase().replace('_', '-'); + if (l.substr(0, 2) === 'zh' && l !== 'zh-cn') { + l = 'zh'; + } + return l; + })(), + init = function(cEditor) { + var base = $(editnode).parent(), + opts; + + // set base height + base.height(fm.getUI().height() - 100); + + // CKEditor5 configure options + opts = Object.assign({ + toolbar: ["heading", "|", "fontSize", "fontFamily", "|", "bold", "italic", "underline", "strikethrough", "highlight", "|", "alignment", "|", "numberedList", "bulletedList", "blockQuote", "indent", "outdent", "|", "ckfinder", "link", "imageUpload", "insertTable", "mediaEmbed", "|", "undo", "redo"], + language: lang + }, self.confObj.ckeOpts); + + // trigger event 'editEditorPrepare' + self.trigger('Prepare', { + node: editnode, + editorObj: cEditor, + instance: void(0), + opts: opts + }); + + cEditor + .create(editnode, opts) + .then(function(editor) { + var ckf = editor.commands.get('ckfinder'), + fileRepo = editor.plugins.get('FileRepository'), + prevVars = {}, isImage, insertImages; + if (editor.ui.view.toolbar && (mode === 'classic' || mode === 'decoupled-document')) { + $(editnode).closest('.elfinder-dialog').children('.ui-widget-header').append($(editor.ui.view.toolbar.element).css({marginRight:'-1em',marginLeft:'-1em'})); + } + if (mode === 'classic') { + $(editnode).closest('.elfinder-edit-editor').css('overflow', 'auto'); + } + // Set up this elFinder instead of CKFinder + if (ckf) { + isImage = function(f) { + return f && f.mime.match(/^image\//i); + }; + insertImages = function(urls) { + var imgCmd = editor.commands.get('imageUpload'); + if (!imgCmd.isEnabled) { + var ntf = editor.plugins.get('Notification'), + i18 = editor.locale.t; + ntf.showWarning(i18('Could not insert image at the current position.'), { + title: i18('Inserting image failed'), + namespace: 'ckfinder' + }); + return; + } + editor.execute('imageInsert', { source: urls }); + }; + // Take over ckfinder execute() + ckf.execute = function() { + var dlg = base.closest('.elfinder-dialog'), + gf = fm.getCommand('getfile'), + rever = function() { + if (prevVars.hasVar) { + dlg.off('resize close', rever); + gf.callback = prevVars.callback; + gf.options.folders = prevVars.folders; + gf.options.multiple = prevVars.multi; + fm.commandMap.open = prevVars.open; + prevVars.hasVar = false; + } + }; + dlg.trigger('togleminimize').one('resize close', rever); + prevVars.callback = gf.callback; + prevVars.folders = gf.options.folders; + prevVars.multi = gf.options.multiple; + prevVars.open = fm.commandMap.open; + prevVars.hasVar = true; + gf.callback = function(files) { + var imgs = []; + if (files.length === 1 && files[0].mime === 'directory') { + fm.one('open', function() { + fm.commandMap.open = 'getfile'; + }).getCommand('open').exec(files[0].hash); + return; + } + fm.getUI('cwd').trigger('unselectall'); + $.each(files, function(i, f) { + if (isImage(f)) { + imgs.push(fm.convAbsUrl(f.url)); + } else { + editor.execute('link', fm.convAbsUrl(f.url)); + } + }); + if (imgs.length) { + insertImages(imgs); + } + dlg.trigger('togleminimize'); + }; + gf.options.folders = true; + gf.options.multiple = true; + fm.commandMap.open = 'getfile'; + fm.toast({ + mode: 'info', + msg: fm.i18n('dblclickToSelect') + }); + }; + } + // Set up image uploader + fileRepo.createUploadAdapter = function(loader) { + return new uploder(loader); + }; + editor.setData($(editnode).data('data').body); + // move .ck-body to elFinder node for fullscreen mode + fm.getUI().append($('body > div.ck-body')); + $('div.ck-balloon-panel').css({ + 'z-index': fm.getMaximizeCss().zIndex + 1 + }); + dfrd.resolve(editor); + /*fm.log({ + defaultConfig: cEditor.defaultConfig, + plugins: cEditor.builtinPlugins.map(function(p) { return p.pluginName; }), + toolbars: Array.from(editor.ui.componentFactory.names()) + });*/ + }) + ['catch'](function(error) { // ['cache'] instead .cache for fix error on ie8 + fm.error(error); + }); + }, + uploder = function(loader) { + var upload = function(file, resolve, reject) { + fm.exec('upload', {files: [file]}, void(0), fm.cwd().hash) + .done(function(data){ + if (data.added && data.added.length) { + fm.url(data.added[0].hash, { async: true }).done(function(url) { + resolve({ + 'default': fm.convAbsUrl(url) + }); + }).fail(function() { + reject('errFileNotFound'); + }); + } else { + reject(fm.i18n(data.error? data.error : 'errUpload')); + } + }) + .fail(function(err) { + var error = fm.parseError(err); + reject(fm.i18n(error? (error === 'userabort'? 'errAbort' : error) : 'errUploadNoFiles')); + }) + .progress(function(data) { + loader.uploadTotal = data.total; + loader.uploaded = data.progress; + }); + }; + this.upload = function() { + return new Promise(function(resolve, reject) { + if (loader.file instanceof Promise || (loader.file && typeof loader.file.then === 'function')) { + loader.file.then(function(file) { + upload(file, resolve, reject); + }); + } else { + upload(loader.file, resolve, reject); + } + }); + }; + this.abort = function() { + fm.getUI().trigger('uploadabort'); + }; + }, loader; + + if (!self.confObj.editor) { + loader = $.Deferred(); + self.fm.loadScript([ + fm.options.cdns.ckeditor5 + '/' + mode + '/ckeditor.js' + ], function(editor) { + if (!editor) { + editor = window.BalloonEditor || window.InlineEditor || window.ClassicEditor || window.DecoupledEditor; + } + if (fm.lang !== 'en') { + self.fm.loadScript([ + fm.options.cdns.ckeditor5 + '/' + mode + '/translations/' + lang + '.js' + ], function(obj) { + loader.resolve(editor); + }, { + tryRequire: true, + loadType: 'tag', + error: function(obj) { + lang = 'en'; + loader.resolve(editor); + } + }); + } else { + loader.resolve(editor); + } + }, { + tryRequire: true, + loadType: 'tag' + }); + loader.done(function(editor) { + self.confObj.editor = editor; + init(editor); + }); + } else { + init(self.confObj.editor); + } + return dfrd; + }, + getContent : function() { + var data = $(this).data('data'); + return data.header + data.body + data.footer; + }, + close : function(editnode, instance) { + instance && instance.destroy(); + }, + save : function(editnode, instance) { + var elm = $(editnode), + data = elm.data('data'); + if (instance) { + data.body = instance.getData(); + elm.data('data', data); + } + }, + focus : function(editnode, instance) { + $(editnode).trigger('focus'); + } + }, + { + // TinyMCE for html file + info : { + id : 'tinymce', + name : 'TinyMCE', + iconImg : 'img/editor-icons.png 0 -64' + }, + exts : ['htm', 'html', 'xhtml'], + setup : function(opts, fm) { + var confObj = this; + if (!fm.options.cdns.tinymce) { + confObj.disabled = true; + } else { + confObj.mceOpts = {}; + if (opts.extraOptions) { + confObj.uploadOpts = Object.assign({}, opts.extraOptions.uploadOpts || {}); + confObj.mceOpts = Object.assign({}, opts.extraOptions.tinymce || {}); + } else { + confObj.uploadOpts = {}; + } + } + }, + load : function(textarea) { + var self = this, + fm = this.fm, + dfrd = $.Deferred(), + init = function() { + var base = $(textarea).show().parent(), + dlg = base.closest('.elfinder-dialog'), + h = base.height(), + delta = base.outerHeight(true) - h, + // hide MCE dialog and modal block + hideMceDlg = function() { + var mceW; + if (tinymce.activeEditor.windowManager.windows) { + mceW = tinymce.activeEditor.windowManager.windows[0]; + mceDlg = $(mceW? mceW.getEl() : void(0)).hide(); + mceCv = $('#mce-modal-block').hide(); + } else { + mceDlg = $('.tox-dialog-wrap').hide(); + } + }, + // Show MCE dialog and modal block + showMceDlg = function() { + mceCv && mceCv.show(); + mceDlg && mceDlg.show(); + }, + tVer = tinymce.majorVersion, + opts, mceDlg, mceCv; + + // set base height + base.height(h); + // fit height function + textarea._setHeight = function(height) { + if (tVer < 5) { + var base = $(this).parent(), + h = height || base.innerHeight(), + ctrH = 0, + areaH; + base.find('.mce-container-body:first').children('.mce-top-part,.mce-statusbar').each(function() { + ctrH += $(this).outerHeight(true); + }); + areaH = h - ctrH - delta; + base.find('.mce-edit-area iframe:first').height(areaH); + } + }; + + // TinyMCE configure options + opts = { + selector: '#' + textarea.id, + resize: false, + plugins: 'print preview fullpage searchreplace autolink directionality visualblocks visualchars fullscreen image link media template codesample table charmap hr pagebreak nonbreaking anchor toc insertdatetime advlist lists wordcount imagetools textpattern help', + toolbar: 'formatselect | bold italic strikethrough forecolor backcolor | link image media | alignleft aligncenter alignright alignjustify | numlist bullist outdent indent | removeformat', + image_advtab: true, + init_instance_callback : function(editor) { + // fit height on init + textarea._setHeight(h); + // re-build on dom move + dlg.one('beforedommove.'+fm.namespace, function() { + tinymce.execCommand('mceRemoveEditor', false, textarea.id); + }).one('dommove.'+fm.namespace, function() { + self.load(textarea).done(function(editor) { + self.instance = editor; + }); + }); + // return editor instance + dfrd.resolve(editor); + }, + file_picker_callback : function (callback, value, meta) { + var gf = fm.getCommand('getfile'), + revar = function() { + if (prevVars.hasVar) { + gf.callback = prevVars.callback; + gf.options.folders = prevVars.folders; + gf.options.multiple = prevVars.multi; + fm.commandMap.open = prevVars.open; + prevVars.hasVar = false; + } + dlg.off('resize close', revar); + showMceDlg(); + }, + prevVars = {}; + prevVars.callback = gf.callback; + prevVars.folders = gf.options.folders; + prevVars.multi = gf.options.multiple; + prevVars.open = fm.commandMap.open; + prevVars.hasVar = true; + gf.callback = function(file) { + var url, info; + + if (file.mime === 'directory') { + fm.one('open', function() { + fm.commandMap.open = 'getfile'; + }).getCommand('open').exec(file.hash); + return; + } + + // URL normalization + url = fm.convAbsUrl(file.url); + + // Make file info + info = file.name + ' (' + fm.formatSize(file.size) + ')'; + + // Provide file and text for the link dialog + if (meta.filetype == 'file') { + callback(url, {text: info, title: info}); + } + + // Provide image and alt text for the image dialog + if (meta.filetype == 'image') { + callback(url, {alt: info}); + } + + // Provide alternative source and posted for the media dialog + if (meta.filetype == 'media') { + callback(url); + } + dlg.trigger('togleminimize'); + }; + gf.options.folders = true; + gf.options.multiple = false; + fm.commandMap.open = 'getfile'; + + hideMceDlg(); + dlg.trigger('togleminimize').one('resize close', revar); + fm.toast({ + mode: 'info', + msg: fm.i18n('dblclickToSelect') + }); + + return false; + }, + images_upload_handler : function (blobInfo, success, failure) { + var file = blobInfo.blob(), + err = function(e) { + var dlg = e.data.dialog || {}; + if (dlg.hasClass('elfinder-dialog-error') || dlg.hasClass('elfinder-confirm-upload')) { + hideMceDlg(); + dlg.trigger('togleminimize').one('resize close', revert); + fm.unbind('dialogopened', err); + } + }, + revert = function() { + dlg.off('resize close', revert); + showMceDlg(); + }, + clipdata = true; + + // check file object + if (file.name) { + // file blob of client side file object + clipdata = void(0); + } + fm.bind('dialogopened', err).exec('upload', Object.assign({ + files: [file], + clipdata: clipdata // to get unique name on connector + }, self.confObj.uploadOpts), void(0), fm.cwd().hash).done(function(data) { + if (data.added && data.added.length) { + fm.url(data.added[0].hash, { async: true }).done(function(url) { + showMceDlg(); + success(fm.convAbsUrl(url)); + }).fail(function() { + failure(fm.i18n('errFileNotFound')); + }); + } else { + failure(fm.i18n(data.error? data.error : 'errUpload')); + } + }).fail(function(err) { + var error = fm.parseError(err); + if (error) { + if (error === 'errUnknownCmd') { + error = 'errPerm'; + } else if (error === 'userabort') { + error = 'errAbort'; + } + } + failure(fm.i18n(error? error : 'errUploadNoFiles')); + }); + } + }; + + // TinyMCE 5 supports "height: 100%" + if (tVer >= 5) { + opts.height = '100%'; + } + + // trigger event 'editEditorPrepare' + self.trigger('Prepare', { + node: textarea, + editorObj: tinymce, + instance: void(0), + opts: opts + }); + + // TinyMCE configure + tinymce.init(Object.assign(opts, self.confObj.mceOpts)); + }; + + if (!self.confObj.loader) { + self.confObj.loader = $.Deferred(); + self.fm.loadScript([fm.options.cdns.tinymce + (fm.options.cdns.tinymce.match(/\.js/)? '' : '/tinymce.min.js')], function() { + self.confObj.loader.resolve(); + }, { + loadType: 'tag' + }); + } + self.confObj.loader.done(init); + return dfrd; + }, + close : function(textarea, instance) { + instance && tinymce.execCommand('mceRemoveEditor', false, textarea.id); + }, + save : function(textarea, instance) { + instance && instance.save(); + }, + focus : function(textarea, instance) { + instance && instance.focus(); + }, + resize : function(textarea, instance, e, data) { + // fit height to base node on dialog resize + instance && textarea._setHeight(); + } + }, + { + info : { + id : 'zohoeditor', + name : 'Zoho Editor', + iconImg : 'img/editor-icons.png 0 -32', + cmdCheck : 'ZohoOffice', + preventGet: true, + hideButtons: true, + syncInterval : 15000, + canMakeEmpty: true, + integrate: { + title: 'Zoho Office API', + link: 'https://www.zoho.com/officeapi/' + } + }, + mimes : [ + 'application/msword', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + //'application/pdf', + 'application/vnd.oasis.opendocument.text', + 'application/rtf', + 'text/html', + 'application/vnd.ms-excel', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'application/vnd.oasis.opendocument.spreadsheet', + 'application/vnd.sun.xml.calc', + 'text/csv', + 'text/tab-separated-values', + 'application/vnd.ms-powerpoint', + 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', + 'application/vnd.oasis.opendocument.presentation', + 'application/vnd.sun.xml.impress' + ], + html : '', + // setup on elFinder bootup + setup : function(opts, fm) { + if (fm.UA.Mobile || fm.UA.ltIE8) { + this.disabled = true; + } + }, + // Prepare on before show dialog + prepare : function(base, dialogOpts, file) { + var elfNode = base.editor.fm.getUI(); + $(base).height(elfNode.height()); + dialogOpts.width = Math.max(dialogOpts.width || 0, elfNode.width() * 0.8); + }, + // Initialization of editing node (this: this editors HTML node) + init : function(id, file, dum, fm) { + var ta = this, + ifm = $(this).hide(), + uiToast = fm.getUI('toast'), + spnr = $('
          ') + .html('' + fm.i18n('nowLoading') + '') + .appendTo(ifm.parent()), + cdata = function() { + var data = ''; + $.each(fm.customData, function(key, val) { + data += '&' + encodeURIComponent(key) + '=' + encodeURIComponent(val); + }); + return data; + }; + + $(ta).data('xhr', fm.request({ + data: { + cmd: 'editor', + name: ta.editor.confObj.info.cmdCheck, + method: 'init', + 'args[target]': file.hash, + 'args[lang]' : fm.lang, + 'args[cdata]' : cdata() + }, + preventDefault : true + }).done(function(data) { + var opts; + if (data.zohourl) { + opts = { + css: { + height: '100%' + } + }; + // trigger event 'editEditorPrepare' + ta.editor.trigger('Prepare', { + node: ta, + editorObj: void(0), + instance: ifm, + opts: opts + }); + + ifm.attr('src', data.zohourl).show().css(opts.css); + if (data.warning) { + uiToast.appendTo(ta.closest('.ui-dialog')); + fm.toast({ + msg: fm.i18n(data.warning), + mode: 'warning', + timeOut: 0, + onHidden: function() { + uiToast.children().length === 1 && uiToast.appendTo(fm.getUI()); + }, + button: { + text: 'btnYes' + } + }); + } + } else { + data.error && fm.error(data.error); + ta.elfinderdialog('destroy'); + } + }).fail(function(error) { + error && fm.error(error); + ta.elfinderdialog('destroy'); + }).always(function() { + spnr.remove(); + })); + }, + load : function() {}, + getContent : function() {}, + save : function() {}, + // Before dialog close + beforeclose : iframeClose, + // On dialog closed + close : function(ta) { + var fm = this.fm, + xhr = $(ta).data('xhr'); + if (xhr.state() === 'pending') { + xhr.reject(); + } + } + }, + { + // Zip Archive with FlySystem + info : { + id : 'ziparchive', + name : 'btnMount', + iconImg : 'img/toolbar.png 0 -416', + cmdCheck : 'ZipArchive', + edit : function(file, editor) { + var fm = this, + dfrd = $.Deferred(); + fm.request({ + data:{ + cmd: 'netmount', + protocol: 'ziparchive', + host: file.hash, + path: file.phash + }, + preventFail: true, + notify : {type : 'netmount', cnt : 1, hideCnt : true} + }).done(function(data) { + var pdir; + if (data.added && data.added.length) { + if (data.added[0].phash) { + if (pdir = fm.file(data.added[0].phash)) { + if (! pdir.dirs) { + pdir.dirs = 1; + fm.change({ changed: [ pdir ] }); + } + } + } + fm.one('netmountdone', function() { + fm.exec('open', data.added[0].hash); + fm.one('opendone', function() { + data.toast && fm.toast(data.toast); + }); + }); + } + dfrd.resolve(); + }) + .fail(function(error) { + dfrd.reject(error); + }); + return dfrd; + } + }, + mimes : ['application/zip'], + load : function() {}, + save : function(){} + }, + { + // Simple Text (basic textarea editor) + info : { + id : 'textarea', + name : 'TextArea', + useTextAreaEvent : true + }, + load : function(textarea) { + // trigger event 'editEditorPrepare' + this.trigger('Prepare', { + node: textarea, + editorObj: void(0), + instance: void(0), + opts: {} + }); + textarea.setSelectionRange && textarea.setSelectionRange(0, 0); + $(textarea).trigger('focus').show(); + }, + save : function(){} + }, + { + // File converter with online-convert.com + info : { + id : 'onlineconvert', + name : 'Online Convert', + iconImg : 'img/editor-icons.png 0 -144', + cmdCheck : 'OnlineConvert', + preventGet: true, + hideButtons: true, + single: true, + converter: true, + canMakeEmpty: false, + integrate: { + title: 'ONLINE-CONVERT.COM', + link: 'https://online-convert.com' + } + }, + mimes : ['*'], + html : '
          ', + // setup on elFinder bootup + setup : function(opts, fm) { + var mOpts = opts.extraOptions.onlineConvert || {maxSize:100,showLink:true}; + if (mOpts.maxSize) { + this.info.maxSize = mOpts.maxSize * 1048576; + } + this.set = Object.assign({ + url : 'https://%s.online-convert.com%s?external_url=', + conv : { + Archive: {'7Z':{}, 'BZ2':{ext:'bz'}, 'GZ':{}, 'ZIP':{}}, + Audio: {'MP3':{}, 'OGG':{ext:'oga'}, 'WAV':{}, 'WMA':{}, 'AAC':{}, 'AIFF':{ext:'aif'}, 'FLAC':{}, 'M4A':{}, 'MMF':{}, 'OPUS':{ext:'oga'}}, + Document: {'DOC':{}, 'DOCX':{}, 'HTML':{}, 'ODT':{}, 'PDF':{}, 'PPT':{}, 'PPTX':{}, 'RTF':{}, 'SWF':{}, 'TXT':{}}, + eBook: {'AZW3':{ext:'azw'}, 'ePub':{}, 'FB2':{ext:'xml'}, 'LIT':{}, 'LRF':{}, 'MOBI':{}, 'PDB':{}, 'PDF':{},'PDF-eBook':{ext:'pdf'}, 'TCR':{}}, + Hash: {'Adler32':{}, 'Apache-htpasswd':{}, 'Blowfish':{}, 'CRC32':{}, 'CRC32B':{}, 'Gost':{}, 'Haval128':{},'MD4':{}, 'MD5':{}, 'RIPEMD128':{}, 'RIPEMD160':{}, 'SHA1':{}, 'SHA256':{}, 'SHA384':{}, 'SHA512':{}, 'Snefru':{}, 'Std-DES':{}, 'Tiger128':{}, 'Tiger128-calculator':{}, 'Tiger128-converter':{}, 'Tiger160':{}, 'Tiger192':{}, 'Whirlpool':{}}, + Image: {'BMP':{}, 'EPS':{ext:'ai'}, 'GIF':{}, 'EXR':{}, 'ICO':{}, 'JPG':{}, 'PNG':{}, 'SVG':{}, 'TGA':{}, 'TIFF':{ext:'tif'}, 'WBMP':{}, 'WebP':{}}, + Video: {'3G2':{}, '3GP':{}, 'AVI':{}, 'FLV':{}, 'HLS':{ext:'m3u8'}, 'MKV':{}, 'MOV':{}, 'MP4':{}, 'MPEG-1':{ext:'mpeg'}, 'MPEG-2':{ext:'mpeg'}, 'OGG':{ext:'ogv'}, 'OGV':{}, 'WebM':{}, 'WMV':{}, 'Android':{link:'/convert-video-for-%s',ext:'mp4'}, 'Blackberry':{link:'/convert-video-for-%s',ext:'mp4'}, 'DPG':{link:'/convert-video-for-%s',ext:'avi'}, 'iPad':{link:'/convert-video-for-%s',ext:'mp4'}, 'iPhone':{link:'/convert-video-for-%s',ext:'mp4'}, 'iPod':{link:'/convert-video-for-%s',ext:'mp4'}, 'Nintendo-3DS':{link:'/convert-video-for-%s',ext:'avi'}, 'Nintendo-DS':{link:'/convert-video-for-%s',ext:'avi'}, 'PS3':{link:'/convert-video-for-%s',ext:'mp4'}, 'Wii':{link:'/convert-video-for-%s',ext:'avi'}, 'Xbox':{link:'/convert-video-for-%s',ext:'wmv'}} + }, + catExts : { + Hash: 'txt' + }, + link : '', + useTabs : ($.fn.tabs && !fm.UA.iOS)? true : false // Can't work on iOS, I don't know why. + }, mOpts); + }, + // Prepare on before show dialog + prepare : function(base, dialogOpts, file) { + var elfNode = base.editor.fm.getUI(); + $(base).height(elfNode.height()); + dialogOpts.width = Math.max(dialogOpts.width || 0, elfNode.width() * 0.8); + }, + // Initialization of editing node (this: this editors HTML node) + init : function(id, file, dum, fm) { + var ta = this, + confObj = ta.editor.confObj, + set = confObj.set, + uiToast = fm.getUI('toast'), + idxs = {}, + allowZip = fm.uploadMimeCheck('application/zip', file.phash), + selfUrl = $('base').length? document.location.href.replace(/#.*$/, '') : '', + getExt = function(cat, con) { + var c; + if (set.catExts[cat]) { + return set.catExts[cat]; + } + if (set.conv[cat] && (c = set.conv[cat][con])) { + return (c.ext || con).toLowerCase(); + } + return con.toLowerCase(); + }, + setOptions = function(cat, done) { + var type, dfdInit, dfd; + if (typeof confObj.api === 'undefined') { + dfdInit = fm.request({ + data: { + cmd: 'editor', + name: 'OnlineConvert', + method: 'init' + }, + preventDefault : true + }); + } else { + dfdInit = $.Deferred().resolve({api: confObj.api}); + } + cat = cat.toLowerCase(); + dfdInit.done(function(data) { + confObj.api = data.api; + if (confObj.api) { + if (cat) { + type = '?category=' + cat; + } else { + type = ''; + cat = 'all'; + } + if (!confObj.conversions) { + confObj.conversions = {}; + } + if (!confObj.conversions[cat]) { + dfd = $.getJSON('https://api2.online-convert.com/conversions' + type); + } else { + dfd = $.Deferred().resolve(confObj.conversions[cat]); + } + dfd.done(function(d) { + confObj.conversions[cat] = d; + $.each(d, function(i, o) { + btns[set.useTabs? 'children' : 'find']('.onlineconvert-category-' + o.category).children('.onlineconvert-' + o.target).trigger('makeoption', o); + }); + done && done(); + }); + } + }); + }, + btns = (function() { + var btns = $('
          ').on('click', 'button', function() { + var b = $(this), + opts = b.data('opts') || null, + cat = b.closest('.onlineconvert-category').data('cname'), + con = b.data('conv'); + if (confObj.api === true) { + api({ + category: cat, + convert: con, + options: opts + }); + } + }).on('change', function(e) { + var t = $(e.target), + p = t.parent(), + b = t.closest('.elfinder-edit-onlineconvert-button').children('button:first'), + o = b.data('opts') || {}, + v = p.data('type') === 'boolean'? t.is(':checked') : t.val(); + e.stopPropagation(); + if (v) { + if (p.data('type') === 'integer') { + v = parseInt(v); + } + if (p.data('pattern')) { + var reg = new RegExp(p.data('pattern')); + if (!reg.test(v)) { + requestAnimationFrame(function() { + fm.error('"' + fm.escape(v) + '" is not match to "/' + fm.escape(p.data('pattern')) + '/"'); + }); + v = null; + } + } + } + if (v) { + o[t.parent().data('optkey')] = v; + } else { + delete o[p.data('optkey')]; + } + b.data('opts', o); + }), + ul = $('
            '), + oform = function(n, o) { + var f = $('

            ').data('optkey', n).data('type', o.type), + checked = '', + disabled = '', + nozip = false, + opts, btn, elm; + if (o.description) { + f.attr('title', fm.i18n(o.description)); + } + if (o.pattern) { + f.data('pattern', o.pattern); + } + f.append($('').text(fm.i18n(n) + ' : ')); + if (o.type === 'boolean') { + if (o['default'] || (nozip = (n === 'allow_multiple_outputs' && !allowZip))) { + checked = ' checked'; + if (nozip) { + disabled = ' disabled'; + } + btn = this.children('button:first'); + opts = btn.data('opts') || {}; + opts[n] = true; + btn.data('opts', opts); + } + f.append($('')); + } else if (o['enum']){ + elm = $('').append($('').text('Select...')); + $.each(o['enum'], function(i, v) { + elm.append($('').text(v)); + }); + f.append(elm); + } else { + f.append($('')); + } + return f; + }, + makeOption = function(o) { + var elm = this, + b = $('').on('click', function() { + f.toggle(); + }), + f = $('
            ').hide(); + if (o.options) { + $.each(o.options, function(k, v) { + k !== 'download_password' && f.append(oform.call(elm, k, v)); + }); + } + elm.append(b, f); + }, + ts = (+new Date()), + i = 0; + + if (!confObj.ext2mime) { + confObj.ext2mime = Object.assign(fm.arrayFlip(fm.mimeTypes), ext2mime); + } + $.each(set.conv, function(t, c) { + var cname = t.toLowerCase(), + id = 'elfinder-edit-onlineconvert-' + cname + ts, + type = $('
            ').data('cname', t), + cext; + $.each(c, function(n, o) { + var nl = n.toLowerCase(), + ext = getExt(t, n); + if (!confObj.ext2mime[ext]) { + if (cname === 'audio' || cname === 'image' || cname === 'video') { + confObj.ext2mime[ext] = cname + '/x-' + nl; + } else { + confObj.ext2mime[ext] = 'application/octet-stream'; + } + } + if (fm.uploadMimeCheck(confObj.ext2mime[ext], file.phash)) { + type.append($('
            ').on('makeoption', function(e, data) { + var elm = $(this); + if (!elm.children('.elfinder-button-icon-preference').length) { + makeOption.call(elm, data); + } + }).append($('').text(n).data('conv', n))); + } + }); + if (type.children().length) { + ul.append($('
          • ').append($('').attr('href', selfUrl + '#' + id).text(t))); + btns.append(type); + idxs[cname] = i++; + } + }); + if (set.useTabs) { + btns.prepend(ul).tabs({ + beforeActivate: function(e, ui) { + setOptions(ui.newPanel.data('cname')); + } + }); + } else { + $.each(set.conv, function(t) { + var tl = t.toLowerCase(); + btns.append($('
            ').append($('').text(t)).append(btns.children('.onlineconvert-category-' + tl))); + }); + } + return btns; + })(), + select = $(this) + .append( + btns, + (set.showLink? $(set.link) : null) + ), + spnr = $('
            ') + .hide() + .html('' + fm.i18n('nowLoading') + '') + .appendTo(select.parent()), + prog = $('
            ').appendTo(spnr), + _url = null, + url = function() { + var onetime; + if (_url) { + return $.Deferred().resolve(_url); + } else { + spnr.show(); + return fm.forExternalUrl(file.hash, { progressBar: prog }).done(function(url) { + _url = url; + }).fail(function(error) { + error && fm.error(error); + ta.elfinderdialog('destroy'); + }).always(function() { + spnr.hide(); + }); + } + }, + api = function(opts) { + $(ta).data('dfrd', url().done(function(url) { + select.fadeOut(); + setStatus({info: 'Start conversion request.'}); + fm.request({ + data: { + cmd: 'editor', + name: 'OnlineConvert', + method: 'api', + 'args[category]' : opts.category.toLowerCase(), + 'args[convert]' : opts.convert.toLowerCase(), + 'args[options]' : JSON.stringify(opts.options), + 'args[source]' : fm.convAbsUrl(url), + 'args[filename]' : fm.splitFileExtention(file.name)[0] + '.' + getExt(opts.category, opts.convert), + 'args[mime]' : file.mime + }, + preventDefault : true + }).done(function(data) { + checkRes(data.apires, opts.category, opts.convert); + }).fail(function(error) { + error && fm.error(error); + ta.elfinderdialog('destroy'); + }); + })); + }, + checkRes = function(res, cat, con) { + var status, err = []; + if (res && res.id) { + status = res.status; + if (status.code === 'failed') { + spnr.hide(); + if (res.errors && res.errors.length) { + $.each(res.errors, function(i, o) { + o.message && err.push(o.message); + }); + } + fm.error(err.length? err : status.info); + select.fadeIn(); + } else if (status.code === 'completed') { + upload(res); + } else { + setStatus(status); + setTimeout(function() { + polling(res.id); + }, 1000); + } + } else { + uiToast.appendTo(ta.closest('.ui-dialog')); + if (res.message) { + fm.toast({ + msg: fm.i18n(res.message), + mode: 'error', + timeOut: 5000, + onHidden: function() { + uiToast.children().length === 1 && uiToast.appendTo(fm.getUI()); + } + }); + } + fm.toast({ + msg: fm.i18n('editorConvNoApi'), + mode: 'error', + timeOut: 3000, + onHidden: function() { + uiToast.children().length === 1 && uiToast.appendTo(fm.getUI()); + } + }); + spnr.hide(); + select.show(); + } + }, + setStatus = function(status) { + spnr.show().children('.elfinder-spinner-text').text(status.info); + }, + polling = function(jobid) { + fm.request({ + data: { + cmd: 'editor', + name: 'OnlineConvert', + method: 'api', + 'args[jobid]': jobid + }, + preventDefault : true + }).done(function(data) { + checkRes(data.apires); + }).fail(function(error) { + error && fm.error(error); + ta.elfinderdialog('destroy'); + }); + }, + upload = function(res) { + var output = res.output, + id = res.id, + url = ''; + spnr.hide(); + if (output && output.length) { + ta.elfinderdialog('destroy'); + $.each(output, function(i, o) { + if (o.uri) { + url += o.uri + '\n'; + } + }); + fm.upload({ + target: file.phash, + files: [url], + type: 'text', + extraData: { + contentSaveId: 'OnlineConvert-' + res.id + } + }); + } + }, + mode = 'document', + cl, m; + select.parent().css({overflow: 'auto'}).addClass('overflow-scrolling-touch'); + if (m = file.mime.match(/^(audio|image|video)/)) { + mode = m[1]; + } + if (set.useTabs) { + if (idxs[mode]) { + btns.tabs('option', 'active', idxs[mode]); + } + } else { + cl = Object.keys(set.conv).length; + $.each(set.conv, function(t) { + if (t.toLowerCase() === mode) { + setOptions(t, function() { + $.each(set.conv, function(t0) { + t0.toLowerCase() !== mode && setOptions(t0); + }); + }); + return false; + } + cl--; + }); + if (!cl) { + $.each(set.conv, function(t) { + setOptions(t); + }); + } + select.parent().scrollTop(btns.children('.onlineconvert-fieldset-' + mode).offset().top); + } + }, + load : function() {}, + getContent : function() {}, + save : function() {}, + // On dialog closed + close : function(ta) { + var fm = this.fm, + dfrd = $(ta).data('dfrd'); + if (dfrd && dfrd.state() === 'pending') { + dfrd.reject(); + } + } + } + ]; +}, window.elFinder)); diff --git a/panel/application/public/js/extras/editors.default.min.js b/panel/application/public/js/extras/editors.default.min.js new file mode 100644 index 0000000..9c973d3 --- /dev/null +++ b/panel/application/public/js/extras/editors.default.min.js @@ -0,0 +1,2 @@ +!function(e,t){if("function"==typeof define&&define.amd)define(["elfinder"],e);else if(t){var i=t.prototype._options.commandsOptions.edit.editors;t.prototype._options.commandsOptions.edit.editors=i.concat(e(t))}}(function(e){"use strict";var t,i=window.location.search.match(/getfile=([a-z]+)/),n=e.prototype.hasRequire,o={bmp:"image/x-ms-bmp",dng:"image/x-adobe-dng",gif:"image/gif",jpeg:"image/jpeg",jpg:"image/jpeg",pdf:"application/pdf",png:"image/png",ppm:"image/x-portable-pixmap",psd:"image/vnd.adobe.photoshop",pxd:"image/x-pixlr-data",svg:"image/svg+xml",tiff:"image/tiff",webp:"image/webp",xcf:"image/x-xcf",sketch:"application/x-sketch",ico:"image/x-icon",dds:"image/vnd-ms.dds",emf:"application/x-msmetafile"},a=function(e,i,n){t||(t=i.arrayFlip(o));var a=t[e]||i.mimeTypes[e];return n?"jpg"===a&&(a="jpeg"):"jpeg"===a&&(a="jpg"),a},r=function(e,t){var i=$.Deferred();try{var n=document.createElement("canvas"),o=n.getContext("2d"),a=new Image,r=function(){var e,o,a=n.toDataURL(t);e=(o=a.match(/^data:([a-z0-9]+\/[a-z0-9.+-]+)/i))?o[1]:"",e.toLowerCase()===t.toLowerCase()?i.resolve(n.toDataURL(t),n):i.reject()};return a.src=e,$(a).on("load",function(){try{n.width=a.width,n.height=a.height,o.drawImage(a,0,0),r()}catch(e){i.reject()}}).on("error",function(){i.reject()}),i}catch(s){return i.reject()}},s=function(e,t,i,n){var o,r=$(this).children("img:first").data("ext",a(t.mime,n)),s=$('
            ').html(''+n.i18n("ntfloadimg")+'').hide().appendTo(this),c=function(){r.attr("id",e+"-img").attr("src",o||i).css({height:"","max-width":"100%","max-height":"100%",cursor:"pointer"}).data("loading",function(e){var t=r.closest(".elfinder-dialog").find("button,.elfinder-titlebar-button");return t.prop("disabled",!e)[e?"removeClass":"addClass"]("ui-state-disabled"),r.css("opacity",e?"":"0.3"),s[e?"hide":"show"](),r})};i.match(/^data:/)?c():n.openUrl(t.hash,!1,function(e){o=e,r.attr("_src",i),c()})},c=function(e,t){var i,n,o,a=e.attr("style");try{e.attr("style",""),i=e.get(0),n=document.createElement("canvas"),n.width=i.width,n.height=i.height,e.attr("style",a),n.getContext("2d").drawImage(i,0,0),o=n.toDataURL(t)}catch(r){o=e.attr("src")}return o},d=function(e){var t,i=$(e),n=$.Deferred().always(function(){i.off("load",r)}),o="about:blank",a=function(){t=setTimeout(function(){var e;try{e=base.contentWindow.location.href}catch(t){e=null}e===o?n.resolve():--s>0?a():n.reject()},500)},r=function(){t&&clearTimeout(t),n.resolve()},s=20;return i.one("load",r),e.src=o,a(),n};return i&&(i=i[1],"ckeditor"===i&&(e.prototype._options.getFileCallback=function(e,t){window.opener.CKEDITOR.tools.callFunction(function(){var e=new RegExp("(?:[?&]|&)CKEditorFuncNum=([^&]+)","i"),t=window.location.search.match(e);return t&&t.length>1?t[1]:""}(),t.convAbsUrl(e.url)),t.destroy(),window.close()})),[{info:{id:"tuiimgedit",name:"TUI Image Editor",iconImg:"img/editor-icons.png 0 -48",dataScheme:!0,schemeContent:!0,openMaximized:!0,canMakeEmpty:!1,integrate:{title:"TOAST UI Image Editor",link:"http://ui.toast.com/tui-image-editor/"}},mimes:["image/jpeg","image/png","image/gif","image/svg+xml","image/x-ms-bmp"],html:'
            ',setup:function(e,t){t.UA.ltIE8||t.UA.Mobile?this.disabled=!0:(this.opts=Object.assign({version:"v3.9.0"},e.extraOptions.tuiImgEditOpts||{},{iconsPath:t.baseUrl+"img/tui-",theme:{}}),t.isSameOrigin(this.opts.iconsPath)||(this.disabled=!0,t.debug("warning","Setting `commandOptions.edit.extraOptions.tuiImgEditOpts.iconsPath` MUST follow the same origin policy.")))},init:function(e,t,i,n){this.data("url",i)},load:function(e){var t,i=this,n=this.fm,o=$.Deferred(),a=n.options.cdns,r=i.confObj.opts.version,s=function(t){var a,r,s,c,d=$(e),l=d.parent(),p=i.confObj.opts,m=p.iconsPath,u=$('
            ').appendTo(l),f=[$('
            ').appendTo(u),$('
            ').appendTo(u)],g=new t(e,{includeUI:{loadImage:{path:d.data("url"),name:i.file.name},theme:Object.assign(p.theme,{"menu.normalIcon.path":m+"icon-d.svg","menu.normalIcon.name":"icon-d","menu.activeIcon.path":m+"icon-b.svg","menu.activeIcon.name":"icon-b","menu.disabledIcon.path":m+"icon-a.svg","menu.disabledIcon.name":"icon-a","menu.hoverIcon.path":m+"icon-c.svg","menu.hoverIcon.name":"icon-c","submenu.normalIcon.path":m+"icon-d.svg","submenu.normalIcon.name":"icon-d","submenu.activeIcon.path":m+"icon-c.svg","submenu.activeIcon.name":"icon-c"}),initMenu:"filter",menuBarPosition:"bottom"},cssMaxWidth:Math.max(300,l.width()),cssMaxHeight:Math.max(200,l.height()-(f[0].height()+f[1].height()+3)),usageStatistics:!1}),h=d.find("canvas:first").get(0),v=function(e){if("undefined"!=typeof e){var t,i,n=$(h),o=parseInt(n.attr("width")),a=parseInt(n.attr("height")),r=o/a;0===e?(t=o,i=a):(t=parseInt(n.css("max-width"))+Number(e),i=t/r,t>o&&i>a&&(t=o,i=a)),y.text(Math.round(t/o*100)+"%"),g.resizeCanvasDimension({width:t,height:i}),c&&setTimeout(function(){c&&v(e)},50)}},b=$('').data("val",10),x=$('').data("val",-10),y=$("").css("width","4em").text("%").attr("title","100%").data("val",0);u.remove(),d.removeData("url").data("mime",i.file.mime),"image/jpeg"===i.file.mime?(d.data("quality",n.storage("jpgQuality")||n.option("jpgQuality")),a=$('').attr("min","1").attr("max","100").attr("title","1 - 100").on("change",function(){var e=a.val();d.data("quality",e),r&&cancelAnimationFrame(r),r=requestAnimationFrame(function(){h.toBlob(function(e){e&&a.next("span").text(" ("+n.formatSize(e.size)+")")},"image/jpeg",Math.max(Math.min(e,100),1)/100)})}).val(d.data("quality")),$('
            ').append($("").html(n.i18n("quality")+" : "),a,$("")).prependTo(d.parent().next())):"image/svg+xml"===i.file.mime&&d.closest(".ui-dialog").trigger("changeType",{extention:"png",mime:"image/png",keepEditor:!0}),$('
            ').append(x,y,b).attr("title",n.i18n("scale")).on("click","span,button",function(){v($(this).data("val"))}).on("mousedown mouseup mouseleave","span",function(e){c=!1,s&&clearTimeout(s),"mousedown"===e.type&&(s=setTimeout(function(){c=!0,v($(e.target).data("val"))},500))}).prependTo(d.parent().next()),setTimeout(function(){o.resolve(g),a&&(a.trigger("change"),g.on("redoStackChanged undoStackChanged",function(){a.trigger("change")})),v(null)},100),d.find(".tui-colorpicker-palette-container").on("click",".tui-colorpicker-palette-preview",function(){$(this).closest(".color-picker-control").height("auto").find(".tui-colorpicker-slider-container").toggle()}),d.on("click",function(){d.find(".tui-colorpicker-slider-container").hide()})};return i.confObj.editor?s(i.confObj.editor):(t=$.Deferred(),n.loadCss([a.tui+"/tui-color-picker/latest/tui-color-picker.css",a.tui+"/tui-image-editor/"+r+"/tui-image-editor.css"]),n.hasRequire?(require.config({paths:{"fabric/dist/fabric.require":a.fabric+"/fabric.require.min",fabric:a.fabric+"/fabric.min","tui-code-snippet":a.tui+"/tui.code-snippet/latest/tui-code-snippet.min","tui-color-picker":a.tui+"/tui-color-picker/latest/tui-color-picker.min","tui-image-editor":a.tui+"/tui-image-editor/"+r+"/tui-image-editor.min"}}),require(["tui-image-editor"],function(e){t.resolve(e)})):n.loadScript([a.fabric+"/fabric.min.js",a.tui+"/tui.code-snippet/latest/tui-code-snippet.min.js"],function(){n.loadScript([a.tui+"/tui-color-picker/latest/tui-color-picker.min.js"],function(){n.loadScript([a.tui+"/tui-image-editor/"+r+"/tui-image-editor.min.js"],function(){t.resolve(window.tui.ImageEditor)},{loadType:"tag"})},{loadType:"tag"})},{loadType:"tag"}),t.done(function(e){i.confObj.editor=e,s(e)})),o},getContent:function(e){var t=this.editor,i=t.fm,n=$(e),o=n.data("quality");if(t.instance)return"image/jpeg"===n.data("mime")&&(o=o||i.storage("jpgQuality")||i.option("jpgQuality"),o=Math.max(.1,Math.min(1,o/100))),t.instance.toDataURL({format:a(n.data("mime"),i,!0),quality:o})},save:function(e){var t,i=$(e),n=i.data("quality"),o=i.data("hash");this.instance.deactivateAll(),"undefined"!=typeof n&&this.fm.storage("jpgQuality",n),o&&(t=this.fm.file(o),i.data("mime",t.mime))}},{info:{id:"photopea",name:"Photopea",iconImg:"img/editor-icons.png 0 -160",single:!0,noContent:!0,arrayBufferContent:!0,openMaximized:!0,canMakeEmpty:["image/jpeg","image/png","image/gif","image/svg+xml","image/x-ms-bmp","image/tiff","image/webp","image/vnd.adobe.photoshop","application/pdf","image/x-portable-pixmap","image/x-sketch","image/x-icon","image/vnd-ms.dds"],integrate:{title:"Photopea",link:"https://www.photopea.com/learn/"}},mimes:["image/jpeg","image/png","image/gif","image/svg+xml","image/x-ms-bmp","image/tiff","image/x-adobe-dng","image/webp","image/x-xcf","image/vnd.adobe.photoshop","application/pdf","image/x-portable-pixmap","image/x-sketch","image/x-icon","image/vnd-ms.dds","application/x-msmetafile"],html:'',setup:function(e,t){(t.UA.IE||t.UA.Mobile)&&(this.disabled=!0)},init:function(e,t,i,n){var r,s,c,d="https://www.photopea.com",l=$(this).hide().on("load",function(){l.show()}).on("error",function(){u.remove(),l.show()}),p=this.editor,m=p.confObj,u=$('
            ').html(''+n.i18n("nowLoading")+'').appendTo(l.parent()),f=n.arrayFlip(m.info.canMakeEmpty),g=function(e){var t=a(e,n),i=o[t];return m.mimesFlip[i]?"jpeg"===t&&(t="jpg"):t="",t&&f[i]||(t="psd",i=o[t],l.closest(".ui-dialog").trigger("changeType",{extention:t,mime:i,keepEditor:!0})),t},h=t.mime;m.mimesFlip||(m.mimesFlip=n.arrayFlip(m.mimes,!0)),m.liveMsg||(m.liveMsg=function(e,t,i){var o,a=e.get(0).contentWindow,r=0,s=null,c=$.Deferred().done(function(){t.remove(),r=1,a.postMessage(s,d)});this.load=function(){return n.getContents(i.hash,"arraybuffer").done(function(e){s=e})},this.receive=function(t){var i=t.originalEvent;i.origin===d&&i.source===a&&("done"===i.data?0===r?c.resolve():1===r?(r=2,e.trigger("contentsloaded")):o&&"pending"===o.state()&&o.reject("errDataEmpty"):"Save"===i.data?p.doSave():o&&"pending"===o.state()&&("object"==typeof i.data?o.resolve("data:"+h+";base64,"+n.arrayBufferToBase64(i.data)):o.reject("errDataEmpty")))},this.getContent=function(){var t,i;if(r>1)return o&&"pending"===o.state()&&o.reject(),o=null,o=$.Deferred(),2===r?(r=3,o.resolve("data:"+h+";base64,"+n.arrayBufferToBase64(s)),s=null,o):(e.data("mime")&&(h=e.data("mime"),t=g(h)),(i=e.data("quality"))&&(t+=":"+i/100),a.postMessage('app.activeDocument.saveToOE("'+t+'")',d),o)}}),l.parent().css("padding",0),s=g(t.mime),r=p.liveMsg=new m.liveMsg(l,u,t),$(window).on("message."+n.namespace,r.receive),r.load().done(function(){var e=JSON.stringify({files:[],environment:{lang:n.lang.replace(/_/g,"-"),customIO:{save:'app.echoToOE("Save");'}}});l.attr("src",d+"/#"+encodeURI(e))}).fail(function(e){e&&n.error(e),p.initFail=!0}),"image/jpeg"!==t.mime&&"image/webp"!==t.mime||(l.data("quality",n.storage("jpgQuality")||n.option("jpgQuality")),c=$('').attr("min","1").attr("max","100").attr("title","1 - 100").on("change",function(){var e=c.val();l.data("quality",e)}).val(l.data("quality")),$('
            ').append($("").html(n.i18n("quality")+" : "),c,$("")).prependTo(l.parent().next()))},load:function(e){var t=$.Deferred(),i=this,n=(this.fm,$(e));return i.initFail?t.reject():n.on("contentsloaded",function(){t.resolve(i.liveMsg)}),t},getContent:function(){return this.editor.liveMsg?this.editor.liveMsg.getContent():void 0},save:function(e,t){var i,n=$(e),o=n.data("quality"),a=n.data("hash");"undefined"!=typeof o&&this.fm.storage("jpgQuality",o),a?(i=this.fm.file(a),n.data("mime",i.mime)):n.removeData("mime")},close:function(e,t){$(e).attr("src",""),t&&$(window).off("message."+this.fm.namespace,t.receive)}},{info:{id:"pixo",name:"Pixo Editor",iconImg:"img/editor-icons.png 0 -208",dataScheme:!0,schemeContent:!0,single:!0,canMakeEmpty:!1,integrate:{title:"Pixo Editor",link:"https://pixoeditor.com/privacy-policy/"}},mimes:["image/jpeg","image/png","image/gif","image/svg+xml","image/x-ms-bmp"],html:'
            ',setup:function(e,t){!t.UA.ltIE8&&e.extraOptions&&e.extraOptions.pixo&&e.extraOptions.pixo.apikey?this.editorOpts=e.extraOptions.pixo:this.disabled=!0},init:function(e,t,i,n){s.call(this,e,t,i,n)},getContent:function(){return $(this).children("img:first").attr("src")},load:function(e){var t,i,n,o,s,c=this,d=this.fm,l=$(e),p=l.children("img:first"),m=l.closest(".ui-dialog"),u=d.getUI(),f=$.Deferred(),g=$("#elfinder-pixo-container"),h=function(n){var h;g.length?g.appendTo(g.parent()):(g=$('
            ').css({position:"fixed",top:0,right:0,width:"100%",height:$(window).height(),overflow:"hidden"}).hide().appendTo(u.hasClass("elfinder-fullscreen")?u:"body"),u.on("resize."+d.namespace,function(e,t){e.preventDefault(),e.stopPropagation(),t&&t.fullscreen&&g.appendTo("on"===t.fullscreen?u:"body")}),d.bind("destroy",function(){s&&s.cancelEditing(),g.remove()})),p.on("click",v),h=Object.assign({type:"child",parent:g.get(0),output:{format:"png"},onSave:function(n){var s=n.toBlob().type,l=a(s,d),u=function(e){p.one("load error",function(){p.data("loading")&&p.data("loading")(!0)}).attr("crossorigin","anonymous").attr("src",e)},f=n.toDataURL();p.data("loading")(),delete e._canvas,p.data("ext")!==l?r(f,c.file.mime).done(function(n,a){a&&(e._canvas=o=a,i.trigger("change"),t&&t.show()),u(n)}).fail(function(){m.trigger("changeType",{extention:l,mime:s}),u(f)}):u(f)},onClose:function(){m.removeClass(d.res("class","preventback")),d.toggleMaximize(g,!1),g.hide(),d.toFront(m)}},c.confObj.editorOpts),c.trigger("Prepare",{node:e,editorObj:Pixo,instance:void 0,opts:h}),s=new Pixo.Bridge(h),f.resolve(s),l.on("saveAsFail",v),n&&n()},v=function(){m.addClass(d.res("class","preventback")),d.toggleMaximize(g,!0),d.toFront(g),g.show().data("curhash",c.file.hash),s.edit(p.get(0)),p.data("loading")(!0)};return p.data("loading")(),"image/jpeg"===c.file.mime&&(i=$('').attr("min","1").attr("max","100").attr("title","1 - 100").on("change",function(){var e=i.val();n&&cancelAnimationFrame(n),n=requestAnimationFrame(function(){o&&o.toBlob(function(e){e&&i.next("span").text(" ("+d.formatSize(e.size)+")")},"image/jpeg",Math.max(Math.min(e,100),1)/100)})}).val(d.storage("jpgQuality")||d.option("jpgQuality")),t=$('
            ').hide().append($("").html(d.i18n("quality")+" : "),i,$("")).prependTo(l.parent().next()),l.data("quty",i)),"undefined"==typeof Pixo?d.loadScript(["https://pixoeditor.com:8443/editor/scripts/bridge.m.js"],function(){h(v)},{loadType:"tag"}):(h(),v()),f},save:function(e){var t,i=this,n=$(e),o=n.children("img:first");e._canvas?(n.data("quty")&&(t=n.data("quty").val(),t&&this.fm.storage("jpgQuality",t)),o.attr("src",e._canvas.toDataURL(i.file.mime,t?Math.max(Math.min(t,100),1)/100:void 0))):"data:"!==o.attr("src").substr(0,5)&&o.attr("src",c(o,this.file.mime))},close:function(e,t){t&&t.destroy()}},{setup:function(e,t){!t.UA.ltIE8&&t.options.cdns.ace||(this.disabled=!0)},info:{id:"aceeditor",name:"ACE Editor",iconImg:"img/editor-icons.png 0 -96"},load:function(e){var t=this,i=this.fm,n=$.Deferred(),o=i.options.cdns.ace,a=function(){var i,a,r,s=$(e),c=s.parent(),d=c.parent(),l=e.id+"_ace",p=(t.file.name.replace(/^.+\.([^.]+)|(.+)$/,"$1$2").toLowerCase(),{"text/x-php":"php","application/x-php":"php","text/html":"html","application/xhtml+xml":"html","text/javascript":"javascript","application/javascript":"javascript","text/css":"css","text/x-c":"c_cpp","text/x-csrc":"c_cpp","text/x-chdr":"c_cpp","text/x-c++":"c_cpp","text/x-c++src":"c_cpp","text/x-c++hdr":"c_cpp","text/x-shellscript":"sh","application/x-csh":"sh","text/x-python":"python","text/x-java":"java","text/x-java-source":"java","text/x-ruby":"ruby","text/x-perl":"perl","application/x-perl":"perl","text/x-sql":"sql","text/xml":"xml","application/docbook+xml":"xml","application/xml":"xml"});c.height(c.height()),ace.config.set("basePath",o),a=$('
            ').text(s.val()).insertBefore(s.hide()),s.data("ace",!0),i=ace.edit(l),i.$blockScrolling=1/0,i.setOptions({theme:"ace/theme/monokai",fontSize:"14px",wrap:!0}),ace.config.loadModule("ace/ext/modelist",function(){r=ace.require("ace/ext/modelist").getModeForPath("/"+t.file.name).name,"text"===r&&p[t.file.mime]&&(r=p[t.file.mime]),c.prev().children(".elfinder-dialog-title").append(" ("+t.file.mime+" : "+r.split(/[\/\\]/).pop()+")"),i.setOptions({mode:"ace/mode/"+r}),"resolved"===n.state()&&d.trigger("resize")}),ace.config.loadModule("ace/ext/language_tools",function(){ace.require("ace/ext/language_tools"),i.setOptions({enableBasicAutocompletion:!0,enableSnippets:!0,enableLiveAutocompletion:!1})}),ace.config.loadModule("ace/ext/settings_menu",function(){ace.require("ace/ext/settings_menu").init(i)}),i.commands.addCommand({name:"saveFile",bindKey:{win:"Ctrl-s",mac:"Command-s"},exec:function(e){t.doSave()}}),i.commands.addCommand({name:"closeEditor",bindKey:{win:"Ctrl-w|Ctrl-q",mac:"Command-w|Command-q"},exec:function(e){t.doCancel()}}),i.resize(),$('
            ').css("float","left").append($("").html(t.fm.i18n("TextArea")).button().on("click",function(){s.data("ace")?(s.removeData("ace"),a.hide(),s.val(i.session.getValue()).show().trigger("focus"),$(this).text("AceEditor")):(s.data("ace",!0),a.show(),i.setValue(s.hide().val(),-1),i.focus(),$(this).html(t.fm.i18n("TextArea")))})).append($("").button({icons:{primary:"ui-icon-gear",secondary:"ui-icon-triangle-1-e"},text:!1}).on("click",function(){i.showSettingsMenu(),$("#ace_settingsmenu").css("font-size","80%").find('div[contains="setOptions"]').hide().end().parent().appendTo($("#elfinder"))})).prependTo(c.next()),t.trigger("Prepare",{node:e,editorObj:ace,instance:i,opts:{}}),n.resolve(i)};return t.confObj.loader||(t.confObj.loader=$.Deferred(),t.fm.loadScript([o+"/ace.js"],function(){t.confObj.loader.resolve()},void 0,{obj:window,name:"ace"})),t.confObj.loader.done(a),n},close:function(e,t){t&&t.destroy()},save:function(e,t){t&&$(e).data("ace")&&(e.value=t.session.getValue())},focus:function(e,t){t&&$(e).data("ace")&&t.focus()},resize:function(e,t,i,n){t&&t.resize()}},{setup:function(e,t){!t.UA.ltIE10&&t.options.cdns.codemirror||(this.disabled=!0)},info:{id:"codemirror",name:"CodeMirror",iconImg:"img/editor-icons.png 0 -176"},load:function(e){var t=this.fm,i=t.convAbsUrl(t.options.cdns.codemirror),o=$.Deferred(),a=this,r=function(t){var r,s,c,d=$(e),l=d.parent();l.height(l.height()),c={lineNumbers:!0,lineWrapping:!0,extraKeys:{"Ctrl-S":function(){a.doSave()},"Ctrl-Q":function(){a.doCancel()},"Ctrl-W":function(){a.doCancel()}}},a.trigger("Prepare",{node:e,editorObj:t,instance:void 0,opts:c}),r=t.fromTextArea(e,c),o.resolve(r);var p,m,u,f;p||(p=t.findModeByMIME(a.file.mime)),!p&&(m=a.file.name.match(/.+\.([^.]+)$/))&&(p=t.findModeByExtension(m[1])),p&&(t.modeURL=n?"codemirror/mode/%N/%N.min":i+"/mode/%N/%N.min.js",u=p.mode,f=p.mime,r.setOption("mode",f),t.autoLoadMode(r,u),l.prev().children(".elfinder-dialog-title").append(" ("+f+("null"!=u?" : "+u:"")+")")),s=$(r.getWrapperElement()).css({padding:0,border:"none"}),d.data("cm",!0),s.height("100%"),$('
            ').css("float","left").append($("").html(a.fm.i18n("TextArea")).button().on("click",function(){d.data("cm")?(d.removeData("cm"),s.hide(),d.val(r.getValue()).show().trigger("focus"),$(this).text("CodeMirror")):(d.data("cm",!0),s.show(),r.setValue(d.hide().val()),r.refresh(),r.focus(),$(this).html(a.fm.i18n("TextArea")))})).prependTo(l.next())};return a.confObj.loader||(a.confObj.loader=$.Deferred(),n?(require.config({packages:[{name:"codemirror",location:i,main:"codemirror.min"}],map:{codemirror:{"codemirror/lib/codemirror":"codemirror"}}}),require(["codemirror","codemirror/addon/mode/loadmode.min","codemirror/mode/meta.min"],function(e){a.confObj.loader.resolve(e)})):a.fm.loadScript([i+"/codemirror.min.js"],function(){a.fm.loadScript([i+"/addon/mode/loadmode.min.js",i+"/mode/meta.min.js"],function(){a.confObj.loader.resolve(CodeMirror)})},{loadType:"tag"}),a.fm.loadCss(i+"/codemirror.css")),a.confObj.loader.done(r),o},close:function(e,t){t&&t.toTextArea()},save:function(e,t){t&&$(e).data("cm")&&(e.value=t.getValue())},focus:function(e,t){t&&$(e).data("cm")&&t.focus()},resize:function(e,t,i,n){t&&t.refresh()}},{setup:function(e,t){!t.UA.ltIE10&&t.options.cdns.simplemde||(this.disabled=!0)},info:{id:"simplemde",name:"SimpleMDE",iconImg:"img/editor-icons.png 0 -80"},exts:["md"],load:function(e){var t=this,i=this.fm,o=$(e).parent(),a=$.Deferred(),r=i.options.cdns.simplemde,s=function(i){var n,r,s,c=o.height(),d=o.outerHeight(!0)-c+14;e._setHeight=function(e){var t,i=e||o.height(),a=0;return o.children(".editor-toolbar,.editor-statusbar").each(function(){a+=$(this).outerHeight(!0)}),t=i-a-d,r.height(t),n.codemirror.refresh(),t},o.height(c),s={element:e,autofocus:!0},t.trigger("Prepare",{node:e,editorObj:i,instance:void 0,opts:s}),n=new i(s),a.resolve(n),r=$(n.codemirror.getWrapperElement()),r.css("min-height","50px").children(".CodeMirror-scroll").css("min-height","50px"),e._setHeight(c)};return t.confObj.loader||(t.confObj.loader=$.Deferred(),t.fm.loadCss(r+"/simplemde.min.css"),n?require([r+"/simplemde.min.js"],function(e){t.confObj.loader.resolve(e)}):t.fm.loadScript([r+"/simplemde.min.js"],function(){t.confObj.loader.resolve(SimpleMDE)},{loadType:"tag"})),t.confObj.loader.done(s),a},close:function(e,t){t&&t.toTextArea(),t=null},save:function(e,t){t&&(e.value=t.value())},focus:function(e,t){t&&t.codemirror.focus()},resize:function(e,t,i,n){t&&e._setHeight()}},{info:{id:"ckeditor",name:"CKEditor",iconImg:"img/editor-icons.png 0 0"},exts:["htm","html","xhtml"],setup:function(e,t){var i=this;t.options.cdns.ckeditor?(i.ckeOpts={},e.extraOptions&&(i.ckeOpts=Object.assign({},e.extraOptions.ckeditor||{}),e.extraOptions.managerUrl&&(i.managerUrl=e.extraOptions.managerUrl))):i.disabled=!0},load:function(e){var t=this,i=this.fm,n=$.Deferred(),o=function(){var o,a=$(e).parent(),r=a.closest(".elfinder-dialog"),s=a.height(),c=/([&?]getfile=)[^&]+/,d=t.confObj.managerUrl||window.location.href.replace(/#.*$/,""),l="ckeditor";c.test(d)?d=d.replace(c,"$1"+l):d+="?getfile="+l,a.height(s),o={startupFocus:!0,fullPage:!0,allowedContent:!0,filebrowserBrowseUrl:d,toolbarCanCollapse:!0,toolbarStartupExpanded:!i.UA.Mobile,removePlugins:"resize",extraPlugins:"colorbutton,justify,docprops",on:{instanceReady:function(o){var a=o.editor;a.resize("100%",s),r.one("beforedommove."+i.namespace,function(){a.destroy()}).one("dommove."+i.namespace,function(){t.load(e).done(function(e){t.instance=e})}),n.resolve(o.editor)}}},t.trigger("Prepare",{node:e,editorObj:CKEDITOR,instance:void 0,opts:o}),CKEDITOR.replace(e.id,Object.assign(o,t.confObj.ckeOpts)),CKEDITOR.on("dialogDefinition",function(e){var t=e.data.definition.dialog;t.on("show",function(e){i.getUI().append($(".cke_dialog_background_cover")).append(this.getElement().$)}),t.on("hide",function(e){$("body:first").append($(".cke_dialog_background_cover")).append(this.getElement().$)})})};return t.confObj.loader||(t.confObj.loader=$.Deferred(),window.CKEDITOR_BASEPATH=i.options.cdns.ckeditor+"/",$.getScript(i.options.cdns.ckeditor+"/ckeditor.js",function(){t.confObj.loader.resolve()})),t.confObj.loader.done(o),n},close:function(e,t){t&&t.destroy()},save:function(e,t){t&&(e.value=t.getData())},focus:function(e,t){t&&t.focus()},resize:function(e,t,i,n){t&&"ready"===t.status&&t.resize("100%",$(e).parent().height())}},{info:{id:"ckeditor5",name:"CKEditor5",iconImg:"img/editor-icons.png 0 -16"},exts:["htm","html","xhtml"],html:'
            ',setup:function(e,t){var i=this;t.options.cdns.ckeditor5&&"function"==typeof window.Symbol&&"symbol"==typeof Symbol()?(i.ckeOpts={},e.extraOptions&&(e.extraOptions.ckeditor5Mode&&(i.ckeditor5Mode=e.extraOptions.ckeditor5Mode),i.ckeOpts=Object.assign({},e.extraOptions.ckeditor5||{}),i.ckeOpts.mode&&(i.ckeditor5Mode=i.ckeOpts.mode,delete i.ckeOpts.mode),e.extraOptions.managerUrl&&(i.managerUrl=e.extraOptions.managerUrl))):i.disabled=!0,t.bind("destroy",function(){i.editor=null})},prepare:function(e,t,i){$(e).height(e.editor.fm.getUI().height()-100)},init:function(e,t,i,n){var o=i.match(/^([\s\S]*]*>)([\s\S]+)(<\/body>[\s\S]*)$/i),a="",r="",s="";this.css({width:"100%",height:"100%","box-sizing":"border-box"}),o?(a=o[1],r=o[2],s=o[3]):r=i,this.data("data",{header:a,body:r,footer:s}),this._setupSelEncoding(i)},load:function(e){var t,i=this,n=this.fm,o=$.Deferred(),a=i.confObj.ckeditor5Mode||"decoupled-document",r=function(){var e=n.lang.toLowerCase().replace("_","-");return"zh"===e.substr(0,2)&&"zh-cn"!==e&&(e="zh"),e}(),s=function(t){var s,d=$(e).parent();d.height(n.getUI().height()-100),s=Object.assign({toolbar:["heading","|","fontSize","fontFamily","|","bold","italic","underline","strikethrough","highlight","|","alignment","|","numberedList","bulletedList","blockQuote","indent","outdent","|","ckfinder","link","imageUpload","insertTable","mediaEmbed","|","undo","redo"],language:r},i.confObj.ckeOpts),i.trigger("Prepare",{node:e,editorObj:t,instance:void 0,opts:s}),t.create(e,s).then(function(t){var i,r,s=t.commands.get("ckfinder"),l=t.plugins.get("FileRepository"),p={};!t.ui.view.toolbar||"classic"!==a&&"decoupled-document"!==a||$(e).closest(".elfinder-dialog").children(".ui-widget-header").append($(t.ui.view.toolbar.element).css({marginRight:"-1em",marginLeft:"-1em"})),"classic"===a&&$(e).closest(".elfinder-edit-editor").css("overflow","auto"),s&&(i=function(e){return e&&e.mime.match(/^image\//i)},r=function(e){var i=t.commands.get("imageUpload");if(!i.isEnabled){var n=t.plugins.get("Notification"),o=t.locale.t;return void n.showWarning(o("Could not insert image at the current position."),{title:o("Inserting image failed"),namespace:"ckfinder"})}t.execute("imageInsert",{source:e})},s.execute=function(){var e=d.closest(".elfinder-dialog"),o=n.getCommand("getfile"),a=function(){p.hasVar&&(e.off("resize close",a),o.callback=p.callback,o.options.folders=p.folders,o.options.multiple=p.multi,n.commandMap.open=p.open,p.hasVar=!1)};e.trigger("togleminimize").one("resize close",a),p.callback=o.callback,p.folders=o.options.folders,p.multi=o.options.multiple,p.open=n.commandMap.open,p.hasVar=!0,o.callback=function(o){var a=[];return 1===o.length&&"directory"===o[0].mime?void n.one("open",function(){n.commandMap.open="getfile"}).getCommand("open").exec(o[0].hash):(n.getUI("cwd").trigger("unselectall"),$.each(o,function(e,o){i(o)?a.push(n.convAbsUrl(o.url)):t.execute("link",n.convAbsUrl(o.url))}),a.length&&r(a),void e.trigger("togleminimize"))},o.options.folders=!0,o.options.multiple=!0,n.commandMap.open="getfile",n.toast({mode:"info",msg:n.i18n("dblclickToSelect")})}),l.createUploadAdapter=function(e){return new c(e)},t.setData($(e).data("data").body),n.getUI().append($("body > div.ck-body")),$("div.ck-balloon-panel").css({"z-index":n.getMaximizeCss().zIndex+1}),o.resolve(t)})["catch"](function(e){n.error(e)})},c=function(e){var t=function(t,i,o){n.exec("upload",{files:[t]},void 0,n.cwd().hash).done(function(e){e.added&&e.added.length?n.url(e.added[0].hash,{async:!0}).done(function(e){i({"default":n.convAbsUrl(e)})}).fail(function(){o("errFileNotFound")}):o(n.i18n(e.error?e.error:"errUpload"))}).fail(function(e){var t=n.parseError(e);o(n.i18n(t?"userabort"===t?"errAbort":t:"errUploadNoFiles"))}).progress(function(t){e.uploadTotal=t.total,e.uploaded=t.progress})};this.upload=function(){return new Promise(function(i,n){e.file instanceof Promise||e.file&&"function"==typeof e.file.then?e.file.then(function(e){t(e,i,n)}):t(e.file,i,n)})},this.abort=function(){n.getUI().trigger("uploadabort")}};return i.confObj.editor?s(i.confObj.editor):(t=$.Deferred(),i.fm.loadScript([n.options.cdns.ckeditor5+"/"+a+"/ckeditor.js"],function(e){e||(e=window.BalloonEditor||window.InlineEditor||window.ClassicEditor||window.DecoupledEditor),"en"!==n.lang?i.fm.loadScript([n.options.cdns.ckeditor5+"/"+a+"/translations/"+r+".js"],function(i){t.resolve(e)},{tryRequire:!0,loadType:"tag",error:function(i){r="en",t.resolve(e)}}):t.resolve(e)},{tryRequire:!0,loadType:"tag"}),t.done(function(e){i.confObj.editor=e,s(e)})),o},getContent:function(){var e=$(this).data("data");return e.header+e.body+e.footer},close:function(e,t){t&&t.destroy()},save:function(e,t){var i=$(e),n=i.data("data");t&&(n.body=t.getData(),i.data("data",n))},focus:function(e,t){$(e).trigger("focus")}},{info:{id:"tinymce",name:"TinyMCE",iconImg:"img/editor-icons.png 0 -64"},exts:["htm","html","xhtml"],setup:function(e,t){var i=this;t.options.cdns.tinymce?(i.mceOpts={},e.extraOptions?(i.uploadOpts=Object.assign({},e.extraOptions.uploadOpts||{}),i.mceOpts=Object.assign({},e.extraOptions.tinymce||{})):i.uploadOpts={}):i.disabled=!0},load:function(e){var t=this,i=this.fm,n=$.Deferred(),o=function(){var o,a,r,s=$(e).show().parent(),c=s.closest(".elfinder-dialog"),d=s.height(),l=s.outerHeight(!0)-d,p=function(){var e;tinymce.activeEditor.windowManager.windows?(e=tinymce.activeEditor.windowManager.windows[0],a=$(e?e.getEl():void 0).hide(),r=$("#mce-modal-block").hide()):a=$(".tox-dialog-wrap").hide()},m=function(){r&&r.show(),a&&a.show()},u=tinymce.majorVersion;s.height(d),e._setHeight=function(e){if(u<5){var t,i=$(this).parent(),n=e||i.innerHeight(),o=0;i.find(".mce-container-body:first").children(".mce-top-part,.mce-statusbar").each(function(){o+=$(this).outerHeight(!0)}),t=n-o-l,i.find(".mce-edit-area iframe:first").height(t)}},o={selector:"#"+e.id,resize:!1,plugins:"print preview fullpage searchreplace autolink directionality visualblocks visualchars fullscreen image link media template codesample table charmap hr pagebreak nonbreaking anchor toc insertdatetime advlist lists wordcount imagetools textpattern help",toolbar:"formatselect | bold italic strikethrough forecolor backcolor | link image media | alignleft aligncenter alignright alignjustify | numlist bullist outdent indent | removeformat",image_advtab:!0,init_instance_callback:function(o){e._setHeight(d),c.one("beforedommove."+i.namespace,function(){tinymce.execCommand("mceRemoveEditor",!1,e.id)}).one("dommove."+i.namespace,function(){t.load(e).done(function(e){t.instance=e})}),n.resolve(o)},file_picker_callback:function(e,t,n){var o=i.getCommand("getfile"),a=function(){r.hasVar&&(o.callback=r.callback,o.options.folders=r.folders,o.options.multiple=r.multi,i.commandMap.open=r.open,r.hasVar=!1),c.off("resize close",a),m()},r={};return r.callback=o.callback,r.folders=o.options.folders,r.multi=o.options.multiple,r.open=i.commandMap.open,r.hasVar=!0,o.callback=function(t){var o,a;return"directory"===t.mime?void i.one("open",function(){i.commandMap.open="getfile"}).getCommand("open").exec(t.hash):(o=i.convAbsUrl(t.url),a=t.name+" ("+i.formatSize(t.size)+")","file"==n.filetype&&e(o,{text:a,title:a}),"image"==n.filetype&&e(o,{alt:a}),"media"==n.filetype&&e(o),void c.trigger("togleminimize"))},o.options.folders=!0,o.options.multiple=!1, +i.commandMap.open="getfile",p(),c.trigger("togleminimize").one("resize close",a),i.toast({mode:"info",msg:i.i18n("dblclickToSelect")}),!1},images_upload_handler:function(e,n,o){var a=e.blob(),r=function(e){var t=e.data.dialog||{};(t.hasClass("elfinder-dialog-error")||t.hasClass("elfinder-confirm-upload"))&&(p(),t.trigger("togleminimize").one("resize close",s),i.unbind("dialogopened",r))},s=function(){c.off("resize close",s),m()},d=!0;a.name&&(d=void 0),i.bind("dialogopened",r).exec("upload",Object.assign({files:[a],clipdata:d},t.confObj.uploadOpts),void 0,i.cwd().hash).done(function(e){e.added&&e.added.length?i.url(e.added[0].hash,{async:!0}).done(function(e){m(),n(i.convAbsUrl(e))}).fail(function(){o(i.i18n("errFileNotFound"))}):o(i.i18n(e.error?e.error:"errUpload"))}).fail(function(e){var t=i.parseError(e);t&&("errUnknownCmd"===t?t="errPerm":"userabort"===t&&(t="errAbort")),o(i.i18n(t?t:"errUploadNoFiles"))})}},u>=5&&(o.height="100%"),t.trigger("Prepare",{node:e,editorObj:tinymce,instance:void 0,opts:o}),tinymce.init(Object.assign(o,t.confObj.mceOpts))};return t.confObj.loader||(t.confObj.loader=$.Deferred(),t.fm.loadScript([i.options.cdns.tinymce+(i.options.cdns.tinymce.match(/\.js/)?"":"/tinymce.min.js")],function(){t.confObj.loader.resolve()},{loadType:"tag"})),t.confObj.loader.done(o),n},close:function(e,t){t&&tinymce.execCommand("mceRemoveEditor",!1,e.id)},save:function(e,t){t&&t.save()},focus:function(e,t){t&&t.focus()},resize:function(e,t,i,n){t&&e._setHeight()}},{info:{id:"zohoeditor",name:"Zoho Editor",iconImg:"img/editor-icons.png 0 -32",cmdCheck:"ZohoOffice",preventGet:!0,hideButtons:!0,syncInterval:15e3,canMakeEmpty:!0,integrate:{title:"Zoho Office API",link:"https://www.zoho.com/officeapi/"}},mimes:["application/msword","application/vnd.openxmlformats-officedocument.wordprocessingml.document","application/vnd.oasis.opendocument.text","application/rtf","text/html","application/vnd.ms-excel","application/vnd.openxmlformats-officedocument.spreadsheetml.sheet","application/vnd.oasis.opendocument.spreadsheet","application/vnd.sun.xml.calc","text/csv","text/tab-separated-values","application/vnd.ms-powerpoint","application/vnd.openxmlformats-officedocument.presentationml.presentation","application/vnd.openxmlformats-officedocument.presentationml.slideshow","application/vnd.oasis.opendocument.presentation","application/vnd.sun.xml.impress"],html:'',setup:function(e,t){(t.UA.Mobile||t.UA.ltIE8)&&(this.disabled=!0)},prepare:function(e,t,i){var n=e.editor.fm.getUI();$(e).height(n.height()),t.width=Math.max(t.width||0,.8*n.width())},init:function(e,t,i,n){var o=this,a=$(this).hide(),r=n.getUI("toast"),s=$('
            ').html(''+n.i18n("nowLoading")+'').appendTo(a.parent()),c=function(){var e="";return $.each(n.customData,function(t,i){e+="&"+encodeURIComponent(t)+"="+encodeURIComponent(i)}),e};$(o).data("xhr",n.request({data:{cmd:"editor",name:o.editor.confObj.info.cmdCheck,method:"init","args[target]":t.hash,"args[lang]":n.lang,"args[cdata]":c()},preventDefault:!0}).done(function(e){var t;e.zohourl?(t={css:{height:"100%"}},o.editor.trigger("Prepare",{node:o,editorObj:void 0,instance:a,opts:t}),a.attr("src",e.zohourl).show().css(t.css),e.warning&&(r.appendTo(o.closest(".ui-dialog")),n.toast({msg:n.i18n(e.warning),mode:"warning",timeOut:0,onHidden:function(){1===r.children().length&&r.appendTo(n.getUI())},button:{text:"btnYes"}}))):(e.error&&n.error(e.error),o.elfinderdialog("destroy"))}).fail(function(e){e&&n.error(e),o.elfinderdialog("destroy")}).always(function(){s.remove()}))},load:function(){},getContent:function(){},save:function(){},beforeclose:d,close:function(e){var t=(this.fm,$(e).data("xhr"));"pending"===t.state()&&t.reject()}},{info:{id:"ziparchive",name:"btnMount",iconImg:"img/toolbar.png 0 -416",cmdCheck:"ZipArchive",edit:function(e,t){var i=this,n=$.Deferred();return i.request({data:{cmd:"netmount",protocol:"ziparchive",host:e.hash,path:e.phash},preventFail:!0,notify:{type:"netmount",cnt:1,hideCnt:!0}}).done(function(e){var t;e.added&&e.added.length&&(e.added[0].phash&&(t=i.file(e.added[0].phash))&&(t.dirs||(t.dirs=1,i.change({changed:[t]}))),i.one("netmountdone",function(){i.exec("open",e.added[0].hash),i.one("opendone",function(){e.toast&&i.toast(e.toast)})})),n.resolve()}).fail(function(e){n.reject(e)}),n}},mimes:["application/zip"],load:function(){},save:function(){}},{info:{id:"textarea",name:"TextArea",useTextAreaEvent:!0},load:function(e){this.trigger("Prepare",{node:e,editorObj:void 0,instance:void 0,opts:{}}),e.setSelectionRange&&e.setSelectionRange(0,0),$(e).trigger("focus").show()},save:function(){}},{info:{id:"onlineconvert",name:"Online Convert",iconImg:"img/editor-icons.png 0 -144",cmdCheck:"OnlineConvert",preventGet:!0,hideButtons:!0,single:!0,converter:!0,canMakeEmpty:!1,integrate:{title:"ONLINE-CONVERT.COM",link:"https://online-convert.com"}},mimes:["*"],html:'
            ',setup:function(e,t){var i=e.extraOptions.onlineConvert||{maxSize:100,showLink:!0};i.maxSize&&(this.info.maxSize=1048576*i.maxSize),this.set=Object.assign({url:"https://%s.online-convert.com%s?external_url=",conv:{Archive:{"7Z":{},BZ2:{ext:"bz"},GZ:{},ZIP:{}},Audio:{MP3:{},OGG:{ext:"oga"},WAV:{},WMA:{},AAC:{},AIFF:{ext:"aif"},FLAC:{},M4A:{},MMF:{},OPUS:{ext:"oga"}},Document:{DOC:{},DOCX:{},HTML:{},ODT:{},PDF:{},PPT:{},PPTX:{},RTF:{},SWF:{},TXT:{}},eBook:{AZW3:{ext:"azw"},ePub:{},FB2:{ext:"xml"},LIT:{},LRF:{},MOBI:{},PDB:{},PDF:{},"PDF-eBook":{ext:"pdf"},TCR:{}},Hash:{Adler32:{},"Apache-htpasswd":{},Blowfish:{},CRC32:{},CRC32B:{},Gost:{},Haval128:{},MD4:{},MD5:{},RIPEMD128:{},RIPEMD160:{},SHA1:{},SHA256:{},SHA384:{},SHA512:{},Snefru:{},"Std-DES":{},Tiger128:{},"Tiger128-calculator":{},"Tiger128-converter":{},Tiger160:{},Tiger192:{},Whirlpool:{}},Image:{BMP:{},EPS:{ext:"ai"},GIF:{},EXR:{},ICO:{},JPG:{},PNG:{},SVG:{},TGA:{},TIFF:{ext:"tif"},WBMP:{},WebP:{}},Video:{"3G2":{},"3GP":{},AVI:{},FLV:{},HLS:{ext:"m3u8"},MKV:{},MOV:{},MP4:{},"MPEG-1":{ext:"mpeg"},"MPEG-2":{ext:"mpeg"},OGG:{ext:"ogv"},OGV:{},WebM:{},WMV:{},Android:{link:"/convert-video-for-%s",ext:"mp4"},Blackberry:{link:"/convert-video-for-%s",ext:"mp4"},DPG:{link:"/convert-video-for-%s",ext:"avi"},iPad:{link:"/convert-video-for-%s",ext:"mp4"},iPhone:{link:"/convert-video-for-%s",ext:"mp4"},iPod:{link:"/convert-video-for-%s",ext:"mp4"},"Nintendo-3DS":{link:"/convert-video-for-%s",ext:"avi"},"Nintendo-DS":{link:"/convert-video-for-%s",ext:"avi"},PS3:{link:"/convert-video-for-%s",ext:"mp4"},Wii:{link:"/convert-video-for-%s",ext:"avi"},Xbox:{link:"/convert-video-for-%s",ext:"wmv"}}},catExts:{Hash:"txt"},link:'',useTabs:!(!$.fn.tabs||t.UA.iOS)},i)},prepare:function(e,t,i){var n=e.editor.fm.getUI();$(e).height(n.height()),t.width=Math.max(t.width||0,.8*n.width())},init:function(e,t,i,n){var a,r,s=this,c=s.editor.confObj,d=c.set,l=n.getUI("toast"),p={},m=n.uploadMimeCheck("application/zip",t.phash),u=$("base").length?document.location.href.replace(/#.*$/,""):"",f=function(e,t){var i;return d.catExts[e]?d.catExts[e]:d.conv[e]&&(i=d.conv[e][t])?(i.ext||t).toLowerCase():t.toLowerCase()},g=function(e,t){var i,o,a;o="undefined"==typeof c.api?n.request({data:{cmd:"editor",name:"OnlineConvert",method:"init"},preventDefault:!0}):$.Deferred().resolve({api:c.api}),e=e.toLowerCase(),o.done(function(n){c.api=n.api,c.api&&(e?i="?category="+e:(i="",e="all"),c.conversions||(c.conversions={}),a=c.conversions[e]?$.Deferred().resolve(c.conversions[e]):$.getJSON("https://api2.online-convert.com/conversions"+i),a.done(function(i){c.conversions[e]=i,$.each(i,function(e,t){h[d.useTabs?"children":"find"](".onlineconvert-category-"+t.category).children(".onlineconvert-"+t.target).trigger("makeoption",t)}),t&&t()}))})},h=function(){var e=$("
            ").on("click","button",function(){var e=$(this),t=e.data("opts")||null,i=e.closest(".onlineconvert-category").data("cname"),n=e.data("conv");c.api===!0&&k({category:i,convert:n,options:t})}).on("change",function(e){var t=$(e.target),i=t.parent(),o=t.closest(".elfinder-edit-onlineconvert-button").children("button:first"),a=o.data("opts")||{},r="boolean"===i.data("type")?t.is(":checked"):t.val();if(e.stopPropagation(),r&&("integer"===i.data("type")&&(r=parseInt(r)),i.data("pattern"))){var s=new RegExp(i.data("pattern"));s.test(r)||(requestAnimationFrame(function(){n.error('"'+n.escape(r)+'" is not match to "/'+n.escape(i.data("pattern"))+'/"')}),r=null)}r?a[t.parent().data("optkey")]=r:delete a[i.data("optkey")],o.data("opts",a)}),i=$("
              "),a=function(e,t){var i,o,a,r=$("

              ").data("optkey",e).data("type",t.type),s="",c="",d=!1;return t.description&&r.attr("title",n.i18n(t.description)),t.pattern&&r.data("pattern",t.pattern),r.append($("").text(n.i18n(e)+" : ")),"boolean"===t.type?((t["default"]||(d="allow_multiple_outputs"===e&&!m))&&(s=" checked",d&&(c=" disabled"),o=this.children("button:first"),i=o.data("opts")||{},i[e]=!0,o.data("opts",i)),r.append($('"))):t["enum"]?(a=$("").append($('').text("Select...")),$.each(t["enum"],function(e,t){a.append($('').text(t))}),r.append(a)):r.append($('')),r},r=function(e){var t=this,i=$('').on("click",function(){n.toggle()}),n=$('
              ').hide();e.options&&$.each(e.options,function(e,i){"download_password"!==e&&n.append(a.call(t,e,i))}),t.append(i,n)},s=+new Date,l=0;return c.ext2mime||(c.ext2mime=Object.assign(n.arrayFlip(n.mimeTypes),o)),$.each(d.conv,function(o,a){var d=o.toLowerCase(),m="elfinder-edit-onlineconvert-"+d+s,g=$('
              ').data("cname",o);$.each(a,function(e,i){var a=e.toLowerCase(),s=f(o,e);c.ext2mime[s]||("audio"===d||"image"===d||"video"===d?c.ext2mime[s]=d+"/x-"+a:c.ext2mime[s]="application/octet-stream"),n.uploadMimeCheck(c.ext2mime[s],t.phash)&&g.append($('
              ').on("makeoption",function(e,t){var i=$(this);i.children(".elfinder-button-icon-preference").length||r.call(i,t)}).append($("").text(e).data("conv",e)))}),g.children().length&&(i.append($("
            • ").append($("").attr("href",u+"#"+m).text(o))),e.append(g),p[d]=l++)}),d.useTabs?e.prepend(i).tabs({beforeActivate:function(e,t){g(t.newPanel.data("cname"))}}):$.each(d.conv,function(t){var i=t.toLowerCase();e.append($('
              ').append($("").text(t)).append(e.children(".onlineconvert-category-"+i)))}),e}(),v=$(this).append(h,d.showLink?$(d.link):null),b=$('
              ').hide().html(''+n.i18n("nowLoading")+'').appendTo(v.parent()),x=$('
              ').appendTo(b),y=null,w=function(){return y?$.Deferred().resolve(y):(b.show(),n.forExternalUrl(t.hash,{progressBar:x}).done(function(e){y=e}).fail(function(e){e&&n.error(e),s.elfinderdialog("destroy")}).always(function(){b.hide()}))},k=function(e){$(s).data("dfrd",w().done(function(i){v.fadeOut(),j({info:"Start conversion request."}),n.request({data:{cmd:"editor",name:"OnlineConvert",method:"api","args[category]":e.category.toLowerCase(),"args[convert]":e.convert.toLowerCase(),"args[options]":JSON.stringify(e.options),"args[source]":n.convAbsUrl(i),"args[filename]":n.splitFileExtention(t.name)[0]+"."+f(e.category,e.convert),"args[mime]":t.mime},preventDefault:!0}).done(function(t){O(t.apires,e.category,e.convert)}).fail(function(e){e&&n.error(e),s.elfinderdialog("destroy")})}))},O=function(e,t,i){var o,a=[];e&&e.id?(o=e.status,"failed"===o.code?(b.hide(),e.errors&&e.errors.length&&$.each(e.errors,function(e,t){t.message&&a.push(t.message)}),n.error(a.length?a:o.info),v.fadeIn()):"completed"===o.code?M(e):(j(o),setTimeout(function(){C(e.id)},1e3))):(l.appendTo(s.closest(".ui-dialog")),e.message&&n.toast({msg:n.i18n(e.message),mode:"error",timeOut:5e3,onHidden:function(){1===l.children().length&&l.appendTo(n.getUI())}}),n.toast({msg:n.i18n("editorConvNoApi"),mode:"error",timeOut:3e3,onHidden:function(){1===l.children().length&&l.appendTo(n.getUI())}}),b.hide(),v.show())},j=function(e){b.show().children(".elfinder-spinner-text").text(e.info)},C=function(e){n.request({data:{cmd:"editor",name:"OnlineConvert",method:"api","args[jobid]":e},preventDefault:!0}).done(function(e){O(e.apires)}).fail(function(e){e&&n.error(e),s.elfinderdialog("destroy")})},M=function(e){var i=e.output,o=(e.id,"");b.hide(),i&&i.length&&(s.elfinderdialog("destroy"),$.each(i,function(e,t){t.uri&&(o+=t.uri+"\n")}),n.upload({target:t.phash,files:[o],type:"text",extraData:{contentSaveId:"OnlineConvert-"+e.id}}))},T="document";v.parent().css({overflow:"auto"}).addClass("overflow-scrolling-touch"),(r=t.mime.match(/^(audio|image|video)/))&&(T=r[1]),d.useTabs?p[T]&&h.tabs("option","active",p[T]):(a=Object.keys(d.conv).length,$.each(d.conv,function(e){return e.toLowerCase()===T?(g(e,function(){$.each(d.conv,function(e){e.toLowerCase()!==T&&g(e)})}),!1):void a--}),a||$.each(d.conv,function(e){g(e)}),v.parent().scrollTop(h.children(".onlineconvert-fieldset-"+T).offset().top))},load:function(){},getContent:function(){},save:function(){},close:function(e){var t=(this.fm,$(e).data("dfrd"));t&&"pending"===t.state()&&t.reject()}}]},window.elFinder); \ No newline at end of file diff --git a/panel/application/public/js/extras/quicklook.googledocs.js b/panel/application/public/js/extras/quicklook.googledocs.js new file mode 100644 index 0000000..a22e837 --- /dev/null +++ b/panel/application/public/js/extras/quicklook.googledocs.js @@ -0,0 +1,75 @@ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { +"use strict"; +try { + if (! elFinder.prototype.commands.quicklook.plugins) { + elFinder.prototype.commands.quicklook.plugins = []; + } + elFinder.prototype.commands.quicklook.plugins.push(function(ql) { + var fm = ql.fm, + preview = ql.preview; + + preview.on('update', function(e) { + var win = ql.window, + file = e.file, node, loading; + + if (file.mime.indexOf('application/vnd.google-apps.') === 0) { + if (file.url == '1') { + preview.hide(); + $('
              ').appendTo(ql.info.find('.elfinder-quicklook-info')) + .on('click', function() { + $(this).html(''); + fm.request({ + data : {cmd : 'url', target : file.hash}, + preventDefault : true + }) + .always(function() { + preview.show(); + $(this).html(''); + }) + .done(function(data) { + var rfile = fm.file(file.hash); + ql.value.url = rfile.url = data.url || ''; + if (ql.value.url) { + preview.trigger($.Event('update', {file : ql.value})); + } + }); + }); + } + if (file.url !== '' && file.url != '1') { + e.stopImmediatePropagation(); + + loading = $('
              '+fm.i18n('nowLoading')+'
              ').appendTo(ql.info.find('.elfinder-quicklook-info')); + + node = $('') + .css('background-color', 'transparent') + .on('load', function() { + ql.hideinfo(); + loading.remove(); + node.css('background-color', '#fff'); + }) + .on('error', function() { + loading.remove(); + node.remove(); + }) + .appendTo(preview) + .attr('src', fm.url(file.hash)); + + preview.one('change', function() { + loading.remove(); + node.off('load').remove(); + }); + } + } + + }); + }); +} catch(e) {} +})); diff --git a/panel/application/public/js/extras/quicklook.googledocs.min.js b/panel/application/public/js/extras/quicklook.googledocs.min.js new file mode 100644 index 0000000..3c33cb6 --- /dev/null +++ b/panel/application/public/js/extras/quicklook.googledocs.min.js @@ -0,0 +1 @@ +!function(e,n){"function"==typeof define&&define.amd?define(["elfinder"],n):"undefined"!=typeof exports?module.exports=n(require("elfinder")):n(e.elFinder)}(this,function(e){"use strict";try{e.prototype.commands.quicklook.plugins||(e.prototype.commands.quicklook.plugins=[]),e.prototype.commands.quicklook.plugins.push(function(e){var n=e.fm,o=e.preview;o.on("update",function(i){var r,a,t=(e.window,i.file);0===t.mime.indexOf("application/vnd.google-apps.")&&("1"==t.url&&(o.hide(),$('
              ").appendTo(e.info.find(".elfinder-quicklook-info")).on("click",function(){$(this).html(''),n.request({data:{cmd:"url",target:t.hash},preventDefault:!0}).always(function(){o.show(),$(this).html("")}).done(function(i){var r=n.file(t.hash);e.value.url=r.url=i.url||"",e.value.url&&o.trigger($.Event("update",{file:e.value}))})})),""!==t.url&&"1"!=t.url&&(i.stopImmediatePropagation(),a=$('
              '+n.i18n("nowLoading")+'
              ').appendTo(e.info.find(".elfinder-quicklook-info")),r=$('').css("background-color","transparent").on("load",function(){e.hideinfo(),a.remove(),r.css("background-color","#fff")}).on("error",function(){a.remove(),r.remove()}).appendTo(o).attr("src",n.url(t.hash)),o.one("change",function(){a.remove(),r.off("load").remove()})))})})}catch(n){}}); \ No newline at end of file diff --git a/panel/application/public/js/i18n/elfinder.ru.js b/panel/application/public/js/i18n/elfinder.ru.js new file mode 100644 index 0000000..c0dbd26 --- /dev/null +++ b/panel/application/public/js/i18n/elfinder.ru.js @@ -0,0 +1,581 @@ +/** + * Русский язык translation + * @author Dmitry "dio" Levashov + * @author Andrew Berezovsky + * @author Alex Yashkin + * @version 2020-01-24 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.ru = { + translator : 'Dmitry "dio" Levashov <dio@std42.ru>, Andrew Berezovsky <andrew.berezovsky@gmail.com>, Alex Yashkin <alex@yashkin.by>', + language : 'Русский язык', + direction : 'ltr', + dateFormat : 'd M Y H:i', // will show like: 24 Янв 2020 15:00 + fancyDateFormat : '$1 H:i', // will show like: Сегодня 15:00 + nonameDateFormat : 'ymd-His', // noname upload will show like: 200124-150054 + messages : { + + /********************************** errors **********************************/ + 'error' : 'Ошибка', + 'errUnknown' : 'Неизвестная ошибка.', + 'errUnknownCmd' : 'Неизвестная команда.', + 'errJqui' : 'Отсутствуют необходимые компоненты jQuery UI - selectable, draggable и droppable.', + 'errNode' : 'Отсутствует DOM элемент для инициализации elFinder.', + 'errURL' : 'Неверная конфигурация elFinder! Не указан URL.', + 'errAccess' : 'Доступ запрещен.', + 'errConnect' : 'Не удалось соединиться с сервером.', + 'errAbort' : 'Соединение прервано.', + 'errTimeout' : 'Таймаут соединения.', + 'errNotFound' : 'Сервер не найден.', + 'errResponse' : 'Некорректный ответ сервера.', + 'errConf' : 'Некорректная настройка сервера.', + 'errJSON' : 'Модуль PHP JSON не установлен.', + 'errNoVolumes' : 'Отсутствуют корневые директории достуные для чтения.', + 'errCmdParams' : 'Некорректные параметры команды "$1".', + 'errDataNotJSON' : 'Данные не в формате JSON.', + 'errDataEmpty' : 'Данные отсутствуют.', + 'errCmdReq' : 'Для запроса к серверу необходимо указать имя команды.', + 'errOpen' : 'Не удалось открыть "$1".', + 'errNotFolder' : 'Объект не является папкой.', + 'errNotFile' : 'Объект не является файлом.', + 'errRead' : 'Ошибка чтения "$1".', + 'errWrite' : 'Ошибка записи в "$1".', + 'errPerm' : 'Доступ запрещен.', + 'errLocked' : '"$1" защищен и не может быть переименован, перемещен или удален.', + 'errExists' : 'В папке уже существует файл с именем "$1".', + 'errInvName' : 'Недопустимое имя файла.', + 'errInvDirname' : 'Недопустимое имя папки.', // from v2.1.24 added 12.4.2017 + 'errFolderNotFound' : 'Папка не найдена.', + 'errFileNotFound' : 'Файл не найден.', + 'errTrgFolderNotFound' : 'Целевая папка "$1" не найдена.', + 'errPopup' : 'Браузер заблокировал открытие нового окна. Чтобы открыть файл, измените настройки браузера.', + 'errMkdir' : 'Ошибка создания папки "$1".', + 'errMkfile' : 'Ошибка создания файла "$1".', + 'errRename' : 'Ошибка переименования "$1".', + 'errCopyFrom' : 'Копирование файлов из директории "$1" запрещено.', + 'errCopyTo' : 'Копирование файлов в директорию "$1" запрещено.', + 'errMkOutLink' : 'Невозможно создать ссылку вне корня раздела.', // from v2.1 added 03.10.2015 + 'errUpload' : 'Ошибка загрузки.', // old name - errUploadCommon + 'errUploadFile' : 'Невозможно загрузить "$1".', // old name - errUpload + 'errUploadNoFiles' : 'Нет файлов для загрузки.', + 'errUploadTotalSize' : 'Превышен допустимый размер загружаемых данных.', // old name - errMaxSize + 'errUploadFileSize' : 'Размер файла превышает допустимый.', // old name - errFileMaxSize + 'errUploadMime' : 'Недопустимый тип файла.', + 'errUploadTransfer' : 'Ошибка передачи файла "$1".', + 'errUploadTemp' : 'Невозможно создать временный файл для загрузки.', // from v2.1 added 26.09.2015 + 'errNotReplace' : 'Объект "$1" по этому адресу уже существует и не может быть заменен объектом другого типа.', // new + 'errReplace' : 'Невозможно заменить "$1".', + 'errSave' : 'Невозможно сохранить "$1".', + 'errCopy' : 'Невозможно скопировать "$1".', + 'errMove' : 'Невозможно переместить "$1".', + 'errCopyInItself' : 'Невозможно скопировать "$1" в самого себя.', + 'errRm' : 'Невозможно удалить "$1".', + 'errTrash' : 'Невозможно переместить в корзину.', // from v2.1.24 added 30.4.2017 + 'errRmSrc' : 'Невозможно удалить файлы источника.', + 'errExtract' : 'Невозможно извлечь фалы из "$1".', + 'errArchive' : 'Невозможно создать архив.', + 'errArcType' : 'Неподдерживаемый тип архива.', + 'errNoArchive' : 'Файл не является архивом или неподдерживаемый тип архива.', + 'errCmdNoSupport' : 'Сервер не поддерживает эту команду.', + 'errReplByChild' : 'Невозможно заменить папку "$1" содержащимся в ней объектом.', + 'errArcSymlinks' : 'По соображениям безопасности запрещена распаковка архивов, содержащих ссылки (symlinks) или файлы с недопустимыми именами.', // edited 24.06.2012 + 'errArcMaxSize' : 'Размер файлов в архиве превышает максимально разрешенный.', + 'errResize' : 'Не удалось изменить размер "$1".', + 'errResizeDegree' : 'Некорректный градус поворота.', // added 7.3.2013 + 'errResizeRotate' : 'Невозможно повернуть изображение.', // added 7.3.2013 + 'errResizeSize' : 'Некорректный размер изображения.', // added 7.3.2013 + 'errResizeNoChange' : 'Размер изображения не изменился.', // added 7.3.2013 + 'errUsupportType' : 'Неподдерживаемый тип файла.', + 'errNotUTF8Content' : 'Файл "$1" содержит текст в кодировке отличной от UTF-8 и не может быть отредактирован.', // added 9.11.2011 + 'errNetMount' : 'Невозможно подключить "$1".', // added 17.04.2012 + 'errNetMountNoDriver' : 'Неподдерживаемый протокол.', // added 17.04.2012 + 'errNetMountFailed' : 'Ошибка монтирования.', // added 17.04.2012 + 'errNetMountHostReq' : 'Требуется указать хост.', // added 18.04.2012 + 'errSessionExpires' : 'Сессия была завершена так как превышено время отсутствия активности.', + 'errCreatingTempDir' : 'Невозможно создать временную директорию: "$1"', + 'errFtpDownloadFile' : 'Невозможно скачать файл с FTP: "$1"', + 'errFtpUploadFile' : 'Невозможно загрузить файл на FTP: "$1"', + 'errFtpMkdir' : 'Невозможно создать директорию на FTP: "$1"', + 'errArchiveExec' : 'Ошибка при выполнении архивации: "$1"', + 'errExtractExec' : 'Ошибка при выполнении распаковки: "$1"', + 'errNetUnMount' : 'Невозможно отключить', // from v2.1 added 30.04.2012 + 'errConvUTF8' : 'Не конвертируется в UTF-8', // from v2.1 added 08.04.2014 + 'errFolderUpload' : 'Если вы хотите загружать папки, попробуйте Google Chrome.', // from v2.1 added 26.6.2015 + 'errSearchTimeout' : 'Превышено время ожидания при поиске "$1". Результаты поиска частичные.', // from v2.1 added 12.1.2016 + 'errReauthRequire' : 'Требуется повторная авторизация.', // from v2.1.10 added 24.3.2016 + 'errMaxTargets' : 'Максимальное число выбираемых файлов: $1.', // from v2.1.17 added 17.10.2016 + 'errRestore' : 'Невозможно восстановить из корзины. Не удалось определить путь для восстановления.', // from v2.1.24 added 3.5.2017 + 'errEditorNotFound' : 'Не найден редактор для этого типа файлов.', // from v2.1.25 added 23.5.2017 + 'errServerError' : 'Возникла ошибка на стороне сервера.', // from v2.1.25 added 16.6.2017 + 'errEmpty' : 'Невозможно очистить папку "$1".', // from v2.1.25 added 22.6.2017 + 'moreErrors' : 'Еще ошибок: $1', // from v2.1.44 added 9.12.2018 + + /******************************* commands names ********************************/ + 'cmdarchive' : 'Создать архив', + 'cmdback' : 'Назад', + 'cmdcopy' : 'Копировать', + 'cmdcut' : 'Вырезать', + 'cmddownload' : 'Скачать', + 'cmdduplicate' : 'Сделать копию', + 'cmdedit' : 'Редактировать файл', + 'cmdextract' : 'Распаковать архив', + 'cmdforward' : 'Вперед', + 'cmdgetfile' : 'Выбрать файлы', + 'cmdhelp' : 'О программе', + 'cmdhome' : 'Домой', + 'cmdinfo' : 'Свойства', + 'cmdmkdir' : 'Новая папка', + 'cmdmkdirin' : 'В новую папку', // from v2.1.7 added 19.2.2016 + 'cmdmkfile' : 'Новый файл', + 'cmdopen' : 'Открыть', + 'cmdpaste' : 'Вставить', + 'cmdquicklook' : 'Быстрый просмотр', + 'cmdreload' : 'Обновить', + 'cmdrename' : 'Переименовать', + 'cmdrm' : 'Удалить', + 'cmdtrash' : 'Переместить в корзину', //from v2.1.24 added 29.4.2017 + 'cmdrestore' : 'Восстановить', //from v2.1.24 added 3.5.2017 + 'cmdsearch' : 'Поиск файлов', + 'cmdup' : 'Наверх', + 'cmdupload' : 'Загрузить файлы', + 'cmdview' : 'Вид', + 'cmdresize' : 'Изменить размер и повернуть', + 'cmdsort' : 'Сортировать', + 'cmdnetmount' : 'Подключить сетевой раздел', // added 18.04.2012 + 'cmdnetunmount': 'Отключить', // from v2.1 added 30.04.2012 + 'cmdplaces' : 'В избранное', // added 28.12.2014 + 'cmdchmod' : 'Изменить права доступа', // from v2.1 added 20.6.2015 + 'cmdopendir' : 'Открыть папку', // from v2.1 added 13.1.2016 + 'cmdcolwidth' : 'Сбросить ширину колонок', // from v2.1.13 added 12.06.2016 + 'cmdfullscreen': 'Полный экран', // from v2.1.15 added 03.08.2016 + 'cmdmove' : 'Переместить', // from v2.1.15 added 21.08.2016 + 'cmdempty' : 'Очистить папку', // from v2.1.25 added 22.06.2017 + 'cmdundo' : 'Отменить', // from v2.1.27 added 31.07.2017 + 'cmdredo' : 'Вернуть', // from v2.1.27 added 31.07.2017 + 'cmdpreference': 'Предпочтения', // from v2.1.27 added 03.08.2017 + 'cmdselectall' : 'Выбрать все', // from v2.1.28 added 15.08.2017 + 'cmdselectnone': 'Отменить выбор', // from v2.1.28 added 15.08.2017 + 'cmdselectinvert': 'Инвертировать выбор', // from v2.1.28 added 15.08.2017 + 'cmdopennew' : 'Открыть в новом окне', // from v2.1.38 added 3.4.2018 + 'cmdhide' : 'Скрыть (персонально)', // from v2.1.41 added 24.7.2018 + + /*********************************** buttons ***********************************/ + 'btnClose' : 'Закрыть', + 'btnSave' : 'Сохранить', + 'btnRm' : 'Удалить', + 'btnApply' : 'Применить', + 'btnCancel' : 'Отмена', + 'btnNo' : 'Нет', + 'btnYes' : 'Да', + 'btnMount' : 'Подключить', // added 18.04.2012 + 'btnApprove': 'Перейти в $1 и применить', // from v2.1 added 26.04.2012 + 'btnUnmount': 'Отключить', // from v2.1 added 30.04.2012 + 'btnConv' : 'Конвертировать', // from v2.1 added 08.04.2014 + 'btnCwd' : 'Здесь', // from v2.1 added 22.5.2015 + 'btnVolume' : 'Раздел', // from v2.1 added 22.5.2015 + 'btnAll' : 'Все', // from v2.1 added 22.5.2015 + 'btnMime' : 'MIME тип', // from v2.1 added 22.5.2015 + 'btnFileName':'Имя файла', // from v2.1 added 22.5.2015 + 'btnSaveClose': 'Сохранить и закрыть', // from v2.1 added 12.6.2015 + 'btnBackup' : 'Резервная копия', // fromv2.1 added 28.11.2015 + 'btnRename' : 'Переименовать', // from v2.1.24 added 6.4.2017 + 'btnRenameAll' : 'Переименовать (все)', // from v2.1.24 added 6.4.2017 + 'btnPrevious' : 'Пред. ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnNext' : 'След. ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnSaveAs' : 'Сохранить как', // from v2.1.25 added 24.5.2017 + + /******************************** notifications ********************************/ + 'ntfopen' : 'Открыть папку', + 'ntffile' : 'Открыть файл', + 'ntfreload' : 'Обновить текущую папку', + 'ntfmkdir' : 'Создание папки', + 'ntfmkfile' : 'Создание файлов', + 'ntfrm' : 'Удалить файлы', + 'ntfcopy' : 'Скопировать файлы', + 'ntfmove' : 'Переместить файлы', + 'ntfprepare' : 'Подготовка к копированию файлов', + 'ntfrename' : 'Переименовать файлы', + 'ntfupload' : 'Загрузка файлов', + 'ntfdownload' : 'Скачивание файлов', + 'ntfsave' : 'Сохранить файлы', + 'ntfarchive' : 'Создание архива', + 'ntfextract' : 'Распаковка архива', + 'ntfsearch' : 'Поиск файлов', + 'ntfresize' : 'Изменение размеров изображений', + 'ntfsmth' : 'Занят важным делом', + 'ntfloadimg' : 'Загрузка изображения', + 'ntfnetmount' : 'Подключение сетевого диска', // added 18.04.2012 + 'ntfnetunmount': 'Отключение сетевого диска', // from v2.1 added 30.04.2012 + 'ntfdim' : 'Получение размеров изображения', // added 20.05.2013 + 'ntfreaddir' : 'Чтение информации о папке', // from v2.1 added 01.07.2013 + 'ntfurl' : 'Получение URL ссылки', // from v2.1 added 11.03.2014 + 'ntfchmod' : 'Изменение прав доступа к файлу', // from v2.1 added 20.6.2015 + 'ntfpreupload': 'Проверка измени загруженного файла', // from v2.1 added 31.11.2015 + 'ntfzipdl' : 'Создание файла для скачки', // from v2.1.7 added 23.1.2016 + 'ntfparents' : 'Получение информации о пути', // from v2.1.17 added 2.11.2016 + 'ntfchunkmerge': 'Обработка загруженного файла', // from v2.1.17 added 2.11.2016 + 'ntftrash' : 'Перемещение в корзину', // from v2.1.24 added 2.5.2017 + 'ntfrestore' : 'Восстановление из корзины', // from v2.1.24 added 3.5.2017 + 'ntfchkdir' : 'Проверка папки назначения', // from v2.1.24 added 3.5.2017 + 'ntfundo' : 'Отмена предыдущей операции', // from v2.1.27 added 31.07.2017 + 'ntfredo' : 'Восстановление предыдущей операции', // from v2.1.27 added 31.07.2017 + 'ntfchkcontent' : 'Проверка содержимого', // from v2.1.41 added 3.8.2018 + + /*********************************** volumes *********************************/ + 'volume_Trash' : 'Корзина', //from v2.1.24 added 29.4.2017 + + /************************************ dates **********************************/ + 'dateUnknown' : 'неизвестно', + 'Today' : 'Сегодня', + 'Yesterday' : 'Вчера', + 'msJan' : 'Янв', + 'msFeb' : 'Фев', + 'msMar' : 'Мар', + 'msApr' : 'Апр', + 'msMay' : 'Май', + 'msJun' : 'Июн', + 'msJul' : 'Июл', + 'msAug' : 'Авг', + 'msSep' : 'Сен', + 'msOct' : 'Окт', + 'msNov' : 'Ноя', + 'msDec' : 'Дек', + 'January' : 'Январь', + 'February' : 'Февраль', + 'March' : 'Март', + 'April' : 'Апрель', + 'May' : 'Май', + 'June' : 'Июнь', + 'July' : 'Июль', + 'August' : 'Август', + 'September' : 'Сентябрь', + 'October' : 'Октябрь', + 'November' : 'Ноябрь', + 'December' : 'Декабрь', + 'Sunday' : 'Воскресенье', + 'Monday' : 'Понедельник', + 'Tuesday' : 'Вторник', + 'Wednesday' : 'Среда', + 'Thursday' : 'Четверг', + 'Friday' : 'Пятница', + 'Saturday' : 'Суббота', + 'Sun' : 'Вск', + 'Mon' : 'Пнд', + 'Tue' : 'Втр', + 'Wed' : 'Срд', + 'Thu' : 'Чтв', + 'Fri' : 'Птн', + 'Sat' : 'Сбт', + + /******************************** sort variants ********************************/ + 'sortname' : 'по имени', + 'sortkind' : 'по типу', + 'sortsize' : 'по размеру', + 'sortdate' : 'по дате', + 'sortFoldersFirst' : 'Папки в начале', + 'sortperm' : 'по разрешениям', // from v2.1.13 added 13.06.2016 + 'sortmode' : 'по режиму', // from v2.1.13 added 13.06.2016 + 'sortowner' : 'по владельцу', // from v2.1.13 added 13.06.2016 + 'sortgroup' : 'по группе', // from v2.1.13 added 13.06.2016 + 'sortAlsoTreeview' : 'Также и дерево каталогов', // from v2.1.15 added 01.08.2016 + + /********************************** new items **********************************/ + 'untitled file.txt' : 'НовыйФайл.txt', // added 10.11.2015 + 'untitled folder' : 'НоваяПапка', // added 10.11.2015 + 'Archive' : 'НовыйАрхив', // from v2.1 added 10.11.2015 + 'untitled file' : 'НовыйФайл.$1', // from v2.1.41 added 6.8.2018 + 'extentionfile' : '$1 Файл', // from v2.1.41 added 6.8.2018 + 'extentiontype' : '$1: $2', // from v2.1.43 added 17.10.2018 + + /********************************** messages **********************************/ + 'confirmReq' : 'Необходимо подтверждение', + 'confirmRm' : 'Вы уверены, что хотите удалить файлы?
              Действие необратимо!', + 'confirmRepl' : 'Заменить старый файл новым?', + 'confirmRest' : 'Заменить существующий файл файлом из корзины?', // fromv2.1.24 added 5.5.2017 + 'confirmConvUTF8' : 'Не UTF-8
              Сконвертировать в UTF-8?
              Данные станут UTF-8 при сохранении после конвертации.', // from v2.1 added 08.04.2014 + 'confirmNonUTF8' : 'Невозможно определить кодировку файла. Необходима предварительная конвертация файла в UTF-8 для дальнейшего редактирования.
              Выберите кодировку файла.', // from v2.1.19 added 28.11.2016 + 'confirmNotSave' : 'Произошли изменения.
              Если не сохраните изменения, то потеряете их.', // from v2.1 added 15.7.2015 + 'confirmTrash' : 'Вы уверены, что хотите переместить файлы в корзину?', //from v2.1.24 added 29.4.2017 + 'confirmMove' : 'Вы уверены, что хотите переместить файлы в "$1"?', //from v2.1.50 added 27.7.2019 + 'apllyAll' : 'Применить для всех', + 'name' : 'Имя', + 'size' : 'Размер', + 'perms' : 'Доступ', + 'modify' : 'Изменен', + 'kind' : 'Тип', + 'read' : 'чтение', + 'write' : 'запись', + 'noaccess' : 'нет доступа', + 'and' : 'и', + 'unknown' : 'неизвестно', + 'selectall' : 'Выбрать все файлы', + 'selectfiles' : 'Выбрать файл(ы)', + 'selectffile' : 'Выбрать первый файл', + 'selectlfile' : 'Выбрать последний файл', + 'viewlist' : 'В виде списка', + 'viewicons' : 'В виде иконок', + 'viewSmall' : 'Маленькие иконки', // from v2.1.39 added 22.5.2018 + 'viewMedium' : 'Средние иконки', // from v2.1.39 added 22.5.2018 + 'viewLarge' : 'Большие иконки', // from v2.1.39 added 22.5.2018 + 'viewExtraLarge' : 'Очень большие иконки', // from v2.1.39 added 22.5.2018 + 'places' : 'Избранное', + 'calc' : 'Вычислить', + 'path' : 'Путь', + 'aliasfor' : 'Указывает на', + 'locked' : 'Защита', + 'dim' : 'Размеры', + 'files' : 'Файлы', + 'folders' : 'Папки', + 'items' : 'Объекты', + 'yes' : 'да', + 'no' : 'нет', + 'link' : 'Ссылка', + 'searcresult' : 'Результаты поиска', + 'selected' : 'выбрано', + 'about' : 'О программе', + 'shortcuts' : 'Горячие клавиши', + 'help' : 'Помощь', + 'webfm' : 'Файловый менеджер для Web', + 'ver' : 'Версия', + 'protocolver' : 'версия протокола', + 'homepage' : 'Сайт проекта', + 'docs' : 'Документация', + 'github' : 'Форкните на GitHub', + 'twitter' : 'Следите в Twitter', + 'facebook' : 'Присоединяйтесь на Facebook', + 'team' : 'Команда', + 'chiefdev' : 'ведущий разработчик', + 'developer' : 'разработчик', + 'contributor' : 'участник', + 'maintainer' : 'сопровождение проекта', + 'translator' : 'переводчик', + 'icons' : 'Иконки', + 'dontforget' : 'и не забудьте взять своё полотенце', + 'shortcutsof' : 'Горячие клавиши отключены', + 'dropFiles' : 'Перетащите файлы сюда', + 'or' : 'или', + 'selectForUpload' : 'Выбрать файлы для загрузки', + 'moveFiles' : 'Переместить файлы', + 'copyFiles' : 'Скопировать файлы', + 'restoreFiles' : 'Восстановить файлы', // from v2.1.24 added 5.5.2017 + 'rmFromPlaces' : 'Удалить из избранного', + 'aspectRatio' : 'Соотношение сторон', + 'scale' : 'Масштаб', + 'width' : 'Ширина', + 'height' : 'Высота', + 'resize' : 'Изменить размер', + 'crop' : 'Обрезать', + 'rotate' : 'Повернуть', + 'rotate-cw' : 'Повернуть на 90 градусов по часовой стрелке', + 'rotate-ccw' : 'Повернуть на 90 градусов против часовой стрелке', + 'degree' : '°', + 'netMountDialogTitle' : 'Подключить сетевой диск', // added 18.04.2012 + 'protocol' : 'Протокол', // added 18.04.2012 + 'host' : 'Хост', // added 18.04.2012 + 'port' : 'Порт', // added 18.04.2012 + 'user' : 'Пользователь', // added 18.04.2012 + 'pass' : 'Пароль', // added 18.04.2012 + 'confirmUnmount' : 'Вы хотите отключить $1?', // from v2.1 added 30.04.2012 + 'dropFilesBrowser': 'Перетащите или вставьте файлы из браузера', // from v2.1 added 30.05.2012 + 'dropPasteFiles' : 'Перетащите или вставьте файлы и ссылки сюда', // from v2.1 added 07.04.2014 + 'encoding' : 'Кодировка', // from v2.1 added 19.12.2014 + 'locale' : 'Локаль', // from v2.1 added 19.12.2014 + 'searchTarget' : 'Цель: $1', // from v2.1 added 22.5.2015 + 'searchMime' : 'Поиск по введенному MIME типу', // from v2.1 added 22.5.2015 + 'owner' : 'Владелец', // from v2.1 added 20.6.2015 + 'group' : 'Группа', // from v2.1 added 20.6.2015 + 'other' : 'Остальные', // from v2.1 added 20.6.2015 + 'execute' : 'Исполнить', // from v2.1 added 20.6.2015 + 'perm' : 'Разрешение', // from v2.1 added 20.6.2015 + 'mode' : 'Режим', // from v2.1 added 20.6.2015 + 'emptyFolder' : 'Папка пуста', // from v2.1.6 added 30.12.2015 + 'emptyFolderDrop' : 'Папка пуста\\A Перетащите чтобы добавить', // from v2.1.6 added 30.12.2015 + 'emptyFolderLTap' : 'Папка пуста\\A Долгое нажатие чтобы добавить', // from v2.1.6 added 30.12.2015 + 'quality' : 'Качество', // from v2.1.6 added 5.1.2016 + 'autoSync' : 'Авто синхронизация', // from v2.1.6 added 10.1.2016 + 'moveUp' : 'Передвинуть вверх', // from v2.1.6 added 18.1.2016 + 'getLink' : 'Получить URL ссылку', // from v2.1.7 added 9.2.2016 + 'selectedItems' : 'Выбранные объекты ($1)', // from v2.1.7 added 2.19.2016 + 'folderId' : 'ID папки', // from v2.1.10 added 3.25.2016 + 'offlineAccess' : 'Позволить автономный доступ', // from v2.1.10 added 3.25.2016 + 'reAuth' : 'Авторизоваться повторно', // from v2.1.10 added 3.25.2016 + 'nowLoading' : 'Загружается...', // from v2.1.12 added 4.26.2016 + 'openMulti' : 'Открыть несколько файлов', // from v2.1.12 added 5.14.2016 + 'openMultiConfirm': 'Вы пытаетесь открыть $1 файл(а/ов). Вы уверены, что хотите открыть их в браузере?', // from v2.1.12 added 5.14.2016 + 'emptySearch' : 'Ничего не найдено', // from v2.1.12 added 5.16.2016 + 'editingFile' : 'Это редактируемый файл.', // from v2.1.13 added 6.3.2016 + 'hasSelected' : 'Вы выбрали $1 файл(-ов).', // from v2.1.13 added 6.3.2016 + 'hasClipboard' : 'У вас $1 файл(-ов) в буфере обмена.', // from v2.1.13 added 6.3.2016 + 'incSearchOnly' : 'Инкрементный поиск возможен только из текущего вида.', // from v2.1.13 added 6.30.2016 + 'reinstate' : 'Восстановить', // from v2.1.15 added 3.8.2016 + 'complete' : '$1 завершен', // from v2.1.15 added 21.8.2016 + 'contextmenu' : 'Контекстное меню', // from v2.1.15 added 9.9.2016 + 'pageTurning' : 'Переключение страницы', // from v2.1.15 added 10.9.2016 + 'volumeRoots' : 'Корни томов', // from v2.1.16 added 16.9.2016 + 'reset' : 'Сбросить', // from v2.1.16 added 1.10.2016 + 'bgcolor' : 'Фоновый цвет', // from v2.1.16 added 1.10.2016 + 'colorPicker' : 'Выбор цвета', // from v2.1.16 added 1.10.2016 + '8pxgrid' : '8px сетка', // from v2.1.16 added 4.10.2016 + 'enabled' : 'Включено', // from v2.1.16 added 4.10.2016 + 'disabled' : 'Отключено', // from v2.1.16 added 4.10.2016 + 'emptyIncSearch' : 'Ничего не найдено в текущем виде.\\AНажмите [Enter] для развертывания цели поиска.', // from v2.1.16 added 5.10.2016 + 'emptyLetSearch' : 'Поиск по первому символу не дал результатов в текущем виде.', // from v2.1.23 added 24.3.2017 + 'textLabel' : 'Текстовая метка', // from v2.1.17 added 13.10.2016 + 'minsLeft' : '$1 минут осталось', // from v2.1.17 added 13.11.2016 + 'openAsEncoding' : 'Переоткрыть с выбранной кодировкой', // from v2.1.19 added 2.12.2016 + 'saveAsEncoding' : 'Сохранить с выбранной кодировкой', // from v2.1.19 added 2.12.2016 + 'selectFolder' : 'Выбрать папку', // from v2.1.20 added 13.12.2016 + 'firstLetterSearch': 'Поиск по первому символу', // from v2.1.23 added 24.3.2017 + 'presets' : 'Пресеты', // from v2.1.25 added 26.5.2017 + 'tooManyToTrash' : 'Слишком много файлов для перемещения в корзину.', // from v2.1.25 added 9.6.2017 + 'TextArea' : 'Текстовая область', // from v2.1.25 added 14.6.2017 + 'folderToEmpty' : 'Очистить папку "$1".', // from v2.1.25 added 22.6.2017 + 'filderIsEmpty' : 'Нет файлов в паке "$1".', // from v2.1.25 added 22.6.2017 + 'preference' : 'Настройки', // from v2.1.26 added 28.6.2017 + 'language' : 'Язык', // from v2.1.26 added 28.6.2017 + 'clearBrowserData': 'Сбросить настройки для этого браузера', // from v2.1.26 added 28.6.2017 + 'toolbarPref' : 'Настройки панели', // from v2.1.27 added 2.8.2017 + 'charsLeft' : '... еще символов: $1.', // from v2.1.29 added 30.8.2017 + 'linesLeft' : '... еще строк: $1.', // from v2.1.52 added 16.1.2020 + 'sum' : 'Общий размер', // from v2.1.29 added 28.9.2017 + 'roughFileSize' : 'Приблизительный размер файла', // from v2.1.30 added 2.11.2017 + 'autoFocusDialog' : 'Фокус на элементе диалога при наведении мыши', // from v2.1.30 added 2.11.2017 + 'select' : 'Выбрать', // from v2.1.30 added 23.11.2017 + 'selectAction' : 'Действие при выборе файла', // from v2.1.30 added 23.11.2017 + 'useStoredEditor' : 'Открывать в редакторе, выбранном в прошлый раз', // from v2.1.30 added 23.11.2017 + 'selectinvert' : 'Выбрать элементы с инвертированием', // from v2.1.30 added 25.11.2017 + 'renameMultiple' : 'Переименовать выбранные элементы ($1 шт.) в $2?
              Действие нельзя отменить!', // from v2.1.31 added 4.12.2017 + 'batchRename' : 'Групповое переименование', // from v2.1.31 added 8.12.2017 + 'plusNumber' : '+ Число', // from v2.1.31 added 8.12.2017 + 'asPrefix' : 'Добавить префикс', // from v2.1.31 added 8.12.2017 + 'asSuffix' : 'Добавить суффикс', // from v2.1.31 added 8.12.2017 + 'changeExtention' : 'Изменить расширение', // from v2.1.31 added 8.12.2017 + 'columnPref' : 'Настройки колонок (для просмотра в виде списка)', // from v2.1.32 added 6.2.2018 + 'reflectOnImmediate' : 'Все изменения будут немедленно отражены в архиве.', // from v2.1.33 added 2.3.2018 + 'reflectOnUnmount' : 'Изменения не вступят в силу до тех пор, пока вы не размонтируете этот том.', // from v2.1.33 added 2.3.2018 + 'unmountChildren' : 'Тома, смонтированные на этом томе, также будут размонтированы. Вы хотите отключить его?', // from v2.1.33 added 5.3.2018 + 'selectionInfo' : 'Свойства', // from v2.1.33 added 7.3.2018 + 'hashChecker' : 'Алгоритмы для отображения хеш-сумм файлов', // from v2.1.33 added 10.3.2018 + 'infoItems' : 'Элементы в панели свойств', // from v2.1.38 added 28.3.2018 + 'pressAgainToExit': 'Нажмите снова для выхода.', // from v2.1.38 added 1.4.2018 + 'toolbar' : 'Панель', // from v2.1.38 added 4.4.2018 + 'workspace' : 'Рабочая область', // from v2.1.38 added 4.4.2018 + 'dialog' : 'Диалог', // from v2.1.38 added 4.4.2018 + 'all' : 'Все', // from v2.1.38 added 4.4.2018 + 'iconSize' : 'Размер иконок (В виде иконок)', // from v2.1.39 added 7.5.2018 + 'editorMaximized' : 'Открывать редактор в развернутом виде', // from v2.1.40 added 30.6.2018 + 'editorConvNoApi' : 'Так как конвертация с помощью API недоступно, произведите конвертацию на веб-сайте.', //from v2.1.40 added 8.7.2018 + 'editorConvNeedUpload' : 'После конвертации вы должны загрузить скачанный файл, чтобы сохранить его.', //from v2.1.40 added 8.7.2018 + 'convertOn' : 'Конвертировать на сайте $1', // from v2.1.40 added 10.7.2018 + 'integrations' : 'Интеграции', // from v2.1.40 added 11.7.2018 + 'integrationWith' : 'Менеджер elFinder интегрирован со следующими внешними сервисами. Ознакомьтесь с правилами пользования, политиками безопасности и др. перед их использованием.', // from v2.1.40 added 11.7.2018 + 'showHidden' : 'Показать скрытые элементы', // from v2.1.41 added 24.7.2018 + 'hideHidden' : 'Скрыть скрытые элементы', // from v2.1.41 added 24.7.2018 + 'toggleHidden' : 'Показать/скрыть скрытые элементы', // from v2.1.41 added 24.7.2018 + 'makefileTypes' : 'Типы файлов в меню "Новый файл"', // from v2.1.41 added 7.8.2018 + 'typeOfTextfile' : 'Тип текстового файла', // from v2.1.41 added 7.8.2018 + 'add' : 'Добавить', // from v2.1.41 added 7.8.2018 + 'theme' : 'Тема', // from v2.1.43 added 19.10.2018 + 'default' : 'По умолчанию', // from v2.1.43 added 19.10.2018 + 'description' : 'Описание', // from v2.1.43 added 19.10.2018 + 'website' : 'Веб-сайт', // from v2.1.43 added 19.10.2018 + 'author' : 'Автор', // from v2.1.43 added 19.10.2018 + 'email' : 'Email', // from v2.1.43 added 19.10.2018 + 'license' : 'Лицензия', // from v2.1.43 added 19.10.2018 + 'exportToSave' : 'Невозможно сохранить файл. Чтобы не потерять изменения, экспортируйте их на свой ПК.', // from v2.1.44 added 1.12.2018 + 'dblclickToSelect': 'Двойной клик по файлу для его выбора.', // from v2.1.47 added 22.1.2019 + 'useFullscreen' : 'Использовать полноэкранный режим', // from v2.1.47 added 19.2.2019 + + /********************************** mimetypes **********************************/ + 'kindUnknown' : 'Неизвестный', + 'kindRoot' : 'Корень тома', // from v2.1.16 added 16.10.2016 + 'kindFolder' : 'Папка', + 'kindSelects' : 'Выбор', // from v2.1.29 added 29.8.2017 + 'kindAlias' : 'Ссылка', + 'kindAliasBroken' : 'Битая ссылка', + // applications + 'kindApp' : 'Приложение', + 'kindPostscript' : 'Документ Postscript', + 'kindMsOffice' : 'Документ Microsoft Office', + 'kindMsWord' : 'Документ Microsoft Word', + 'kindMsExcel' : 'Документ Microsoft Excel', + 'kindMsPP' : 'Презентация Microsoft Powerpoint', + 'kindOO' : 'Документ Open Office', + 'kindAppFlash' : 'Приложение Flash', + 'kindPDF' : 'Документ PDF', + 'kindTorrent' : 'Файл Bittorrent', + 'kind7z' : 'Архив 7z', + 'kindTAR' : 'Архив TAR', + 'kindGZIP' : 'Архив GZIP', + 'kindBZIP' : 'Архив BZIP', + 'kindXZ' : 'Архив XZ', + 'kindZIP' : 'Архив ZIP', + 'kindRAR' : 'Архив RAR', + 'kindJAR' : 'Файл Java JAR', + 'kindTTF' : 'Шрифт True Type', + 'kindOTF' : 'Шрифт Open Type', + 'kindRPM' : 'Пакет RPM', + // texts + 'kindText' : 'Текстовый документ', + 'kindTextPlain' : 'Простой текст', + 'kindPHP' : 'Исходник PHP', + 'kindCSS' : 'Таблицы стилей CSS', + 'kindHTML' : 'Документ HTML', + 'kindJS' : 'Исходник Javascript', + 'kindRTF' : 'Rich Text Format', + 'kindC' : 'Исходник C', + 'kindCHeader' : 'Заголовочный файл C', + 'kindCPP' : 'Исходник C++', + 'kindCPPHeader' : 'Заголовочный файл C++', + 'kindShell' : 'Скрипт Unix shell', + 'kindPython' : 'Исходник Python', + 'kindJava' : 'Исходник Java', + 'kindRuby' : 'Исходник Ruby', + 'kindPerl' : 'Исходник Perl', + 'kindSQL' : 'Исходник SQL', + 'kindXML' : 'Документ XML', + 'kindAWK' : 'Исходник AWK', + 'kindCSV' : 'Текст с разделителями', + 'kindDOCBOOK' : 'Документ Docbook XML', + 'kindMarkdown' : 'Текст Markdown', // added 20.7.2015 + // images + 'kindImage' : 'Изображение', + 'kindBMP' : 'Изображение BMP', + 'kindJPEG' : 'Изображение JPEG', + 'kindGIF' : 'Изображение GIF', + 'kindPNG' : 'Изображение PNG', + 'kindTIFF' : 'Изображение TIFF', + 'kindTGA' : 'Изображение TGA', + 'kindPSD' : 'Изображение Adobe Photoshop', + 'kindXBITMAP' : 'Изображение X bitmap', + 'kindPXM' : 'Изображение Pixelmator', + // media + 'kindAudio' : 'Аудио файл', + 'kindAudioMPEG' : 'Аудио MPEG', + 'kindAudioMPEG4' : 'Аудио MPEG-4', + 'kindAudioMIDI' : 'Аудио MIDI', + 'kindAudioOGG' : 'Аудио Ogg Vorbis', + 'kindAudioWAV' : 'Аудио WAV', + 'AudioPlaylist' : 'Плейлист MP3', + 'kindVideo' : 'Видео файл', + 'kindVideoDV' : 'Видео DV', + 'kindVideoMPEG' : 'Видео MPEG', + 'kindVideoMPEG4' : 'Видео MPEG-4', + 'kindVideoAVI' : 'Видео AVI', + 'kindVideoMOV' : 'Видео Quick Time', + 'kindVideoWM' : 'Видео Windows Media', + 'kindVideoFlash' : 'Видео Flash', + 'kindVideoMKV' : 'Видео Matroska', + 'kindVideoOGG' : 'Видео Ogg' + } + }; +})); + diff --git a/panel/application/public/js/jquery-ui.min.js b/panel/application/public/js/jquery-ui.min.js new file mode 100644 index 0000000..67b4289 --- /dev/null +++ b/panel/application/public/js/jquery-ui.min.js @@ -0,0 +1,13 @@ +/*! jQuery UI - v1.11.2 - 2015-01-25 +* http://jqueryui.com +* Includes: core.js, widget.js, mouse.js, position.js, draggable.js, droppable.js, resizable.js, selectable.js, sortable.js, accordion.js, autocomplete.js, button.js, datepicker.js, dialog.js, menu.js, progressbar.js, selectmenu.js, slider.js, spinner.js, tabs.js, tooltip.js, effect.js, effect-blind.js, effect-bounce.js, effect-clip.js, effect-drop.js, effect-explode.js, effect-fade.js, effect-fold.js, effect-highlight.js, effect-puff.js, effect-pulsate.js, effect-scale.js, effect-shake.js, effect-size.js, effect-slide.js, effect-transfer.js +* Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */ + +(function(e){"function"==typeof define&&define.amd?define(["jquery"],e):e(jQuery)})(function(e){function t(t,s){var n,a,o,r=t.nodeName.toLowerCase();return"area"===r?(n=t.parentNode,a=n.name,t.href&&a&&"map"===n.nodeName.toLowerCase()?(o=e("img[usemap='#"+a+"']")[0],!!o&&i(o)):!1):(/input|select|textarea|button|object/.test(r)?!t.disabled:"a"===r?t.href||s:s)&&i(t)}function i(t){return e.expr.filters.visible(t)&&!e(t).parents().addBack().filter(function(){return"hidden"===e.css(this,"visibility")}).length}function s(e){for(var t,i;e.length&&e[0]!==document;){if(t=e.css("position"),("absolute"===t||"relative"===t||"fixed"===t)&&(i=parseInt(e.css("zIndex"),10),!isNaN(i)&&0!==i))return i;e=e.parent()}return 0}function n(){this._curInst=null,this._keyEvent=!1,this._disabledInputs=[],this._datepickerShowing=!1,this._inDialog=!1,this._mainDivId="ui-datepicker-div",this._inlineClass="ui-datepicker-inline",this._appendClass="ui-datepicker-append",this._triggerClass="ui-datepicker-trigger",this._dialogClass="ui-datepicker-dialog",this._disableClass="ui-datepicker-disabled",this._unselectableClass="ui-datepicker-unselectable",this._currentClass="ui-datepicker-current-day",this._dayOverClass="ui-datepicker-days-cell-over",this.regional=[],this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su","Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:!1,hideIfNoPrevNext:!1,navigationAsDateFormat:!1,gotoCurrent:!1,changeMonth:!1,changeYear:!1,yearRange:"c-10:c+10",showOtherMonths:!1,selectOtherMonths:!1,showWeek:!1,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:!0,showButtonPanel:!1,autoSize:!1,disabled:!1},e.extend(this._defaults,this.regional[""]),this.regional.en=e.extend(!0,{},this.regional[""]),this.regional["en-US"]=e.extend(!0,{},this.regional.en),this.dpDiv=a(e("
              "))}function a(t){var i="button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";return t.delegate(i,"mouseout",function(){e(this).removeClass("ui-state-hover"),-1!==this.className.indexOf("ui-datepicker-prev")&&e(this).removeClass("ui-datepicker-prev-hover"),-1!==this.className.indexOf("ui-datepicker-next")&&e(this).removeClass("ui-datepicker-next-hover")}).delegate(i,"mouseover",o)}function o(){e.datepicker._isDisabledDatepicker(v.inline?v.dpDiv.parent()[0]:v.input[0])||(e(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"),e(this).addClass("ui-state-hover"),-1!==this.className.indexOf("ui-datepicker-prev")&&e(this).addClass("ui-datepicker-prev-hover"),-1!==this.className.indexOf("ui-datepicker-next")&&e(this).addClass("ui-datepicker-next-hover"))}function r(t,i){e.extend(t,i);for(var s in i)null==i[s]&&(t[s]=i[s]);return t}function h(e){return function(){var t=this.element.val();e.apply(this,arguments),this._refresh(),t!==this.element.val()&&this._trigger("change")}}e.ui=e.ui||{},e.extend(e.ui,{version:"1.11.2",keyCode:{BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38}}),e.fn.extend({scrollParent:function(t){var i=this.css("position"),s="absolute"===i,n=t?/(auto|scroll|hidden)/:/(auto|scroll)/,a=this.parents().filter(function(){var t=e(this);return s&&"static"===t.css("position")?!1:n.test(t.css("overflow")+t.css("overflow-y")+t.css("overflow-x"))}).eq(0);return"fixed"!==i&&a.length?a:e(this[0].ownerDocument||document)},uniqueId:function(){var e=0;return function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++e)})}}(),removeUniqueId:function(){return this.each(function(){/^ui-id-\d+$/.test(this.id)&&e(this).removeAttr("id")})}}),e.extend(e.expr[":"],{data:e.expr.createPseudo?e.expr.createPseudo(function(t){return function(i){return!!e.data(i,t)}}):function(t,i,s){return!!e.data(t,s[3])},focusable:function(i){return t(i,!isNaN(e.attr(i,"tabindex")))},tabbable:function(i){var s=e.attr(i,"tabindex"),n=isNaN(s);return(n||s>=0)&&t(i,!n)}}),e("").outerWidth(1).jquery||e.each(["Width","Height"],function(t,i){function s(t,i,s,a){return e.each(n,function(){i-=parseFloat(e.css(t,"padding"+this))||0,s&&(i-=parseFloat(e.css(t,"border"+this+"Width"))||0),a&&(i-=parseFloat(e.css(t,"margin"+this))||0)}),i}var n="Width"===i?["Left","Right"]:["Top","Bottom"],a=i.toLowerCase(),o={innerWidth:e.fn.innerWidth,innerHeight:e.fn.innerHeight,outerWidth:e.fn.outerWidth,outerHeight:e.fn.outerHeight};e.fn["inner"+i]=function(t){return void 0===t?o["inner"+i].call(this):this.each(function(){e(this).css(a,s(this,t)+"px")})},e.fn["outer"+i]=function(t,n){return"number"!=typeof t?o["outer"+i].call(this,t):this.each(function(){e(this).css(a,s(this,t,!0,n)+"px")})}}),e.fn.addBack||(e.fn.addBack=function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}),e("").data("a-b","a").removeData("a-b").data("a-b")&&(e.fn.removeData=function(t){return function(i){return arguments.length?t.call(this,e.camelCase(i)):t.call(this)}}(e.fn.removeData)),e.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase()),e.fn.extend({focus:function(t){return function(i,s){return"number"==typeof i?this.each(function(){var t=this;setTimeout(function(){e(t).focus(),s&&s.call(t)},i)}):t.apply(this,arguments)}}(e.fn.focus),disableSelection:function(){var e="onselectstart"in document.createElement("div")?"selectstart":"mousedown";return function(){return this.bind(e+".ui-disableSelection",function(e){e.preventDefault()})}}(),enableSelection:function(){return this.unbind(".ui-disableSelection")},zIndex:function(t){if(void 0!==t)return this.css("zIndex",t);if(this.length)for(var i,s,n=e(this[0]);n.length&&n[0]!==document;){if(i=n.css("position"),("absolute"===i||"relative"===i||"fixed"===i)&&(s=parseInt(n.css("zIndex"),10),!isNaN(s)&&0!==s))return s;n=n.parent()}return 0}}),e.ui.plugin={add:function(t,i,s){var n,a=e.ui[t].prototype;for(n in s)a.plugins[n]=a.plugins[n]||[],a.plugins[n].push([i,s[n]])},call:function(e,t,i,s){var n,a=e.plugins[t];if(a&&(s||e.element[0].parentNode&&11!==e.element[0].parentNode.nodeType))for(n=0;a.length>n;n++)e.options[a[n][0]]&&a[n][1].apply(e.element,i)}};var l=0,u=Array.prototype.slice;e.cleanData=function(t){return function(i){var s,n,a;for(a=0;null!=(n=i[a]);a++)try{s=e._data(n,"events"),s&&s.remove&&e(n).triggerHandler("remove")}catch(o){}t(i)}}(e.cleanData),e.widget=function(t,i,s){var n,a,o,r,h={},l=t.split(".")[0];return t=t.split(".")[1],n=l+"-"+t,s||(s=i,i=e.Widget),e.expr[":"][n.toLowerCase()]=function(t){return!!e.data(t,n)},e[l]=e[l]||{},a=e[l][t],o=e[l][t]=function(e,t){return this._createWidget?(arguments.length&&this._createWidget(e,t),void 0):new o(e,t)},e.extend(o,a,{version:s.version,_proto:e.extend({},s),_childConstructors:[]}),r=new i,r.options=e.widget.extend({},r.options),e.each(s,function(t,s){return e.isFunction(s)?(h[t]=function(){var e=function(){return i.prototype[t].apply(this,arguments)},n=function(e){return i.prototype[t].apply(this,e)};return function(){var t,i=this._super,a=this._superApply;return this._super=e,this._superApply=n,t=s.apply(this,arguments),this._super=i,this._superApply=a,t}}(),void 0):(h[t]=s,void 0)}),o.prototype=e.widget.extend(r,{widgetEventPrefix:a?r.widgetEventPrefix||t:t},h,{constructor:o,namespace:l,widgetName:t,widgetFullName:n}),a?(e.each(a._childConstructors,function(t,i){var s=i.prototype;e.widget(s.namespace+"."+s.widgetName,o,i._proto)}),delete a._childConstructors):i._childConstructors.push(o),e.widget.bridge(t,o),o},e.widget.extend=function(t){for(var i,s,n=u.call(arguments,1),a=0,o=n.length;o>a;a++)for(i in n[a])s=n[a][i],n[a].hasOwnProperty(i)&&void 0!==s&&(t[i]=e.isPlainObject(s)?e.isPlainObject(t[i])?e.widget.extend({},t[i],s):e.widget.extend({},s):s);return t},e.widget.bridge=function(t,i){var s=i.prototype.widgetFullName||t;e.fn[t]=function(n){var a="string"==typeof n,o=u.call(arguments,1),r=this;return n=!a&&o.length?e.widget.extend.apply(null,[n].concat(o)):n,a?this.each(function(){var i,a=e.data(this,s);return"instance"===n?(r=a,!1):a?e.isFunction(a[n])&&"_"!==n.charAt(0)?(i=a[n].apply(a,o),i!==a&&void 0!==i?(r=i&&i.jquery?r.pushStack(i.get()):i,!1):void 0):e.error("no such method '"+n+"' for "+t+" widget instance"):e.error("cannot call methods on "+t+" prior to initialization; "+"attempted to call method '"+n+"'")}):this.each(function(){var t=e.data(this,s);t?(t.option(n||{}),t._init&&t._init()):e.data(this,s,new i(n,this))}),r}},e.Widget=function(){},e.Widget._childConstructors=[],e.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"
              ",options:{disabled:!1,create:null},_createWidget:function(t,i){i=e(i||this.defaultElement||this)[0],this.element=e(i),this.uuid=l++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=e(),this.hoverable=e(),this.focusable=e(),i!==this&&(e.data(i,this.widgetFullName,this),this._on(!0,this.element,{remove:function(e){e.target===i&&this.destroy()}}),this.document=e(i.style?i.ownerDocument:i.document||i),this.window=e(this.document[0].defaultView||this.document[0].parentWindow)),this.options=e.widget.extend({},this.options,this._getCreateOptions(),t),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:e.noop,_getCreateEventData:e.noop,_create:e.noop,_init:e.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetFullName).removeData(e.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled "+"ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:e.noop,widget:function(){return this.element},option:function(t,i){var s,n,a,o=t;if(0===arguments.length)return e.widget.extend({},this.options);if("string"==typeof t)if(o={},s=t.split("."),t=s.shift(),s.length){for(n=o[t]=e.widget.extend({},this.options[t]),a=0;s.length-1>a;a++)n[s[a]]=n[s[a]]||{},n=n[s[a]];if(t=s.pop(),1===arguments.length)return void 0===n[t]?null:n[t];n[t]=i}else{if(1===arguments.length)return void 0===this.options[t]?null:this.options[t];o[t]=i}return this._setOptions(o),this},_setOptions:function(e){var t;for(t in e)this._setOption(t,e[t]);return this},_setOption:function(e,t){return this.options[e]=t,"disabled"===e&&(this.widget().toggleClass(this.widgetFullName+"-disabled",!!t),t&&(this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus"))),this},enable:function(){return this._setOptions({disabled:!1})},disable:function(){return this._setOptions({disabled:!0})},_on:function(t,i,s){var n,a=this;"boolean"!=typeof t&&(s=i,i=t,t=!1),s?(i=n=e(i),this.bindings=this.bindings.add(i)):(s=i,i=this.element,n=this.widget()),e.each(s,function(s,o){function r(){return t||a.options.disabled!==!0&&!e(this).hasClass("ui-state-disabled")?("string"==typeof o?a[o]:o).apply(a,arguments):void 0}"string"!=typeof o&&(r.guid=o.guid=o.guid||r.guid||e.guid++);var h=s.match(/^([\w:-]*)\s*(.*)$/),l=h[1]+a.eventNamespace,u=h[2];u?n.delegate(u,l,r):i.bind(l,r)})},_off:function(t,i){i=(i||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,t.unbind(i).undelegate(i),this.bindings=e(this.bindings.not(t).get()),this.focusable=e(this.focusable.not(t).get()),this.hoverable=e(this.hoverable.not(t).get())},_delay:function(e,t){function i(){return("string"==typeof e?s[e]:e).apply(s,arguments)}var s=this;return setTimeout(i,t||0)},_hoverable:function(t){this.hoverable=this.hoverable.add(t),this._on(t,{mouseenter:function(t){e(t.currentTarget).addClass("ui-state-hover")},mouseleave:function(t){e(t.currentTarget).removeClass("ui-state-hover")}})},_focusable:function(t){this.focusable=this.focusable.add(t),this._on(t,{focusin:function(t){e(t.currentTarget).addClass("ui-state-focus")},focusout:function(t){e(t.currentTarget).removeClass("ui-state-focus")}})},_trigger:function(t,i,s){var n,a,o=this.options[t];if(s=s||{},i=e.Event(i),i.type=(t===this.widgetEventPrefix?t:this.widgetEventPrefix+t).toLowerCase(),i.target=this.element[0],a=i.originalEvent)for(n in a)n in i||(i[n]=a[n]);return this.element.trigger(i,s),!(e.isFunction(o)&&o.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},e.each({show:"fadeIn",hide:"fadeOut"},function(t,i){e.Widget.prototype["_"+t]=function(s,n,a){"string"==typeof n&&(n={effect:n});var o,r=n?n===!0||"number"==typeof n?i:n.effect||i:t;n=n||{},"number"==typeof n&&(n={duration:n}),o=!e.isEmptyObject(n),n.complete=a,n.delay&&s.delay(n.delay),o&&e.effects&&e.effects.effect[r]?s[t](n):r!==t&&s[r]?s[r](n.duration,n.easing,a):s.queue(function(i){e(this)[t](),a&&a.call(s[0]),i()})}}),e.widget;var d=!1;e(document).mouseup(function(){d=!1}),e.widget("ui.mouse",{version:"1.11.2",options:{cancel:"input,textarea,button,select,option",distance:1,delay:0},_mouseInit:function(){var t=this;this.element.bind("mousedown."+this.widgetName,function(e){return t._mouseDown(e)}).bind("click."+this.widgetName,function(i){return!0===e.data(i.target,t.widgetName+".preventClickEvent")?(e.removeData(i.target,t.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):void 0}),this.started=!1},_mouseDestroy:function(){this.element.unbind("."+this.widgetName),this._mouseMoveDelegate&&this.document.unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(t){if(!d){this._mouseMoved=!1,this._mouseStarted&&this._mouseUp(t),this._mouseDownEvent=t;var i=this,s=1===t.which,n="string"==typeof this.options.cancel&&t.target.nodeName?e(t.target).closest(this.options.cancel).length:!1;return s&&!n&&this._mouseCapture(t)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){i.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(t)&&this._mouseDelayMet(t)&&(this._mouseStarted=this._mouseStart(t)!==!1,!this._mouseStarted)?(t.preventDefault(),!0):(!0===e.data(t.target,this.widgetName+".preventClickEvent")&&e.removeData(t.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(e){return i._mouseMove(e)},this._mouseUpDelegate=function(e){return i._mouseUp(e)},this.document.bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate),t.preventDefault(),d=!0,!0)):!0}},_mouseMove:function(t){if(this._mouseMoved){if(e.ui.ie&&(!document.documentMode||9>document.documentMode)&&!t.button)return this._mouseUp(t);if(!t.which)return this._mouseUp(t)}return(t.which||t.button)&&(this._mouseMoved=!0),this._mouseStarted?(this._mouseDrag(t),t.preventDefault()):(this._mouseDistanceMet(t)&&this._mouseDelayMet(t)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,t)!==!1,this._mouseStarted?this._mouseDrag(t):this._mouseUp(t)),!this._mouseStarted)},_mouseUp:function(t){return this.document.unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,t.target===this._mouseDownEvent.target&&e.data(t.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(t)),d=!1,!1},_mouseDistanceMet:function(e){return Math.max(Math.abs(this._mouseDownEvent.pageX-e.pageX),Math.abs(this._mouseDownEvent.pageY-e.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}}),function(){function t(e,t,i){return[parseFloat(e[0])*(p.test(e[0])?t/100:1),parseFloat(e[1])*(p.test(e[1])?i/100:1)]}function i(t,i){return parseInt(e.css(t,i),10)||0}function s(t){var i=t[0];return 9===i.nodeType?{width:t.width(),height:t.height(),offset:{top:0,left:0}}:e.isWindow(i)?{width:t.width(),height:t.height(),offset:{top:t.scrollTop(),left:t.scrollLeft()}}:i.preventDefault?{width:0,height:0,offset:{top:i.pageY,left:i.pageX}}:{width:t.outerWidth(),height:t.outerHeight(),offset:t.offset()}}e.ui=e.ui||{};var n,a,o=Math.max,r=Math.abs,h=Math.round,l=/left|center|right/,u=/top|center|bottom/,d=/[\+\-]\d+(\.[\d]+)?%?/,c=/^\w+/,p=/%$/,f=e.fn.position;e.position={scrollbarWidth:function(){if(void 0!==n)return n;var t,i,s=e("
              "),a=s.children()[0];return e("body").append(s),t=a.offsetWidth,s.css("overflow","scroll"),i=a.offsetWidth,t===i&&(i=s[0].clientWidth),s.remove(),n=t-i},getScrollInfo:function(t){var i=t.isWindow||t.isDocument?"":t.element.css("overflow-x"),s=t.isWindow||t.isDocument?"":t.element.css("overflow-y"),n="scroll"===i||"auto"===i&&t.widthi?"left":t>0?"right":"center",vertical:0>a?"top":s>0?"bottom":"middle"};d>m&&m>r(t+i)&&(h.horizontal="center"),c>g&&g>r(s+a)&&(h.vertical="middle"),h.important=o(r(t),r(i))>o(r(s),r(a))?"horizontal":"vertical",n.using.call(this,e,h)}),u.offset(e.extend(M,{using:l}))})},e.ui.position={fit:{left:function(e,t){var i,s=t.within,n=s.isWindow?s.scrollLeft:s.offset.left,a=s.width,r=e.left-t.collisionPosition.marginLeft,h=n-r,l=r+t.collisionWidth-a-n;t.collisionWidth>a?h>0&&0>=l?(i=e.left+h+t.collisionWidth-a-n,e.left+=h-i):e.left=l>0&&0>=h?n:h>l?n+a-t.collisionWidth:n:h>0?e.left+=h:l>0?e.left-=l:e.left=o(e.left-r,e.left)},top:function(e,t){var i,s=t.within,n=s.isWindow?s.scrollTop:s.offset.top,a=t.within.height,r=e.top-t.collisionPosition.marginTop,h=n-r,l=r+t.collisionHeight-a-n;t.collisionHeight>a?h>0&&0>=l?(i=e.top+h+t.collisionHeight-a-n,e.top+=h-i):e.top=l>0&&0>=h?n:h>l?n+a-t.collisionHeight:n:h>0?e.top+=h:l>0?e.top-=l:e.top=o(e.top-r,e.top)}},flip:{left:function(e,t){var i,s,n=t.within,a=n.offset.left+n.scrollLeft,o=n.width,h=n.isWindow?n.scrollLeft:n.offset.left,l=e.left-t.collisionPosition.marginLeft,u=l-h,d=l+t.collisionWidth-o-h,c="left"===t.my[0]?-t.elemWidth:"right"===t.my[0]?t.elemWidth:0,p="left"===t.at[0]?t.targetWidth:"right"===t.at[0]?-t.targetWidth:0,f=-2*t.offset[0];0>u?(i=e.left+c+p+f+t.collisionWidth-o-a,(0>i||r(u)>i)&&(e.left+=c+p+f)):d>0&&(s=e.left-t.collisionPosition.marginLeft+c+p+f-h,(s>0||d>r(s))&&(e.left+=c+p+f))},top:function(e,t){var i,s,n=t.within,a=n.offset.top+n.scrollTop,o=n.height,h=n.isWindow?n.scrollTop:n.offset.top,l=e.top-t.collisionPosition.marginTop,u=l-h,d=l+t.collisionHeight-o-h,c="top"===t.my[1],p=c?-t.elemHeight:"bottom"===t.my[1]?t.elemHeight:0,f="top"===t.at[1]?t.targetHeight:"bottom"===t.at[1]?-t.targetHeight:0,m=-2*t.offset[1];0>u?(s=e.top+p+f+m+t.collisionHeight-o-a,e.top+p+f+m>u&&(0>s||r(u)>s)&&(e.top+=p+f+m)):d>0&&(i=e.top-t.collisionPosition.marginTop+p+f+m-h,e.top+p+f+m>d&&(i>0||d>r(i))&&(e.top+=p+f+m))}},flipfit:{left:function(){e.ui.position.flip.left.apply(this,arguments),e.ui.position.fit.left.apply(this,arguments)},top:function(){e.ui.position.flip.top.apply(this,arguments),e.ui.position.fit.top.apply(this,arguments)}}},function(){var t,i,s,n,o,r=document.getElementsByTagName("body")[0],h=document.createElement("div");t=document.createElement(r?"div":"body"),s={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},r&&e.extend(s,{position:"absolute",left:"-1000px",top:"-1000px"});for(o in s)t.style[o]=s[o];t.appendChild(h),i=r||document.documentElement,i.insertBefore(t,i.firstChild),h.style.cssText="position: absolute; left: 10.7432222px;",n=e(h).offset().left,a=n>10&&11>n,t.innerHTML="",i.removeChild(t)}()}(),e.ui.position,e.widget("ui.draggable",e.ui.mouse,{version:"1.11.2",widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1,drag:null,start:null,stop:null},_create:function(){"original"===this.options.helper&&this._setPositionRelative(),this.options.addClasses&&this.element.addClass("ui-draggable"),this.options.disabled&&this.element.addClass("ui-draggable-disabled"),this._setHandleClassName(),this._mouseInit()},_setOption:function(e,t){this._super(e,t),"handle"===e&&(this._removeHandleClassName(),this._setHandleClassName())},_destroy:function(){return(this.helper||this.element).is(".ui-draggable-dragging")?(this.destroyOnClear=!0,void 0):(this.element.removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled"),this._removeHandleClassName(),this._mouseDestroy(),void 0)},_mouseCapture:function(t){var i=this.options;return this._blurActiveElement(t),this.helper||i.disabled||e(t.target).closest(".ui-resizable-handle").length>0?!1:(this.handle=this._getHandle(t),this.handle?(this._blockFrames(i.iframeFix===!0?"iframe":i.iframeFix),!0):!1)},_blockFrames:function(t){this.iframeBlocks=this.document.find(t).map(function(){var t=e(this);return e("
              ").css("position","absolute").appendTo(t.parent()).outerWidth(t.outerWidth()).outerHeight(t.outerHeight()).offset(t.offset())[0]})},_unblockFrames:function(){this.iframeBlocks&&(this.iframeBlocks.remove(),delete this.iframeBlocks)},_blurActiveElement:function(t){var i=this.document[0];if(this.handleElement.is(t.target))try{i.activeElement&&"body"!==i.activeElement.nodeName.toLowerCase()&&e(i.activeElement).blur()}catch(s){}},_mouseStart:function(t){var i=this.options;return this.helper=this._createHelper(t),this.helper.addClass("ui-draggable-dragging"),this._cacheHelperProportions(),e.ui.ddmanager&&(e.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(!0),this.offsetParent=this.helper.offsetParent(),this.hasFixedAncestor=this.helper.parents().filter(function(){return"fixed"===e(this).css("position")}).length>0,this.positionAbs=this.element.offset(),this._refreshOffsets(t),this.originalPosition=this.position=this._generatePosition(t,!1),this.originalPageX=t.pageX,this.originalPageY=t.pageY,i.cursorAt&&this._adjustOffsetFromHelper(i.cursorAt),this._setContainment(),this._trigger("start",t)===!1?(this._clear(),!1):(this._cacheHelperProportions(),e.ui.ddmanager&&!i.dropBehaviour&&e.ui.ddmanager.prepareOffsets(this,t),this._normalizeRightBottom(),this._mouseDrag(t,!0),e.ui.ddmanager&&e.ui.ddmanager.dragStart(this,t),!0)},_refreshOffsets:function(e){this.offset={top:this.positionAbs.top-this.margins.top,left:this.positionAbs.left-this.margins.left,scroll:!1,parent:this._getParentOffset(),relative:this._getRelativeOffset()},this.offset.click={left:e.pageX-this.offset.left,top:e.pageY-this.offset.top}},_mouseDrag:function(t,i){if(this.hasFixedAncestor&&(this.offset.parent=this._getParentOffset()),this.position=this._generatePosition(t,!0),this.positionAbs=this._convertPositionTo("absolute"),!i){var s=this._uiHash();if(this._trigger("drag",t,s)===!1)return this._mouseUp({}),!1;this.position=s.position}return this.helper[0].style.left=this.position.left+"px",this.helper[0].style.top=this.position.top+"px",e.ui.ddmanager&&e.ui.ddmanager.drag(this,t),!1},_mouseStop:function(t){var i=this,s=!1;return e.ui.ddmanager&&!this.options.dropBehaviour&&(s=e.ui.ddmanager.drop(this,t)),this.dropped&&(s=this.dropped,this.dropped=!1),"invalid"===this.options.revert&&!s||"valid"===this.options.revert&&s||this.options.revert===!0||e.isFunction(this.options.revert)&&this.options.revert.call(this.element,s)?e(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){i._trigger("stop",t)!==!1&&i._clear()}):this._trigger("stop",t)!==!1&&this._clear(),!1},_mouseUp:function(t){return this._unblockFrames(),e.ui.ddmanager&&e.ui.ddmanager.dragStop(this,t),this.handleElement.is(t.target)&&this.element.focus(),e.ui.mouse.prototype._mouseUp.call(this,t)},cancel:function(){return this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear(),this},_getHandle:function(t){return this.options.handle?!!e(t.target).closest(this.element.find(this.options.handle)).length:!0},_setHandleClassName:function(){this.handleElement=this.options.handle?this.element.find(this.options.handle):this.element,this.handleElement.addClass("ui-draggable-handle")},_removeHandleClassName:function(){this.handleElement.removeClass("ui-draggable-handle")},_createHelper:function(t){var i=this.options,s=e.isFunction(i.helper),n=s?e(i.helper.apply(this.element[0],[t])):"clone"===i.helper?this.element.clone().removeAttr("id"):this.element;return n.parents("body").length||n.appendTo("parent"===i.appendTo?this.element[0].parentNode:i.appendTo),s&&n[0]===this.element[0]&&this._setPositionRelative(),n[0]===this.element[0]||/(fixed|absolute)/.test(n.css("position"))||n.css("position","absolute"),n},_setPositionRelative:function(){/^(?:r|a|f)/.test(this.element.css("position"))||(this.element[0].style.position="relative")},_adjustOffsetFromHelper:function(t){"string"==typeof t&&(t=t.split(" ")),e.isArray(t)&&(t={left:+t[0],top:+t[1]||0}),"left"in t&&(this.offset.click.left=t.left+this.margins.left),"right"in t&&(this.offset.click.left=this.helperProportions.width-t.right+this.margins.left),"top"in t&&(this.offset.click.top=t.top+this.margins.top),"bottom"in t&&(this.offset.click.top=this.helperProportions.height-t.bottom+this.margins.top)},_isRootNode:function(e){return/(html|body)/i.test(e.tagName)||e===this.document[0]},_getParentOffset:function(){var t=this.offsetParent.offset(),i=this.document[0];return"absolute"===this.cssPosition&&this.scrollParent[0]!==i&&e.contains(this.scrollParent[0],this.offsetParent[0])&&(t.left+=this.scrollParent.scrollLeft(),t.top+=this.scrollParent.scrollTop()),this._isRootNode(this.offsetParent[0])&&(t={top:0,left:0}),{top:t.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:t.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"!==this.cssPosition)return{top:0,left:0};var e=this.element.position(),t=this._isRootNode(this.scrollParent[0]);return{top:e.top-(parseInt(this.helper.css("top"),10)||0)+(t?0:this.scrollParent.scrollTop()),left:e.left-(parseInt(this.helper.css("left"),10)||0)+(t?0:this.scrollParent.scrollLeft())}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var t,i,s,n=this.options,a=this.document[0];return this.relativeContainer=null,n.containment?"window"===n.containment?(this.containment=[e(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,e(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,e(window).scrollLeft()+e(window).width()-this.helperProportions.width-this.margins.left,e(window).scrollTop()+(e(window).height()||a.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],void 0):"document"===n.containment?(this.containment=[0,0,e(a).width()-this.helperProportions.width-this.margins.left,(e(a).height()||a.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],void 0):n.containment.constructor===Array?(this.containment=n.containment,void 0):("parent"===n.containment&&(n.containment=this.helper[0].parentNode),i=e(n.containment),s=i[0],s&&(t=/(scroll|auto)/.test(i.css("overflow")),this.containment=[(parseInt(i.css("borderLeftWidth"),10)||0)+(parseInt(i.css("paddingLeft"),10)||0),(parseInt(i.css("borderTopWidth"),10)||0)+(parseInt(i.css("paddingTop"),10)||0),(t?Math.max(s.scrollWidth,s.offsetWidth):s.offsetWidth)-(parseInt(i.css("borderRightWidth"),10)||0)-(parseInt(i.css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(t?Math.max(s.scrollHeight,s.offsetHeight):s.offsetHeight)-(parseInt(i.css("borderBottomWidth"),10)||0)-(parseInt(i.css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relativeContainer=i),void 0):(this.containment=null,void 0)},_convertPositionTo:function(e,t){t||(t=this.position);var i="absolute"===e?1:-1,s=this._isRootNode(this.scrollParent[0]);return{top:t.top+this.offset.relative.top*i+this.offset.parent.top*i-("fixed"===this.cssPosition?-this.offset.scroll.top:s?0:this.offset.scroll.top)*i,left:t.left+this.offset.relative.left*i+this.offset.parent.left*i-("fixed"===this.cssPosition?-this.offset.scroll.left:s?0:this.offset.scroll.left)*i}},_generatePosition:function(e,t){var i,s,n,a,o=this.options,r=this._isRootNode(this.scrollParent[0]),h=e.pageX,l=e.pageY;return r&&this.offset.scroll||(this.offset.scroll={top:this.scrollParent.scrollTop(),left:this.scrollParent.scrollLeft()}),t&&(this.containment&&(this.relativeContainer?(s=this.relativeContainer.offset(),i=[this.containment[0]+s.left,this.containment[1]+s.top,this.containment[2]+s.left,this.containment[3]+s.top]):i=this.containment,e.pageX-this.offset.click.lefti[2]&&(h=i[2]+this.offset.click.left),e.pageY-this.offset.click.top>i[3]&&(l=i[3]+this.offset.click.top)),o.grid&&(n=o.grid[1]?this.originalPageY+Math.round((l-this.originalPageY)/o.grid[1])*o.grid[1]:this.originalPageY,l=i?n-this.offset.click.top>=i[1]||n-this.offset.click.top>i[3]?n:n-this.offset.click.top>=i[1]?n-o.grid[1]:n+o.grid[1]:n,a=o.grid[0]?this.originalPageX+Math.round((h-this.originalPageX)/o.grid[0])*o.grid[0]:this.originalPageX,h=i?a-this.offset.click.left>=i[0]||a-this.offset.click.left>i[2]?a:a-this.offset.click.left>=i[0]?a-o.grid[0]:a+o.grid[0]:a),"y"===o.axis&&(h=this.originalPageX),"x"===o.axis&&(l=this.originalPageY)),{top:l-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.offset.scroll.top:r?0:this.offset.scroll.top),left:h-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.offset.scroll.left:r?0:this.offset.scroll.left)} +},_clear:function(){this.helper.removeClass("ui-draggable-dragging"),this.helper[0]===this.element[0]||this.cancelHelperRemoval||this.helper.remove(),this.helper=null,this.cancelHelperRemoval=!1,this.destroyOnClear&&this.destroy()},_normalizeRightBottom:function(){"y"!==this.options.axis&&"auto"!==this.helper.css("right")&&(this.helper.width(this.helper.width()),this.helper.css("right","auto")),"x"!==this.options.axis&&"auto"!==this.helper.css("bottom")&&(this.helper.height(this.helper.height()),this.helper.css("bottom","auto"))},_trigger:function(t,i,s){return s=s||this._uiHash(),e.ui.plugin.call(this,t,[i,s,this],!0),/^(drag|start|stop)/.test(t)&&(this.positionAbs=this._convertPositionTo("absolute"),s.offset=this.positionAbs),e.Widget.prototype._trigger.call(this,t,i,s)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}}),e.ui.plugin.add("draggable","connectToSortable",{start:function(t,i,s){var n=e.extend({},i,{item:s.element});s.sortables=[],e(s.options.connectToSortable).each(function(){var i=e(this).sortable("instance");i&&!i.options.disabled&&(s.sortables.push(i),i.refreshPositions(),i._trigger("activate",t,n))})},stop:function(t,i,s){var n=e.extend({},i,{item:s.element});s.cancelHelperRemoval=!1,e.each(s.sortables,function(){var e=this;e.isOver?(e.isOver=0,s.cancelHelperRemoval=!0,e.cancelHelperRemoval=!1,e._storedCSS={position:e.placeholder.css("position"),top:e.placeholder.css("top"),left:e.placeholder.css("left")},e._mouseStop(t),e.options.helper=e.options._helper):(e.cancelHelperRemoval=!0,e._trigger("deactivate",t,n))})},drag:function(t,i,s){e.each(s.sortables,function(){var n=!1,a=this;a.positionAbs=s.positionAbs,a.helperProportions=s.helperProportions,a.offset.click=s.offset.click,a._intersectsWith(a.containerCache)&&(n=!0,e.each(s.sortables,function(){return this.positionAbs=s.positionAbs,this.helperProportions=s.helperProportions,this.offset.click=s.offset.click,this!==a&&this._intersectsWith(this.containerCache)&&e.contains(a.element[0],this.element[0])&&(n=!1),n})),n?(a.isOver||(a.isOver=1,a.currentItem=i.helper.appendTo(a.element).data("ui-sortable-item",!0),a.options._helper=a.options.helper,a.options.helper=function(){return i.helper[0]},t.target=a.currentItem[0],a._mouseCapture(t,!0),a._mouseStart(t,!0,!0),a.offset.click.top=s.offset.click.top,a.offset.click.left=s.offset.click.left,a.offset.parent.left-=s.offset.parent.left-a.offset.parent.left,a.offset.parent.top-=s.offset.parent.top-a.offset.parent.top,s._trigger("toSortable",t),s.dropped=a.element,e.each(s.sortables,function(){this.refreshPositions()}),s.currentItem=s.element,a.fromOutside=s),a.currentItem&&(a._mouseDrag(t),i.position=a.position)):a.isOver&&(a.isOver=0,a.cancelHelperRemoval=!0,a.options._revert=a.options.revert,a.options.revert=!1,a._trigger("out",t,a._uiHash(a)),a._mouseStop(t,!0),a.options.revert=a.options._revert,a.options.helper=a.options._helper,a.placeholder&&a.placeholder.remove(),s._refreshOffsets(t),i.position=s._generatePosition(t,!0),s._trigger("fromSortable",t),s.dropped=!1,e.each(s.sortables,function(){this.refreshPositions()}))})}}),e.ui.plugin.add("draggable","cursor",{start:function(t,i,s){var n=e("body"),a=s.options;n.css("cursor")&&(a._cursor=n.css("cursor")),n.css("cursor",a.cursor)},stop:function(t,i,s){var n=s.options;n._cursor&&e("body").css("cursor",n._cursor)}}),e.ui.plugin.add("draggable","opacity",{start:function(t,i,s){var n=e(i.helper),a=s.options;n.css("opacity")&&(a._opacity=n.css("opacity")),n.css("opacity",a.opacity)},stop:function(t,i,s){var n=s.options;n._opacity&&e(i.helper).css("opacity",n._opacity)}}),e.ui.plugin.add("draggable","scroll",{start:function(e,t,i){i.scrollParentNotHidden||(i.scrollParentNotHidden=i.helper.scrollParent(!1)),i.scrollParentNotHidden[0]!==i.document[0]&&"HTML"!==i.scrollParentNotHidden[0].tagName&&(i.overflowOffset=i.scrollParentNotHidden.offset())},drag:function(t,i,s){var n=s.options,a=!1,o=s.scrollParentNotHidden[0],r=s.document[0];o!==r&&"HTML"!==o.tagName?(n.axis&&"x"===n.axis||(s.overflowOffset.top+o.offsetHeight-t.pageY=0;c--)h=s.snapElements[c].left-s.margins.left,l=h+s.snapElements[c].width,u=s.snapElements[c].top-s.margins.top,d=u+s.snapElements[c].height,h-m>v||g>l+m||u-m>b||y>d+m||!e.contains(s.snapElements[c].item.ownerDocument,s.snapElements[c].item)?(s.snapElements[c].snapping&&s.options.snap.release&&s.options.snap.release.call(s.element,t,e.extend(s._uiHash(),{snapItem:s.snapElements[c].item})),s.snapElements[c].snapping=!1):("inner"!==f.snapMode&&(n=m>=Math.abs(u-b),a=m>=Math.abs(d-y),o=m>=Math.abs(h-v),r=m>=Math.abs(l-g),n&&(i.position.top=s._convertPositionTo("relative",{top:u-s.helperProportions.height,left:0}).top),a&&(i.position.top=s._convertPositionTo("relative",{top:d,left:0}).top),o&&(i.position.left=s._convertPositionTo("relative",{top:0,left:h-s.helperProportions.width}).left),r&&(i.position.left=s._convertPositionTo("relative",{top:0,left:l}).left)),p=n||a||o||r,"outer"!==f.snapMode&&(n=m>=Math.abs(u-y),a=m>=Math.abs(d-b),o=m>=Math.abs(h-g),r=m>=Math.abs(l-v),n&&(i.position.top=s._convertPositionTo("relative",{top:u,left:0}).top),a&&(i.position.top=s._convertPositionTo("relative",{top:d-s.helperProportions.height,left:0}).top),o&&(i.position.left=s._convertPositionTo("relative",{top:0,left:h}).left),r&&(i.position.left=s._convertPositionTo("relative",{top:0,left:l-s.helperProportions.width}).left)),!s.snapElements[c].snapping&&(n||a||o||r||p)&&s.options.snap.snap&&s.options.snap.snap.call(s.element,t,e.extend(s._uiHash(),{snapItem:s.snapElements[c].item})),s.snapElements[c].snapping=n||a||o||r||p)}}),e.ui.plugin.add("draggable","stack",{start:function(t,i,s){var n,a=s.options,o=e.makeArray(e(a.stack)).sort(function(t,i){return(parseInt(e(t).css("zIndex"),10)||0)-(parseInt(e(i).css("zIndex"),10)||0)});o.length&&(n=parseInt(e(o[0]).css("zIndex"),10)||0,e(o).each(function(t){e(this).css("zIndex",n+t)}),this.css("zIndex",n+o.length))}}),e.ui.plugin.add("draggable","zIndex",{start:function(t,i,s){var n=e(i.helper),a=s.options;n.css("zIndex")&&(a._zIndex=n.css("zIndex")),n.css("zIndex",a.zIndex)},stop:function(t,i,s){var n=s.options;n._zIndex&&e(i.helper).css("zIndex",n._zIndex)}}),e.ui.draggable,e.widget("ui.droppable",{version:"1.11.2",widgetEventPrefix:"drop",options:{accept:"*",activeClass:!1,addClasses:!0,greedy:!1,hoverClass:!1,scope:"default",tolerance:"intersect",activate:null,deactivate:null,drop:null,out:null,over:null},_create:function(){var t,i=this.options,s=i.accept;this.isover=!1,this.isout=!0,this.accept=e.isFunction(s)?s:function(e){return e.is(s)},this.proportions=function(){return arguments.length?(t=arguments[0],void 0):t?t:t={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight}},this._addToManager(i.scope),i.addClasses&&this.element.addClass("ui-droppable")},_addToManager:function(t){e.ui.ddmanager.droppables[t]=e.ui.ddmanager.droppables[t]||[],e.ui.ddmanager.droppables[t].push(this)},_splice:function(e){for(var t=0;e.length>t;t++)e[t]===this&&e.splice(t,1)},_destroy:function(){var t=e.ui.ddmanager.droppables[this.options.scope];this._splice(t),this.element.removeClass("ui-droppable ui-droppable-disabled")},_setOption:function(t,i){if("accept"===t)this.accept=e.isFunction(i)?i:function(e){return e.is(i)};else if("scope"===t){var s=e.ui.ddmanager.droppables[this.options.scope];this._splice(s),this._addToManager(i)}this._super(t,i)},_activate:function(t){var i=e.ui.ddmanager.current;this.options.activeClass&&this.element.addClass(this.options.activeClass),i&&this._trigger("activate",t,this.ui(i))},_deactivate:function(t){var i=e.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass),i&&this._trigger("deactivate",t,this.ui(i))},_over:function(t){var i=e.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this.options.hoverClass&&this.element.addClass(this.options.hoverClass),this._trigger("over",t,this.ui(i)))},_out:function(t){var i=e.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("out",t,this.ui(i)))},_drop:function(t,i){var s=i||e.ui.ddmanager.current,n=!1;return s&&(s.currentItem||s.element)[0]!==this.element[0]?(this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function(){var i=e(this).droppable("instance");return i.options.greedy&&!i.options.disabled&&i.options.scope===s.options.scope&&i.accept.call(i.element[0],s.currentItem||s.element)&&e.ui.intersect(s,e.extend(i,{offset:i.element.offset()}),i.options.tolerance,t)?(n=!0,!1):void 0}),n?!1:this.accept.call(this.element[0],s.currentItem||s.element)?(this.options.activeClass&&this.element.removeClass(this.options.activeClass),this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("drop",t,this.ui(s)),this.element):!1):!1},ui:function(e){return{draggable:e.currentItem||e.element,helper:e.helper,position:e.position,offset:e.positionAbs}}}),e.ui.intersect=function(){function e(e,t,i){return e>=t&&t+i>e}return function(t,i,s,n){if(!i.offset)return!1;var a=(t.positionAbs||t.position.absolute).left+t.margins.left,o=(t.positionAbs||t.position.absolute).top+t.margins.top,r=a+t.helperProportions.width,h=o+t.helperProportions.height,l=i.offset.left,u=i.offset.top,d=l+i.proportions().width,c=u+i.proportions().height;switch(s){case"fit":return a>=l&&d>=r&&o>=u&&c>=h;case"intersect":return a+t.helperProportions.width/2>l&&d>r-t.helperProportions.width/2&&o+t.helperProportions.height/2>u&&c>h-t.helperProportions.height/2;case"pointer":return e(n.pageY,u,i.proportions().height)&&e(n.pageX,l,i.proportions().width);case"touch":return(o>=u&&c>=o||h>=u&&c>=h||u>o&&h>c)&&(a>=l&&d>=a||r>=l&&d>=r||l>a&&r>d);default:return!1}}}(),e.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(t,i){var s,n,a=e.ui.ddmanager.droppables[t.options.scope]||[],o=i?i.type:null,r=(t.currentItem||t.element).find(":data(ui-droppable)").addBack();e:for(s=0;a.length>s;s++)if(!(a[s].options.disabled||t&&!a[s].accept.call(a[s].element[0],t.currentItem||t.element))){for(n=0;r.length>n;n++)if(r[n]===a[s].element[0]){a[s].proportions().height=0;continue e}a[s].visible="none"!==a[s].element.css("display"),a[s].visible&&("mousedown"===o&&a[s]._activate.call(a[s],i),a[s].offset=a[s].element.offset(),a[s].proportions({width:a[s].element[0].offsetWidth,height:a[s].element[0].offsetHeight}))}},drop:function(t,i){var s=!1;return e.each((e.ui.ddmanager.droppables[t.options.scope]||[]).slice(),function(){this.options&&(!this.options.disabled&&this.visible&&e.ui.intersect(t,this,this.options.tolerance,i)&&(s=this._drop.call(this,i)||s),!this.options.disabled&&this.visible&&this.accept.call(this.element[0],t.currentItem||t.element)&&(this.isout=!0,this.isover=!1,this._deactivate.call(this,i)))}),s},dragStart:function(t,i){t.element.parentsUntil("body").bind("scroll.droppable",function(){t.options.refreshPositions||e.ui.ddmanager.prepareOffsets(t,i)})},drag:function(t,i){t.options.refreshPositions&&e.ui.ddmanager.prepareOffsets(t,i),e.each(e.ui.ddmanager.droppables[t.options.scope]||[],function(){if(!this.options.disabled&&!this.greedyChild&&this.visible){var s,n,a,o=e.ui.intersect(t,this,this.options.tolerance,i),r=!o&&this.isover?"isout":o&&!this.isover?"isover":null;r&&(this.options.greedy&&(n=this.options.scope,a=this.element.parents(":data(ui-droppable)").filter(function(){return e(this).droppable("instance").options.scope===n}),a.length&&(s=e(a[0]).droppable("instance"),s.greedyChild="isover"===r)),s&&"isover"===r&&(s.isover=!1,s.isout=!0,s._out.call(s,i)),this[r]=!0,this["isout"===r?"isover":"isout"]=!1,this["isover"===r?"_over":"_out"].call(this,i),s&&"isout"===r&&(s.isout=!1,s.isover=!0,s._over.call(s,i)))}})},dragStop:function(t,i){t.element.parentsUntil("body").unbind("scroll.droppable"),t.options.refreshPositions||e.ui.ddmanager.prepareOffsets(t,i)}},e.ui.droppable,e.widget("ui.resizable",e.ui.mouse,{version:"1.11.2",widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:90,resize:null,start:null,stop:null},_num:function(e){return parseInt(e,10)||0},_isNumber:function(e){return!isNaN(parseInt(e,10))},_hasScroll:function(t,i){if("hidden"===e(t).css("overflow"))return!1;var s=i&&"left"===i?"scrollLeft":"scrollTop",n=!1;return t[s]>0?!0:(t[s]=1,n=t[s]>0,t[s]=0,n)},_create:function(){var t,i,s,n,a,o=this,r=this.options;if(this.element.addClass("ui-resizable"),e.extend(this,{_aspectRatio:!!r.aspectRatio,aspectRatio:r.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:r.helper||r.ghost||r.animate?r.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)&&(this.element.wrap(e("
              ").css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("ui-resizable",this.element.resizable("instance")),this.elementIsWrapper=!0,this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")}),this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0}),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css({margin:this.originalElement.css("margin")}),this._proportionallyResize()),this.handles=r.handles||(e(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se"),this.handles.constructor===String)for("all"===this.handles&&(this.handles="n,e,s,w,se,sw,ne,nw"),t=this.handles.split(","),this.handles={},i=0;t.length>i;i++)s=e.trim(t[i]),a="ui-resizable-"+s,n=e("
              "),n.css({zIndex:r.zIndex}),"se"===s&&n.addClass("ui-icon ui-icon-gripsmall-diagonal-se"),this.handles[s]=".ui-resizable-"+s,this.element.append(n);this._renderAxis=function(t){var i,s,n,a;t=t||this.element;for(i in this.handles)this.handles[i].constructor===String&&(this.handles[i]=this.element.children(this.handles[i]).first().show()),this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)&&(s=e(this.handles[i],this.element),a=/sw|ne|nw|se|n|s/.test(i)?s.outerHeight():s.outerWidth(),n=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join(""),t.css(n,a),this._proportionallyResize()),e(this.handles[i]).length},this._renderAxis(this.element),this._handles=e(".ui-resizable-handle",this.element).disableSelection(),this._handles.mouseover(function(){o.resizing||(this.className&&(n=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)),o.axis=n&&n[1]?n[1]:"se")}),r.autoHide&&(this._handles.hide(),e(this.element).addClass("ui-resizable-autohide").mouseenter(function(){r.disabled||(e(this).removeClass("ui-resizable-autohide"),o._handles.show())}).mouseleave(function(){r.disabled||o.resizing||(e(this).addClass("ui-resizable-autohide"),o._handles.hide())})),this._mouseInit()},_destroy:function(){this._mouseDestroy();var t,i=function(t){e(t).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};return this.elementIsWrapper&&(i(this.element),t=this.element,this.originalElement.css({position:t.css("position"),width:t.outerWidth(),height:t.outerHeight(),top:t.css("top"),left:t.css("left")}).insertAfter(t),t.remove()),this.originalElement.css("resize",this.originalResizeStyle),i(this.originalElement),this},_mouseCapture:function(t){var i,s,n=!1;for(i in this.handles)s=e(this.handles[i])[0],(s===t.target||e.contains(s,t.target))&&(n=!0);return!this.options.disabled&&n},_mouseStart:function(t){var i,s,n,a=this.options,o=this.element;return this.resizing=!0,this._renderProxy(),i=this._num(this.helper.css("left")),s=this._num(this.helper.css("top")),a.containment&&(i+=e(a.containment).scrollLeft()||0,s+=e(a.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:i,top:s},this.size=this._helper?{width:this.helper.width(),height:this.helper.height()}:{width:o.width(),height:o.height()},this.originalSize=this._helper?{width:o.outerWidth(),height:o.outerHeight()}:{width:o.width(),height:o.height()},this.sizeDiff={width:o.outerWidth()-o.width(),height:o.outerHeight()-o.height()},this.originalPosition={left:i,top:s},this.originalMousePosition={left:t.pageX,top:t.pageY},this.aspectRatio="number"==typeof a.aspectRatio?a.aspectRatio:this.originalSize.width/this.originalSize.height||1,n=e(".ui-resizable-"+this.axis).css("cursor"),e("body").css("cursor","auto"===n?this.axis+"-resize":n),o.addClass("ui-resizable-resizing"),this._propagate("start",t),!0},_mouseDrag:function(t){var i,s,n=this.originalMousePosition,a=this.axis,o=t.pageX-n.left||0,r=t.pageY-n.top||0,h=this._change[a];return this._updatePrevProperties(),h?(i=h.apply(this,[t,o,r]),this._updateVirtualBoundaries(t.shiftKey),(this._aspectRatio||t.shiftKey)&&(i=this._updateRatio(i,t)),i=this._respectSize(i,t),this._updateCache(i),this._propagate("resize",t),s=this._applyChanges(),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),e.isEmptyObject(s)||(this._updatePrevProperties(),this._trigger("resize",t,this.ui()),this._applyChanges()),!1):!1},_mouseStop:function(t){this.resizing=!1;var i,s,n,a,o,r,h,l=this.options,u=this;return this._helper&&(i=this._proportionallyResizeElements,s=i.length&&/textarea/i.test(i[0].nodeName),n=s&&this._hasScroll(i[0],"left")?0:u.sizeDiff.height,a=s?0:u.sizeDiff.width,o={width:u.helper.width()-a,height:u.helper.height()-n},r=parseInt(u.element.css("left"),10)+(u.position.left-u.originalPosition.left)||null,h=parseInt(u.element.css("top"),10)+(u.position.top-u.originalPosition.top)||null,l.animate||this.element.css(e.extend(o,{top:h,left:r})),u.helper.height(u.size.height),u.helper.width(u.size.width),this._helper&&!l.animate&&this._proportionallyResize()),e("body").css("cursor","auto"),this.element.removeClass("ui-resizable-resizing"),this._propagate("stop",t),this._helper&&this.helper.remove(),!1},_updatePrevProperties:function(){this.prevPosition={top:this.position.top,left:this.position.left},this.prevSize={width:this.size.width,height:this.size.height}},_applyChanges:function(){var e={};return this.position.top!==this.prevPosition.top&&(e.top=this.position.top+"px"),this.position.left!==this.prevPosition.left&&(e.left=this.position.left+"px"),this.size.width!==this.prevSize.width&&(e.width=this.size.width+"px"),this.size.height!==this.prevSize.height&&(e.height=this.size.height+"px"),this.helper.css(e),e},_updateVirtualBoundaries:function(e){var t,i,s,n,a,o=this.options;a={minWidth:this._isNumber(o.minWidth)?o.minWidth:0,maxWidth:this._isNumber(o.maxWidth)?o.maxWidth:1/0,minHeight:this._isNumber(o.minHeight)?o.minHeight:0,maxHeight:this._isNumber(o.maxHeight)?o.maxHeight:1/0},(this._aspectRatio||e)&&(t=a.minHeight*this.aspectRatio,s=a.minWidth/this.aspectRatio,i=a.maxHeight*this.aspectRatio,n=a.maxWidth/this.aspectRatio,t>a.minWidth&&(a.minWidth=t),s>a.minHeight&&(a.minHeight=s),a.maxWidth>i&&(a.maxWidth=i),a.maxHeight>n&&(a.maxHeight=n)),this._vBoundaries=a},_updateCache:function(e){this.offset=this.helper.offset(),this._isNumber(e.left)&&(this.position.left=e.left),this._isNumber(e.top)&&(this.position.top=e.top),this._isNumber(e.height)&&(this.size.height=e.height),this._isNumber(e.width)&&(this.size.width=e.width)},_updateRatio:function(e){var t=this.position,i=this.size,s=this.axis;return this._isNumber(e.height)?e.width=e.height*this.aspectRatio:this._isNumber(e.width)&&(e.height=e.width/this.aspectRatio),"sw"===s&&(e.left=t.left+(i.width-e.width),e.top=null),"nw"===s&&(e.top=t.top+(i.height-e.height),e.left=t.left+(i.width-e.width)),e},_respectSize:function(e){var t=this._vBoundaries,i=this.axis,s=this._isNumber(e.width)&&t.maxWidth&&t.maxWidthe.width,o=this._isNumber(e.height)&&t.minHeight&&t.minHeight>e.height,r=this.originalPosition.left+this.originalSize.width,h=this.position.top+this.size.height,l=/sw|nw|w/.test(i),u=/nw|ne|n/.test(i);return a&&(e.width=t.minWidth),o&&(e.height=t.minHeight),s&&(e.width=t.maxWidth),n&&(e.height=t.maxHeight),a&&l&&(e.left=r-t.minWidth),s&&l&&(e.left=r-t.maxWidth),o&&u&&(e.top=h-t.minHeight),n&&u&&(e.top=h-t.maxHeight),e.width||e.height||e.left||!e.top?e.width||e.height||e.top||!e.left||(e.left=null):e.top=null,e},_getPaddingPlusBorderDimensions:function(e){for(var t=0,i=[],s=[e.css("borderTopWidth"),e.css("borderRightWidth"),e.css("borderBottomWidth"),e.css("borderLeftWidth")],n=[e.css("paddingTop"),e.css("paddingRight"),e.css("paddingBottom"),e.css("paddingLeft")];4>t;t++)i[t]=parseInt(s[t],10)||0,i[t]+=parseInt(n[t],10)||0;return{height:i[0]+i[2],width:i[1]+i[3]}},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var e,t=0,i=this.helper||this.element;this._proportionallyResizeElements.length>t;t++)e=this._proportionallyResizeElements[t],this.outerDimensions||(this.outerDimensions=this._getPaddingPlusBorderDimensions(e)),e.css({height:i.height()-this.outerDimensions.height||0,width:i.width()-this.outerDimensions.width||0})},_renderProxy:function(){var t=this.element,i=this.options;this.elementOffset=t.offset(),this._helper?(this.helper=this.helper||e("
              "),this.helper.addClass(this._helper).css({width:this.element.outerWidth()-1,height:this.element.outerHeight()-1,position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++i.zIndex}),this.helper.appendTo("body").disableSelection()):this.helper=this.element},_change:{e:function(e,t){return{width:this.originalSize.width+t}},w:function(e,t){var i=this.originalSize,s=this.originalPosition;return{left:s.left+t,width:i.width-t}},n:function(e,t,i){var s=this.originalSize,n=this.originalPosition;return{top:n.top+i,height:s.height-i}},s:function(e,t,i){return{height:this.originalSize.height+i}},se:function(t,i,s){return e.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[t,i,s]))},sw:function(t,i,s){return e.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[t,i,s]))},ne:function(t,i,s){return e.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[t,i,s]))},nw:function(t,i,s){return e.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[t,i,s]))}},_propagate:function(t,i){e.ui.plugin.call(this,t,[i,this.ui()]),"resize"!==t&&this._trigger(t,i,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),e.ui.plugin.add("resizable","animate",{stop:function(t){var i=e(this).resizable("instance"),s=i.options,n=i._proportionallyResizeElements,a=n.length&&/textarea/i.test(n[0].nodeName),o=a&&i._hasScroll(n[0],"left")?0:i.sizeDiff.height,r=a?0:i.sizeDiff.width,h={width:i.size.width-r,height:i.size.height-o},l=parseInt(i.element.css("left"),10)+(i.position.left-i.originalPosition.left)||null,u=parseInt(i.element.css("top"),10)+(i.position.top-i.originalPosition.top)||null;i.element.animate(e.extend(h,u&&l?{top:u,left:l}:{}),{duration:s.animateDuration,easing:s.animateEasing,step:function(){var s={width:parseInt(i.element.css("width"),10),height:parseInt(i.element.css("height"),10),top:parseInt(i.element.css("top"),10),left:parseInt(i.element.css("left"),10)};n&&n.length&&e(n[0]).css({width:s.width,height:s.height}),i._updateCache(s),i._propagate("resize",t)}})}}),e.ui.plugin.add("resizable","containment",{start:function(){var t,i,s,n,a,o,r,h=e(this).resizable("instance"),l=h.options,u=h.element,d=l.containment,c=d instanceof e?d.get(0):/parent/.test(d)?u.parent().get(0):d;c&&(h.containerElement=e(c),/document/.test(d)||d===document?(h.containerOffset={left:0,top:0},h.containerPosition={left:0,top:0},h.parentData={element:e(document),left:0,top:0,width:e(document).width(),height:e(document).height()||document.body.parentNode.scrollHeight}):(t=e(c),i=[],e(["Top","Right","Left","Bottom"]).each(function(e,s){i[e]=h._num(t.css("padding"+s))}),h.containerOffset=t.offset(),h.containerPosition=t.position(),h.containerSize={height:t.innerHeight()-i[3],width:t.innerWidth()-i[1]},s=h.containerOffset,n=h.containerSize.height,a=h.containerSize.width,o=h._hasScroll(c,"left")?c.scrollWidth:a,r=h._hasScroll(c)?c.scrollHeight:n,h.parentData={element:c,left:s.left,top:s.top,width:o,height:r}))},resize:function(t){var i,s,n,a,o=e(this).resizable("instance"),r=o.options,h=o.containerOffset,l=o.position,u=o._aspectRatio||t.shiftKey,d={top:0,left:0},c=o.containerElement,p=!0;c[0]!==document&&/static/.test(c.css("position"))&&(d=h),l.left<(o._helper?h.left:0)&&(o.size.width=o.size.width+(o._helper?o.position.left-h.left:o.position.left-d.left),u&&(o.size.height=o.size.width/o.aspectRatio,p=!1),o.position.left=r.helper?h.left:0),l.top<(o._helper?h.top:0)&&(o.size.height=o.size.height+(o._helper?o.position.top-h.top:o.position.top),u&&(o.size.width=o.size.height*o.aspectRatio,p=!1),o.position.top=o._helper?h.top:0),n=o.containerElement.get(0)===o.element.parent().get(0),a=/relative|absolute/.test(o.containerElement.css("position")),n&&a?(o.offset.left=o.parentData.left+o.position.left,o.offset.top=o.parentData.top+o.position.top):(o.offset.left=o.element.offset().left,o.offset.top=o.element.offset().top),i=Math.abs(o.sizeDiff.width+(o._helper?o.offset.left-d.left:o.offset.left-h.left)),s=Math.abs(o.sizeDiff.height+(o._helper?o.offset.top-d.top:o.offset.top-h.top)),i+o.size.width>=o.parentData.width&&(o.size.width=o.parentData.width-i,u&&(o.size.height=o.size.width/o.aspectRatio,p=!1)),s+o.size.height>=o.parentData.height&&(o.size.height=o.parentData.height-s,u&&(o.size.width=o.size.height*o.aspectRatio,p=!1)),p||(o.position.left=o.prevPosition.left,o.position.top=o.prevPosition.top,o.size.width=o.prevSize.width,o.size.height=o.prevSize.height)},stop:function(){var t=e(this).resizable("instance"),i=t.options,s=t.containerOffset,n=t.containerPosition,a=t.containerElement,o=e(t.helper),r=o.offset(),h=o.outerWidth()-t.sizeDiff.width,l=o.outerHeight()-t.sizeDiff.height;t._helper&&!i.animate&&/relative/.test(a.css("position"))&&e(this).css({left:r.left-n.left-s.left,width:h,height:l}),t._helper&&!i.animate&&/static/.test(a.css("position"))&&e(this).css({left:r.left-n.left-s.left,width:h,height:l})}}),e.ui.plugin.add("resizable","alsoResize",{start:function(){var t=e(this).resizable("instance"),i=t.options,s=function(t){e(t).each(function(){var t=e(this);t.data("ui-resizable-alsoresize",{width:parseInt(t.width(),10),height:parseInt(t.height(),10),left:parseInt(t.css("left"),10),top:parseInt(t.css("top"),10)})})};"object"!=typeof i.alsoResize||i.alsoResize.parentNode?s(i.alsoResize):i.alsoResize.length?(i.alsoResize=i.alsoResize[0],s(i.alsoResize)):e.each(i.alsoResize,function(e){s(e)})},resize:function(t,i){var s=e(this).resizable("instance"),n=s.options,a=s.originalSize,o=s.originalPosition,r={height:s.size.height-a.height||0,width:s.size.width-a.width||0,top:s.position.top-o.top||0,left:s.position.left-o.left||0},h=function(t,s){e(t).each(function(){var t=e(this),n=e(this).data("ui-resizable-alsoresize"),a={},o=s&&s.length?s:t.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];e.each(o,function(e,t){var i=(n[t]||0)+(r[t]||0);i&&i>=0&&(a[t]=i||null)}),t.css(a)})};"object"!=typeof n.alsoResize||n.alsoResize.nodeType?h(n.alsoResize):e.each(n.alsoResize,function(e,t){h(e,t)})},stop:function(){e(this).removeData("resizable-alsoresize")}}),e.ui.plugin.add("resizable","ghost",{start:function(){var t=e(this).resizable("instance"),i=t.options,s=t.size;t.ghost=t.originalElement.clone(),t.ghost.css({opacity:.25,display:"block",position:"relative",height:s.height,width:s.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass("string"==typeof i.ghost?i.ghost:""),t.ghost.appendTo(t.helper)},resize:function(){var t=e(this).resizable("instance");t.ghost&&t.ghost.css({position:"relative",height:t.size.height,width:t.size.width})},stop:function(){var t=e(this).resizable("instance");t.ghost&&t.helper&&t.helper.get(0).removeChild(t.ghost.get(0))}}),e.ui.plugin.add("resizable","grid",{resize:function(){var t,i=e(this).resizable("instance"),s=i.options,n=i.size,a=i.originalSize,o=i.originalPosition,r=i.axis,h="number"==typeof s.grid?[s.grid,s.grid]:s.grid,l=h[0]||1,u=h[1]||1,d=Math.round((n.width-a.width)/l)*l,c=Math.round((n.height-a.height)/u)*u,p=a.width+d,f=a.height+c,m=s.maxWidth&&p>s.maxWidth,g=s.maxHeight&&f>s.maxHeight,v=s.minWidth&&s.minWidth>p,y=s.minHeight&&s.minHeight>f;s.grid=h,v&&(p+=l),y&&(f+=u),m&&(p-=l),g&&(f-=u),/^(se|s|e)$/.test(r)?(i.size.width=p,i.size.height=f):/^(ne)$/.test(r)?(i.size.width=p,i.size.height=f,i.position.top=o.top-c):/^(sw)$/.test(r)?(i.size.width=p,i.size.height=f,i.position.left=o.left-d):((0>=f-u||0>=p-l)&&(t=i._getPaddingPlusBorderDimensions(this)),f-u>0?(i.size.height=f,i.position.top=o.top-c):(f=u-t.height,i.size.height=f,i.position.top=o.top+a.height-f),p-l>0?(i.size.width=p,i.position.left=o.left-d):(p=u-t.height,i.size.width=p,i.position.left=o.left+a.width-p))}}),e.ui.resizable,e.widget("ui.selectable",e.ui.mouse,{version:"1.11.2",options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch",selected:null,selecting:null,start:null,stop:null,unselected:null,unselecting:null},_create:function(){var t,i=this; +this.element.addClass("ui-selectable"),this.dragged=!1,this.refresh=function(){t=e(i.options.filter,i.element[0]),t.addClass("ui-selectee"),t.each(function(){var t=e(this),i=t.offset();e.data(this,"selectable-item",{element:this,$element:t,left:i.left,top:i.top,right:i.left+t.outerWidth(),bottom:i.top+t.outerHeight(),startselected:!1,selected:t.hasClass("ui-selected"),selecting:t.hasClass("ui-selecting"),unselecting:t.hasClass("ui-unselecting")})})},this.refresh(),this.selectees=t.addClass("ui-selectee"),this._mouseInit(),this.helper=e("
              ")},_destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item"),this.element.removeClass("ui-selectable ui-selectable-disabled"),this._mouseDestroy()},_mouseStart:function(t){var i=this,s=this.options;this.opos=[t.pageX,t.pageY],this.options.disabled||(this.selectees=e(s.filter,this.element[0]),this._trigger("start",t),e(s.appendTo).append(this.helper),this.helper.css({left:t.pageX,top:t.pageY,width:0,height:0}),s.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var s=e.data(this,"selectable-item");s.startselected=!0,t.metaKey||t.ctrlKey||(s.$element.removeClass("ui-selected"),s.selected=!1,s.$element.addClass("ui-unselecting"),s.unselecting=!0,i._trigger("unselecting",t,{unselecting:s.element}))}),e(t.target).parents().addBack().each(function(){var s,n=e.data(this,"selectable-item");return n?(s=!t.metaKey&&!t.ctrlKey||!n.$element.hasClass("ui-selected"),n.$element.removeClass(s?"ui-unselecting":"ui-selected").addClass(s?"ui-selecting":"ui-unselecting"),n.unselecting=!s,n.selecting=s,n.selected=s,s?i._trigger("selecting",t,{selecting:n.element}):i._trigger("unselecting",t,{unselecting:n.element}),!1):void 0}))},_mouseDrag:function(t){if(this.dragged=!0,!this.options.disabled){var i,s=this,n=this.options,a=this.opos[0],o=this.opos[1],r=t.pageX,h=t.pageY;return a>r&&(i=r,r=a,a=i),o>h&&(i=h,h=o,o=i),this.helper.css({left:a,top:o,width:r-a,height:h-o}),this.selectees.each(function(){var i=e.data(this,"selectable-item"),l=!1;i&&i.element!==s.element[0]&&("touch"===n.tolerance?l=!(i.left>r||a>i.right||i.top>h||o>i.bottom):"fit"===n.tolerance&&(l=i.left>a&&r>i.right&&i.top>o&&h>i.bottom),l?(i.selected&&(i.$element.removeClass("ui-selected"),i.selected=!1),i.unselecting&&(i.$element.removeClass("ui-unselecting"),i.unselecting=!1),i.selecting||(i.$element.addClass("ui-selecting"),i.selecting=!0,s._trigger("selecting",t,{selecting:i.element}))):(i.selecting&&((t.metaKey||t.ctrlKey)&&i.startselected?(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.$element.addClass("ui-selected"),i.selected=!0):(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.startselected&&(i.$element.addClass("ui-unselecting"),i.unselecting=!0),s._trigger("unselecting",t,{unselecting:i.element}))),i.selected&&(t.metaKey||t.ctrlKey||i.startselected||(i.$element.removeClass("ui-selected"),i.selected=!1,i.$element.addClass("ui-unselecting"),i.unselecting=!0,s._trigger("unselecting",t,{unselecting:i.element})))))}),!1}},_mouseStop:function(t){var i=this;return this.dragged=!1,e(".ui-unselecting",this.element[0]).each(function(){var s=e.data(this,"selectable-item");s.$element.removeClass("ui-unselecting"),s.unselecting=!1,s.startselected=!1,i._trigger("unselected",t,{unselected:s.element})}),e(".ui-selecting",this.element[0]).each(function(){var s=e.data(this,"selectable-item");s.$element.removeClass("ui-selecting").addClass("ui-selected"),s.selecting=!1,s.selected=!0,s.startselected=!0,i._trigger("selected",t,{selected:s.element})}),this._trigger("stop",t),this.helper.remove(),!1}}),e.widget("ui.sortable",e.ui.mouse,{version:"1.11.2",widgetEventPrefix:"sort",ready:!1,options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3,activate:null,beforeStop:null,change:null,deactivate:null,out:null,over:null,receive:null,remove:null,sort:null,start:null,stop:null,update:null},_isOverAxis:function(e,t,i){return e>=t&&t+i>e},_isFloating:function(e){return/left|right/.test(e.css("float"))||/inline|table-cell/.test(e.css("display"))},_create:function(){var e=this.options;this.containerCache={},this.element.addClass("ui-sortable"),this.refresh(),this.floating=this.items.length?"x"===e.axis||this._isFloating(this.items[0].item):!1,this.offset=this.element.offset(),this._mouseInit(),this._setHandleClassName(),this.ready=!0},_setOption:function(e,t){this._super(e,t),"handle"===e&&this._setHandleClassName()},_setHandleClassName:function(){this.element.find(".ui-sortable-handle").removeClass("ui-sortable-handle"),e.each(this.items,function(){(this.instance.options.handle?this.item.find(this.instance.options.handle):this.item).addClass("ui-sortable-handle")})},_destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled").find(".ui-sortable-handle").removeClass("ui-sortable-handle"),this._mouseDestroy();for(var e=this.items.length-1;e>=0;e--)this.items[e].item.removeData(this.widgetName+"-item");return this},_mouseCapture:function(t,i){var s=null,n=!1,a=this;return this.reverting?!1:this.options.disabled||"static"===this.options.type?!1:(this._refreshItems(t),e(t.target).parents().each(function(){return e.data(this,a.widgetName+"-item")===a?(s=e(this),!1):void 0}),e.data(t.target,a.widgetName+"-item")===a&&(s=e(t.target)),s?!this.options.handle||i||(e(this.options.handle,s).find("*").addBack().each(function(){this===t.target&&(n=!0)}),n)?(this.currentItem=s,this._removeCurrentsFromItems(),!0):!1:!1)},_mouseStart:function(t,i,s){var n,a,o=this.options;if(this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(t),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},e.extend(this.offset,{click:{left:t.pageX-this.offset.left,top:t.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),this.originalPosition=this._generatePosition(t),this.originalPageX=t.pageX,this.originalPageY=t.pageY,o.cursorAt&&this._adjustOffsetFromHelper(o.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!==this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),o.containment&&this._setContainment(),o.cursor&&"auto"!==o.cursor&&(a=this.document.find("body"),this.storedCursor=a.css("cursor"),a.css("cursor",o.cursor),this.storedStylesheet=e("").appendTo(a)),o.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",o.opacity)),o.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",o.zIndex)),this.scrollParent[0]!==document&&"HTML"!==this.scrollParent[0].tagName&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",t,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions(),!s)for(n=this.containers.length-1;n>=0;n--)this.containers[n]._trigger("activate",t,this._uiHash(this));return e.ui.ddmanager&&(e.ui.ddmanager.current=this),e.ui.ddmanager&&!o.dropBehaviour&&e.ui.ddmanager.prepareOffsets(this,t),this.dragging=!0,this.helper.addClass("ui-sortable-helper"),this._mouseDrag(t),!0},_mouseDrag:function(t){var i,s,n,a,o=this.options,r=!1;for(this.position=this._generatePosition(t),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs),this.options.scroll&&(this.scrollParent[0]!==document&&"HTML"!==this.scrollParent[0].tagName?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-t.pageY=0;i--)if(s=this.items[i],n=s.item[0],a=this._intersectsWithPointer(s),a&&s.instance===this.currentContainer&&n!==this.currentItem[0]&&this.placeholder[1===a?"next":"prev"]()[0]!==n&&!e.contains(this.placeholder[0],n)&&("semi-dynamic"===this.options.type?!e.contains(this.element[0],n):!0)){if(this.direction=1===a?"down":"up","pointer"!==this.options.tolerance&&!this._intersectsWithSides(s))break;this._rearrange(t,s),this._trigger("change",t,this._uiHash());break}return this._contactContainers(t),e.ui.ddmanager&&e.ui.ddmanager.drag(this,t),this._trigger("sort",t,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseStop:function(t,i){if(t){if(e.ui.ddmanager&&!this.options.dropBehaviour&&e.ui.ddmanager.drop(this,t),this.options.revert){var s=this,n=this.placeholder.offset(),a=this.options.axis,o={};a&&"x"!==a||(o.left=n.left-this.offset.parent.left-this.margins.left+(this.offsetParent[0]===document.body?0:this.offsetParent[0].scrollLeft)),a&&"y"!==a||(o.top=n.top-this.offset.parent.top-this.margins.top+(this.offsetParent[0]===document.body?0:this.offsetParent[0].scrollTop)),this.reverting=!0,e(this.helper).animate(o,parseInt(this.options.revert,10)||500,function(){s._clear(t)})}else this._clear(t,i);return!1}},cancel:function(){if(this.dragging){this._mouseUp({target:null}),"original"===this.options.helper?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var t=this.containers.length-1;t>=0;t--)this.containers[t]._trigger("deactivate",null,this._uiHash(this)),this.containers[t].containerCache.over&&(this.containers[t]._trigger("out",null,this._uiHash(this)),this.containers[t].containerCache.over=0)}return this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),"original"!==this.options.helper&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),e.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?e(this.domPosition.prev).after(this.currentItem):e(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(t){var i=this._getItemsAsjQuery(t&&t.connected),s=[];return t=t||{},e(i).each(function(){var i=(e(t.item||this).attr(t.attribute||"id")||"").match(t.expression||/(.+)[\-=_](.+)/);i&&s.push((t.key||i[1]+"[]")+"="+(t.key&&t.expression?i[1]:i[2]))}),!s.length&&t.key&&s.push(t.key+"="),s.join("&")},toArray:function(t){var i=this._getItemsAsjQuery(t&&t.connected),s=[];return t=t||{},i.each(function(){s.push(e(t.item||this).attr(t.attribute||"id")||"")}),s},_intersectsWith:function(e){var t=this.positionAbs.left,i=t+this.helperProportions.width,s=this.positionAbs.top,n=s+this.helperProportions.height,a=e.left,o=a+e.width,r=e.top,h=r+e.height,l=this.offset.click.top,u=this.offset.click.left,d="x"===this.options.axis||s+l>r&&h>s+l,c="y"===this.options.axis||t+u>a&&o>t+u,p=d&&c;return"pointer"===this.options.tolerance||this.options.forcePointerForContainers||"pointer"!==this.options.tolerance&&this.helperProportions[this.floating?"width":"height"]>e[this.floating?"width":"height"]?p:t+this.helperProportions.width/2>a&&o>i-this.helperProportions.width/2&&s+this.helperProportions.height/2>r&&h>n-this.helperProportions.height/2},_intersectsWithPointer:function(e){var t="x"===this.options.axis||this._isOverAxis(this.positionAbs.top+this.offset.click.top,e.top,e.height),i="y"===this.options.axis||this._isOverAxis(this.positionAbs.left+this.offset.click.left,e.left,e.width),s=t&&i,n=this._getDragVerticalDirection(),a=this._getDragHorizontalDirection();return s?this.floating?a&&"right"===a||"down"===n?2:1:n&&("down"===n?2:1):!1},_intersectsWithSides:function(e){var t=this._isOverAxis(this.positionAbs.top+this.offset.click.top,e.top+e.height/2,e.height),i=this._isOverAxis(this.positionAbs.left+this.offset.click.left,e.left+e.width/2,e.width),s=this._getDragVerticalDirection(),n=this._getDragHorizontalDirection();return this.floating&&n?"right"===n&&i||"left"===n&&!i:s&&("down"===s&&t||"up"===s&&!t)},_getDragVerticalDirection:function(){var e=this.positionAbs.top-this.lastPositionAbs.top;return 0!==e&&(e>0?"down":"up")},_getDragHorizontalDirection:function(){var e=this.positionAbs.left-this.lastPositionAbs.left;return 0!==e&&(e>0?"right":"left")},refresh:function(e){return this._refreshItems(e),this._setHandleClassName(),this.refreshPositions(),this},_connectWith:function(){var e=this.options;return e.connectWith.constructor===String?[e.connectWith]:e.connectWith},_getItemsAsjQuery:function(t){function i(){r.push(this)}var s,n,a,o,r=[],h=[],l=this._connectWith();if(l&&t)for(s=l.length-1;s>=0;s--)for(a=e(l[s]),n=a.length-1;n>=0;n--)o=e.data(a[n],this.widgetFullName),o&&o!==this&&!o.options.disabled&&h.push([e.isFunction(o.options.items)?o.options.items.call(o.element):e(o.options.items,o.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),o]);for(h.push([e.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):e(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]),s=h.length-1;s>=0;s--)h[s][0].each(i);return e(r)},_removeCurrentsFromItems:function(){var t=this.currentItem.find(":data("+this.widgetName+"-item)");this.items=e.grep(this.items,function(e){for(var i=0;t.length>i;i++)if(t[i]===e.item[0])return!1;return!0})},_refreshItems:function(t){this.items=[],this.containers=[this];var i,s,n,a,o,r,h,l,u=this.items,d=[[e.isFunction(this.options.items)?this.options.items.call(this.element[0],t,{item:this.currentItem}):e(this.options.items,this.element),this]],c=this._connectWith();if(c&&this.ready)for(i=c.length-1;i>=0;i--)for(n=e(c[i]),s=n.length-1;s>=0;s--)a=e.data(n[s],this.widgetFullName),a&&a!==this&&!a.options.disabled&&(d.push([e.isFunction(a.options.items)?a.options.items.call(a.element[0],t,{item:this.currentItem}):e(a.options.items,a.element),a]),this.containers.push(a));for(i=d.length-1;i>=0;i--)for(o=d[i][1],r=d[i][0],s=0,l=r.length;l>s;s++)h=e(r[s]),h.data(this.widgetName+"-item",o),u.push({item:h,instance:o,width:0,height:0,left:0,top:0})},refreshPositions:function(t){this.offsetParent&&this.helper&&(this.offset.parent=this._getParentOffset());var i,s,n,a;for(i=this.items.length-1;i>=0;i--)s=this.items[i],s.instance!==this.currentContainer&&this.currentContainer&&s.item[0]!==this.currentItem[0]||(n=this.options.toleranceElement?e(this.options.toleranceElement,s.item):s.item,t||(s.width=n.outerWidth(),s.height=n.outerHeight()),a=n.offset(),s.left=a.left,s.top=a.top);if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(i=this.containers.length-1;i>=0;i--)a=this.containers[i].element.offset(),this.containers[i].containerCache.left=a.left,this.containers[i].containerCache.top=a.top,this.containers[i].containerCache.width=this.containers[i].element.outerWidth(),this.containers[i].containerCache.height=this.containers[i].element.outerHeight();return this},_createPlaceholder:function(t){t=t||this;var i,s=t.options;s.placeholder&&s.placeholder.constructor!==String||(i=s.placeholder,s.placeholder={element:function(){var s=t.currentItem[0].nodeName.toLowerCase(),n=e("<"+s+">",t.document[0]).addClass(i||t.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper");return"tr"===s?t.currentItem.children().each(function(){e(" ",t.document[0]).attr("colspan",e(this).attr("colspan")||1).appendTo(n)}):"img"===s&&n.attr("src",t.currentItem.attr("src")),i||n.css("visibility","hidden"),n},update:function(e,n){(!i||s.forcePlaceholderSize)&&(n.height()||n.height(t.currentItem.innerHeight()-parseInt(t.currentItem.css("paddingTop")||0,10)-parseInt(t.currentItem.css("paddingBottom")||0,10)),n.width()||n.width(t.currentItem.innerWidth()-parseInt(t.currentItem.css("paddingLeft")||0,10)-parseInt(t.currentItem.css("paddingRight")||0,10)))}}),t.placeholder=e(s.placeholder.element.call(t.element,t.currentItem)),t.currentItem.after(t.placeholder),s.placeholder.update(t,t.placeholder)},_contactContainers:function(t){var i,s,n,a,o,r,h,l,u,d,c=null,p=null;for(i=this.containers.length-1;i>=0;i--)if(!e.contains(this.currentItem[0],this.containers[i].element[0]))if(this._intersectsWith(this.containers[i].containerCache)){if(c&&e.contains(this.containers[i].element[0],c.element[0]))continue;c=this.containers[i],p=i}else this.containers[i].containerCache.over&&(this.containers[i]._trigger("out",t,this._uiHash(this)),this.containers[i].containerCache.over=0);if(c)if(1===this.containers.length)this.containers[p].containerCache.over||(this.containers[p]._trigger("over",t,this._uiHash(this)),this.containers[p].containerCache.over=1);else{for(n=1e4,a=null,u=c.floating||this._isFloating(this.currentItem),o=u?"left":"top",r=u?"width":"height",d=u?"clientX":"clientY",s=this.items.length-1;s>=0;s--)e.contains(this.containers[p].element[0],this.items[s].item[0])&&this.items[s].item[0]!==this.currentItem[0]&&(h=this.items[s].item.offset()[o],l=!1,t[d]-h>this.items[s][r]/2&&(l=!0),n>Math.abs(t[d]-h)&&(n=Math.abs(t[d]-h),a=this.items[s],this.direction=l?"up":"down"));if(!a&&!this.options.dropOnEmpty)return;if(this.currentContainer===this.containers[p])return this.currentContainer.containerCache.over||(this.containers[p]._trigger("over",t,this._uiHash()),this.currentContainer.containerCache.over=1),void 0;a?this._rearrange(t,a,null,!0):this._rearrange(t,null,this.containers[p].element,!0),this._trigger("change",t,this._uiHash()),this.containers[p]._trigger("change",t,this._uiHash(this)),this.currentContainer=this.containers[p],this.options.placeholder.update(this.currentContainer,this.placeholder),this.containers[p]._trigger("over",t,this._uiHash(this)),this.containers[p].containerCache.over=1}},_createHelper:function(t){var i=this.options,s=e.isFunction(i.helper)?e(i.helper.apply(this.element[0],[t,this.currentItem])):"clone"===i.helper?this.currentItem.clone():this.currentItem;return s.parents("body").length||e("parent"!==i.appendTo?i.appendTo:this.currentItem[0].parentNode)[0].appendChild(s[0]),s[0]===this.currentItem[0]&&(this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}),(!s[0].style.width||i.forceHelperSize)&&s.width(this.currentItem.width()),(!s[0].style.height||i.forceHelperSize)&&s.height(this.currentItem.height()),s},_adjustOffsetFromHelper:function(t){"string"==typeof t&&(t=t.split(" ")),e.isArray(t)&&(t={left:+t[0],top:+t[1]||0}),"left"in t&&(this.offset.click.left=t.left+this.margins.left),"right"in t&&(this.offset.click.left=this.helperProportions.width-t.right+this.margins.left),"top"in t&&(this.offset.click.top=t.top+this.margins.top),"bottom"in t&&(this.offset.click.top=this.helperProportions.height-t.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var t=this.offsetParent.offset();return"absolute"===this.cssPosition&&this.scrollParent[0]!==document&&e.contains(this.scrollParent[0],this.offsetParent[0])&&(t.left+=this.scrollParent.scrollLeft(),t.top+=this.scrollParent.scrollTop()),(this.offsetParent[0]===document.body||this.offsetParent[0].tagName&&"html"===this.offsetParent[0].tagName.toLowerCase()&&e.ui.ie)&&(t={top:0,left:0}),{top:t.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:t.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"===this.cssPosition){var e=this.currentItem.position();return{top:e.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:e.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var t,i,s,n=this.options;"parent"===n.containment&&(n.containment=this.helper[0].parentNode),("document"===n.containment||"window"===n.containment)&&(this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,e("document"===n.containment?document:window).width()-this.helperProportions.width-this.margins.left,(e("document"===n.containment?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]),/^(document|window|parent)$/.test(n.containment)||(t=e(n.containment)[0],i=e(n.containment).offset(),s="hidden"!==e(t).css("overflow"),this.containment=[i.left+(parseInt(e(t).css("borderLeftWidth"),10)||0)+(parseInt(e(t).css("paddingLeft"),10)||0)-this.margins.left,i.top+(parseInt(e(t).css("borderTopWidth"),10)||0)+(parseInt(e(t).css("paddingTop"),10)||0)-this.margins.top,i.left+(s?Math.max(t.scrollWidth,t.offsetWidth):t.offsetWidth)-(parseInt(e(t).css("borderLeftWidth"),10)||0)-(parseInt(e(t).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,i.top+(s?Math.max(t.scrollHeight,t.offsetHeight):t.offsetHeight)-(parseInt(e(t).css("borderTopWidth"),10)||0)-(parseInt(e(t).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top])},_convertPositionTo:function(t,i){i||(i=this.position);var s="absolute"===t?1:-1,n="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&e.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,a=/(html|body)/i.test(n[0].tagName);return{top:i.top+this.offset.relative.top*s+this.offset.parent.top*s-("fixed"===this.cssPosition?-this.scrollParent.scrollTop():a?0:n.scrollTop())*s,left:i.left+this.offset.relative.left*s+this.offset.parent.left*s-("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():a?0:n.scrollLeft())*s}},_generatePosition:function(t){var i,s,n=this.options,a=t.pageX,o=t.pageY,r="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&e.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,h=/(html|body)/i.test(r[0].tagName);return"relative"!==this.cssPosition||this.scrollParent[0]!==document&&this.scrollParent[0]!==this.offsetParent[0]||(this.offset.relative=this._getRelativeOffset()),this.originalPosition&&(this.containment&&(t.pageX-this.offset.click.leftthis.containment[2]&&(a=this.containment[2]+this.offset.click.left),t.pageY-this.offset.click.top>this.containment[3]&&(o=this.containment[3]+this.offset.click.top)),n.grid&&(i=this.originalPageY+Math.round((o-this.originalPageY)/n.grid[1])*n.grid[1],o=this.containment?i-this.offset.click.top>=this.containment[1]&&i-this.offset.click.top<=this.containment[3]?i:i-this.offset.click.top>=this.containment[1]?i-n.grid[1]:i+n.grid[1]:i,s=this.originalPageX+Math.round((a-this.originalPageX)/n.grid[0])*n.grid[0],a=this.containment?s-this.offset.click.left>=this.containment[0]&&s-this.offset.click.left<=this.containment[2]?s:s-this.offset.click.left>=this.containment[0]?s-n.grid[0]:s+n.grid[0]:s)),{top:o-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():h?0:r.scrollTop()),left:a-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():h?0:r.scrollLeft())}},_rearrange:function(e,t,i,s){i?i[0].appendChild(this.placeholder[0]):t.item[0].parentNode.insertBefore(this.placeholder[0],"down"===this.direction?t.item[0]:t.item[0].nextSibling),this.counter=this.counter?++this.counter:1;var n=this.counter;this._delay(function(){n===this.counter&&this.refreshPositions(!s)})},_clear:function(e,t){function i(e,t,i){return function(s){i._trigger(e,s,t._uiHash(t))}}this.reverting=!1;var s,n=[];if(!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null,this.helper[0]===this.currentItem[0]){for(s in this._storedCSS)("auto"===this._storedCSS[s]||"static"===this._storedCSS[s])&&(this._storedCSS[s]="");this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();for(this.fromOutside&&!t&&n.push(function(e){this._trigger("receive",e,this._uiHash(this.fromOutside))}),!this.fromOutside&&this.domPosition.prev===this.currentItem.prev().not(".ui-sortable-helper")[0]&&this.domPosition.parent===this.currentItem.parent()[0]||t||n.push(function(e){this._trigger("update",e,this._uiHash())}),this!==this.currentContainer&&(t||(n.push(function(e){this._trigger("remove",e,this._uiHash())}),n.push(function(e){return function(t){e._trigger("receive",t,this._uiHash(this))}}.call(this,this.currentContainer)),n.push(function(e){return function(t){e._trigger("update",t,this._uiHash(this))}}.call(this,this.currentContainer)))),s=this.containers.length-1;s>=0;s--)t||n.push(i("deactivate",this,this.containers[s])),this.containers[s].containerCache.over&&(n.push(i("out",this,this.containers[s])),this.containers[s].containerCache.over=0);if(this.storedCursor&&(this.document.find("body").css("cursor",this.storedCursor),this.storedStylesheet.remove()),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex","auto"===this._storedZIndex?"":this._storedZIndex),this.dragging=!1,t||this._trigger("beforeStop",e,this._uiHash()),this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.cancelHelperRemoval||(this.helper[0]!==this.currentItem[0]&&this.helper.remove(),this.helper=null),!t){for(s=0;n.length>s;s++)n[s].call(this,e);this._trigger("stop",e,this._uiHash())}return this.fromOutside=!1,!this.cancelHelperRemoval},_trigger:function(){e.Widget.prototype._trigger.apply(this,arguments)===!1&&this.cancel()},_uiHash:function(t){var i=t||this;return{helper:i.helper,placeholder:i.placeholder||e([]),position:i.position,originalPosition:i.originalPosition,offset:i.positionAbs,item:i.currentItem,sender:t?t.element:null}}}),e.widget("ui.accordion",{version:"1.11.2",options:{active:0,animate:{},collapsible:!1,event:"click",header:"> li > :first-child,> :not(li):even",heightStyle:"auto",icons:{activeHeader:"ui-icon-triangle-1-s",header:"ui-icon-triangle-1-e"},activate:null,beforeActivate:null},hideProps:{borderTopWidth:"hide",borderBottomWidth:"hide",paddingTop:"hide",paddingBottom:"hide",height:"hide"},showProps:{borderTopWidth:"show",borderBottomWidth:"show",paddingTop:"show",paddingBottom:"show",height:"show"},_create:function(){var t=this.options;this.prevShow=this.prevHide=e(),this.element.addClass("ui-accordion ui-widget ui-helper-reset").attr("role","tablist"),t.collapsible||t.active!==!1&&null!=t.active||(t.active=0),this._processPanels(),0>t.active&&(t.active+=this.headers.length),this._refresh()},_getCreateEventData:function(){return{header:this.active,panel:this.active.length?this.active.next():e()}},_createIcons:function(){var t=this.options.icons;t&&(e("").addClass("ui-accordion-header-icon ui-icon "+t.header).prependTo(this.headers),this.active.children(".ui-accordion-header-icon").removeClass(t.header).addClass(t.activeHeader),this.headers.addClass("ui-accordion-icons"))},_destroyIcons:function(){this.headers.removeClass("ui-accordion-icons").children(".ui-accordion-header-icon").remove()},_destroy:function(){var e;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role"),this.headers.removeClass("ui-accordion-header ui-accordion-header-active ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-selected").removeAttr("aria-controls").removeAttr("tabIndex").removeUniqueId(),this._destroyIcons(),e=this.headers.next().removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled").css("display","").removeAttr("role").removeAttr("aria-hidden").removeAttr("aria-labelledby").removeUniqueId(),"content"!==this.options.heightStyle&&e.css("height","")},_setOption:function(e,t){return"active"===e?(this._activate(t),void 0):("event"===e&&(this.options.event&&this._off(this.headers,this.options.event),this._setupEvents(t)),this._super(e,t),"collapsible"!==e||t||this.options.active!==!1||this._activate(0),"icons"===e&&(this._destroyIcons(),t&&this._createIcons()),"disabled"===e&&(this.element.toggleClass("ui-state-disabled",!!t).attr("aria-disabled",t),this.headers.add(this.headers.next()).toggleClass("ui-state-disabled",!!t)),void 0)},_keydown:function(t){if(!t.altKey&&!t.ctrlKey){var i=e.ui.keyCode,s=this.headers.length,n=this.headers.index(t.target),a=!1;switch(t.keyCode){case i.RIGHT:case i.DOWN:a=this.headers[(n+1)%s];break;case i.LEFT:case i.UP:a=this.headers[(n-1+s)%s];break;case i.SPACE:case i.ENTER:this._eventHandler(t);break;case i.HOME:a=this.headers[0];break;case i.END:a=this.headers[s-1]}a&&(e(t.target).attr("tabIndex",-1),e(a).attr("tabIndex",0),a.focus(),t.preventDefault())}},_panelKeyDown:function(t){t.keyCode===e.ui.keyCode.UP&&t.ctrlKey&&e(t.currentTarget).prev().focus()},refresh:function(){var t=this.options;this._processPanels(),t.active===!1&&t.collapsible===!0||!this.headers.length?(t.active=!1,this.active=e()):t.active===!1?this._activate(0):this.active.length&&!e.contains(this.element[0],this.active[0])?this.headers.length===this.headers.find(".ui-state-disabled").length?(t.active=!1,this.active=e()):this._activate(Math.max(0,t.active-1)):t.active=this.headers.index(this.active),this._destroyIcons(),this._refresh()},_processPanels:function(){var e=this.headers,t=this.panels;this.headers=this.element.find(this.options.header).addClass("ui-accordion-header ui-state-default ui-corner-all"),this.panels=this.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom").filter(":not(.ui-accordion-content-active)").hide(),t&&(this._off(e.not(this.headers)),this._off(t.not(this.panels)))},_refresh:function(){var t,i=this.options,s=i.heightStyle,n=this.element.parent();this.active=this._findActive(i.active).addClass("ui-accordion-header-active ui-state-active ui-corner-top").removeClass("ui-corner-all"),this.active.next().addClass("ui-accordion-content-active").show(),this.headers.attr("role","tab").each(function(){var t=e(this),i=t.uniqueId().attr("id"),s=t.next(),n=s.uniqueId().attr("id"); +t.attr("aria-controls",n),s.attr("aria-labelledby",i)}).next().attr("role","tabpanel"),this.headers.not(this.active).attr({"aria-selected":"false","aria-expanded":"false",tabIndex:-1}).next().attr({"aria-hidden":"true"}).hide(),this.active.length?this.active.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0}).next().attr({"aria-hidden":"false"}):this.headers.eq(0).attr("tabIndex",0),this._createIcons(),this._setupEvents(i.event),"fill"===s?(t=n.height(),this.element.siblings(":visible").each(function(){var i=e(this),s=i.css("position");"absolute"!==s&&"fixed"!==s&&(t-=i.outerHeight(!0))}),this.headers.each(function(){t-=e(this).outerHeight(!0)}),this.headers.next().each(function(){e(this).height(Math.max(0,t-e(this).innerHeight()+e(this).height()))}).css("overflow","auto")):"auto"===s&&(t=0,this.headers.next().each(function(){t=Math.max(t,e(this).css("height","").height())}).height(t))},_activate:function(t){var i=this._findActive(t)[0];i!==this.active[0]&&(i=i||this.active[0],this._eventHandler({target:i,currentTarget:i,preventDefault:e.noop}))},_findActive:function(t){return"number"==typeof t?this.headers.eq(t):e()},_setupEvents:function(t){var i={keydown:"_keydown"};t&&e.each(t.split(" "),function(e,t){i[t]="_eventHandler"}),this._off(this.headers.add(this.headers.next())),this._on(this.headers,i),this._on(this.headers.next(),{keydown:"_panelKeyDown"}),this._hoverable(this.headers),this._focusable(this.headers)},_eventHandler:function(t){var i=this.options,s=this.active,n=e(t.currentTarget),a=n[0]===s[0],o=a&&i.collapsible,r=o?e():n.next(),h=s.next(),l={oldHeader:s,oldPanel:h,newHeader:o?e():n,newPanel:r};t.preventDefault(),a&&!i.collapsible||this._trigger("beforeActivate",t,l)===!1||(i.active=o?!1:this.headers.index(n),this.active=a?e():n,this._toggle(l),s.removeClass("ui-accordion-header-active ui-state-active"),i.icons&&s.children(".ui-accordion-header-icon").removeClass(i.icons.activeHeader).addClass(i.icons.header),a||(n.removeClass("ui-corner-all").addClass("ui-accordion-header-active ui-state-active ui-corner-top"),i.icons&&n.children(".ui-accordion-header-icon").removeClass(i.icons.header).addClass(i.icons.activeHeader),n.next().addClass("ui-accordion-content-active")))},_toggle:function(t){var i=t.newPanel,s=this.prevShow.length?this.prevShow:t.oldPanel;this.prevShow.add(this.prevHide).stop(!0,!0),this.prevShow=i,this.prevHide=s,this.options.animate?this._animate(i,s,t):(s.hide(),i.show(),this._toggleComplete(t)),s.attr({"aria-hidden":"true"}),s.prev().attr("aria-selected","false"),i.length&&s.length?s.prev().attr({tabIndex:-1,"aria-expanded":"false"}):i.length&&this.headers.filter(function(){return 0===e(this).attr("tabIndex")}).attr("tabIndex",-1),i.attr("aria-hidden","false").prev().attr({"aria-selected":"true",tabIndex:0,"aria-expanded":"true"})},_animate:function(e,t,i){var s,n,a,o=this,r=0,h=e.length&&(!t.length||e.index()",delay:300,options:{icons:{submenu:"ui-icon-carat-1-e"},items:"> *",menus:"ul",position:{my:"left-1 top",at:"right top"},role:"menu",blur:null,focus:null,select:null},_create:function(){this.activeMenu=this.element,this.mouseHandled=!1,this.element.uniqueId().addClass("ui-menu ui-widget ui-widget-content").toggleClass("ui-menu-icons",!!this.element.find(".ui-icon").length).attr({role:this.options.role,tabIndex:0}),this.options.disabled&&this.element.addClass("ui-state-disabled").attr("aria-disabled","true"),this._on({"mousedown .ui-menu-item":function(e){e.preventDefault()},"click .ui-menu-item":function(t){var i=e(t.target);!this.mouseHandled&&i.not(".ui-state-disabled").length&&(this.select(t),t.isPropagationStopped()||(this.mouseHandled=!0),i.has(".ui-menu").length?this.expand(t):!this.element.is(":focus")&&e(this.document[0].activeElement).closest(".ui-menu").length&&(this.element.trigger("focus",[!0]),this.active&&1===this.active.parents(".ui-menu").length&&clearTimeout(this.timer)))},"mouseenter .ui-menu-item":function(t){if(!this.previousFilter){var i=e(t.currentTarget);i.siblings(".ui-state-active").removeClass("ui-state-active"),this.focus(t,i)}},mouseleave:"collapseAll","mouseleave .ui-menu":"collapseAll",focus:function(e,t){var i=this.active||this.element.find(this.options.items).eq(0);t||this.focus(e,i)},blur:function(t){this._delay(function(){e.contains(this.element[0],this.document[0].activeElement)||this.collapseAll(t)})},keydown:"_keydown"}),this.refresh(),this._on(this.document,{click:function(e){this._closeOnDocumentClick(e)&&this.collapseAll(e),this.mouseHandled=!1}})},_destroy:function(){this.element.removeAttr("aria-activedescendant").find(".ui-menu").addBack().removeClass("ui-menu ui-widget ui-widget-content ui-menu-icons ui-front").removeAttr("role").removeAttr("tabIndex").removeAttr("aria-labelledby").removeAttr("aria-expanded").removeAttr("aria-hidden").removeAttr("aria-disabled").removeUniqueId().show(),this.element.find(".ui-menu-item").removeClass("ui-menu-item").removeAttr("role").removeAttr("aria-disabled").removeUniqueId().removeClass("ui-state-hover").removeAttr("tabIndex").removeAttr("role").removeAttr("aria-haspopup").children().each(function(){var t=e(this);t.data("ui-menu-submenu-carat")&&t.remove()}),this.element.find(".ui-menu-divider").removeClass("ui-menu-divider ui-widget-content")},_keydown:function(t){var i,s,n,a,o=!0;switch(t.keyCode){case e.ui.keyCode.PAGE_UP:this.previousPage(t);break;case e.ui.keyCode.PAGE_DOWN:this.nextPage(t);break;case e.ui.keyCode.HOME:this._move("first","first",t);break;case e.ui.keyCode.END:this._move("last","last",t);break;case e.ui.keyCode.UP:this.previous(t);break;case e.ui.keyCode.DOWN:this.next(t);break;case e.ui.keyCode.LEFT:this.collapse(t);break;case e.ui.keyCode.RIGHT:this.active&&!this.active.is(".ui-state-disabled")&&this.expand(t);break;case e.ui.keyCode.ENTER:case e.ui.keyCode.SPACE:this._activate(t);break;case e.ui.keyCode.ESCAPE:this.collapse(t);break;default:o=!1,s=this.previousFilter||"",n=String.fromCharCode(t.keyCode),a=!1,clearTimeout(this.filterTimer),n===s?a=!0:n=s+n,i=this._filterMenuItems(n),i=a&&-1!==i.index(this.active.next())?this.active.nextAll(".ui-menu-item"):i,i.length||(n=String.fromCharCode(t.keyCode),i=this._filterMenuItems(n)),i.length?(this.focus(t,i),this.previousFilter=n,this.filterTimer=this._delay(function(){delete this.previousFilter},1e3)):delete this.previousFilter}o&&t.preventDefault()},_activate:function(e){this.active.is(".ui-state-disabled")||(this.active.is("[aria-haspopup='true']")?this.expand(e):this.select(e))},refresh:function(){var t,i,s=this,n=this.options.icons.submenu,a=this.element.find(this.options.menus);this.element.toggleClass("ui-menu-icons",!!this.element.find(".ui-icon").length),a.filter(":not(.ui-menu)").addClass("ui-menu ui-widget ui-widget-content ui-front").hide().attr({role:this.options.role,"aria-hidden":"true","aria-expanded":"false"}).each(function(){var t=e(this),i=t.parent(),s=e("").addClass("ui-menu-icon ui-icon "+n).data("ui-menu-submenu-carat",!0);i.attr("aria-haspopup","true").prepend(s),t.attr("aria-labelledby",i.attr("id"))}),t=a.add(this.element),i=t.find(this.options.items),i.not(".ui-menu-item").each(function(){var t=e(this);s._isDivider(t)&&t.addClass("ui-widget-content ui-menu-divider")}),i.not(".ui-menu-item, .ui-menu-divider").addClass("ui-menu-item").uniqueId().attr({tabIndex:-1,role:this._itemRole()}),i.filter(".ui-state-disabled").attr("aria-disabled","true"),this.active&&!e.contains(this.element[0],this.active[0])&&this.blur()},_itemRole:function(){return{menu:"menuitem",listbox:"option"}[this.options.role]},_setOption:function(e,t){"icons"===e&&this.element.find(".ui-menu-icon").removeClass(this.options.icons.submenu).addClass(t.submenu),"disabled"===e&&this.element.toggleClass("ui-state-disabled",!!t).attr("aria-disabled",t),this._super(e,t)},focus:function(e,t){var i,s;this.blur(e,e&&"focus"===e.type),this._scrollIntoView(t),this.active=t.first(),s=this.active.addClass("ui-state-focus").removeClass("ui-state-active"),this.options.role&&this.element.attr("aria-activedescendant",s.attr("id")),this.active.parent().closest(".ui-menu-item").addClass("ui-state-active"),e&&"keydown"===e.type?this._close():this.timer=this._delay(function(){this._close()},this.delay),i=t.children(".ui-menu"),i.length&&e&&/^mouse/.test(e.type)&&this._startOpening(i),this.activeMenu=t.parent(),this._trigger("focus",e,{item:t})},_scrollIntoView:function(t){var i,s,n,a,o,r;this._hasScroll()&&(i=parseFloat(e.css(this.activeMenu[0],"borderTopWidth"))||0,s=parseFloat(e.css(this.activeMenu[0],"paddingTop"))||0,n=t.offset().top-this.activeMenu.offset().top-i-s,a=this.activeMenu.scrollTop(),o=this.activeMenu.height(),r=t.outerHeight(),0>n?this.activeMenu.scrollTop(a+n):n+r>o&&this.activeMenu.scrollTop(a+n-o+r))},blur:function(e,t){t||clearTimeout(this.timer),this.active&&(this.active.removeClass("ui-state-focus"),this.active=null,this._trigger("blur",e,{item:this.active}))},_startOpening:function(e){clearTimeout(this.timer),"true"===e.attr("aria-hidden")&&(this.timer=this._delay(function(){this._close(),this._open(e)},this.delay))},_open:function(t){var i=e.extend({of:this.active},this.options.position);clearTimeout(this.timer),this.element.find(".ui-menu").not(t.parents(".ui-menu")).hide().attr("aria-hidden","true"),t.show().removeAttr("aria-hidden").attr("aria-expanded","true").position(i)},collapseAll:function(t,i){clearTimeout(this.timer),this.timer=this._delay(function(){var s=i?this.element:e(t&&t.target).closest(this.element.find(".ui-menu"));s.length||(s=this.element),this._close(s),this.blur(t),this.activeMenu=s},this.delay)},_close:function(e){e||(e=this.active?this.active.parent():this.element),e.find(".ui-menu").hide().attr("aria-hidden","true").attr("aria-expanded","false").end().find(".ui-state-active").not(".ui-state-focus").removeClass("ui-state-active")},_closeOnDocumentClick:function(t){return!e(t.target).closest(".ui-menu").length},_isDivider:function(e){return!/[^\-\u2014\u2013\s]/.test(e.text())},collapse:function(e){var t=this.active&&this.active.parent().closest(".ui-menu-item",this.element);t&&t.length&&(this._close(),this.focus(e,t))},expand:function(e){var t=this.active&&this.active.children(".ui-menu ").find(this.options.items).first();t&&t.length&&(this._open(t.parent()),this._delay(function(){this.focus(e,t)}))},next:function(e){this._move("next","first",e)},previous:function(e){this._move("prev","last",e)},isFirstItem:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},isLastItem:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},_move:function(e,t,i){var s;this.active&&(s="first"===e||"last"===e?this.active["first"===e?"prevAll":"nextAll"](".ui-menu-item").eq(-1):this.active[e+"All"](".ui-menu-item").eq(0)),s&&s.length&&this.active||(s=this.activeMenu.find(this.options.items)[t]()),this.focus(i,s)},nextPage:function(t){var i,s,n;return this.active?(this.isLastItem()||(this._hasScroll()?(s=this.active.offset().top,n=this.element.height(),this.active.nextAll(".ui-menu-item").each(function(){return i=e(this),0>i.offset().top-s-n}),this.focus(t,i)):this.focus(t,this.activeMenu.find(this.options.items)[this.active?"last":"first"]())),void 0):(this.next(t),void 0)},previousPage:function(t){var i,s,n;return this.active?(this.isFirstItem()||(this._hasScroll()?(s=this.active.offset().top,n=this.element.height(),this.active.prevAll(".ui-menu-item").each(function(){return i=e(this),i.offset().top-s+n>0}),this.focus(t,i)):this.focus(t,this.activeMenu.find(this.options.items).first())),void 0):(this.next(t),void 0)},_hasScroll:function(){return this.element.outerHeight()",options:{appendTo:null,autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null,change:null,close:null,focus:null,open:null,response:null,search:null,select:null},requestIndex:0,pending:0,_create:function(){var t,i,s,n=this.element[0].nodeName.toLowerCase(),a="textarea"===n,o="input"===n;this.isMultiLine=a?!0:o?!1:this.element.prop("isContentEditable"),this.valueMethod=this.element[a||o?"val":"text"],this.isNewMenu=!0,this.element.addClass("ui-autocomplete-input").attr("autocomplete","off"),this._on(this.element,{keydown:function(n){if(this.element.prop("readOnly"))return t=!0,s=!0,i=!0,void 0;t=!1,s=!1,i=!1;var a=e.ui.keyCode;switch(n.keyCode){case a.PAGE_UP:t=!0,this._move("previousPage",n);break;case a.PAGE_DOWN:t=!0,this._move("nextPage",n);break;case a.UP:t=!0,this._keyEvent("previous",n);break;case a.DOWN:t=!0,this._keyEvent("next",n);break;case a.ENTER:this.menu.active&&(t=!0,n.preventDefault(),this.menu.select(n));break;case a.TAB:this.menu.active&&this.menu.select(n);break;case a.ESCAPE:this.menu.element.is(":visible")&&(this.isMultiLine||this._value(this.term),this.close(n),n.preventDefault());break;default:i=!0,this._searchTimeout(n)}},keypress:function(s){if(t)return t=!1,(!this.isMultiLine||this.menu.element.is(":visible"))&&s.preventDefault(),void 0;if(!i){var n=e.ui.keyCode;switch(s.keyCode){case n.PAGE_UP:this._move("previousPage",s);break;case n.PAGE_DOWN:this._move("nextPage",s);break;case n.UP:this._keyEvent("previous",s);break;case n.DOWN:this._keyEvent("next",s)}}},input:function(e){return s?(s=!1,e.preventDefault(),void 0):(this._searchTimeout(e),void 0)},focus:function(){this.selectedItem=null,this.previous=this._value()},blur:function(e){return this.cancelBlur?(delete this.cancelBlur,void 0):(clearTimeout(this.searching),this.close(e),this._change(e),void 0)}}),this._initSource(),this.menu=e("