This is an automated email from the ASF dual-hosted git repository. matthiasblaesing pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/netbeans-tools.git
The following commit(s) were added to refs/heads/master by this push: new 4a88fd3 Improve image upload handling for PP3 new 1158393 Merge pull request #55 from matthiasblaesing/improve_image_upload 4a88fd3 is described below commit 4a88fd3c11717a99ae1b5cd924742b2f538c952a Author: Matthias Bläsing <mblaes...@doppel-helix.eu> AuthorDate: Thu Nov 10 20:47:23 2022 +0100 Improve image upload handling for PP3 - Allow the user/admin to remove an existing image - Prepare the fileselector with a list of relevant files - Remove old images - Unify naming of uploaded images --- .../Application/config/module.config.php.dist | 6 ++ .../src/Application/Controller/AdminController.php | 58 +++++++++++++---- .../Application/Controller/PluginController.php | 74 ++++++++++++++++++---- .../Application/view/application/admin/edit.phtml | 2 +- .../view/application/plugin/_plugin-form.phtml | 11 +++- .../view/application/plugin/confirm.phtml | 2 +- .../Application/view/application/plugin/edit.phtml | 2 +- 7 files changed, 126 insertions(+), 29 deletions(-) diff --git a/pp3/module/Application/config/module.config.php.dist b/pp3/module/Application/config/module.config.php.dist index 32f514b..36bae75 100755 --- a/pp3/module/Application/config/module.config.php.dist +++ b/pp3/module/Application/config/module.config.php.dist @@ -36,6 +36,12 @@ return array( 'dtdPath' => 'http://localhost/checkout/pp3/public/dtd/autoupdate-catalog-2_8.dtd', 'downloadBaseUrl' => 'http://localhost/pp3/catalogue/download' ), + 'imageTypes' => array ( + 'svg', + 'png', + 'jpg', + 'jpeg' + ), 'loginConfig' => array ( array( 'id' => 'github', diff --git a/pp3/module/Application/src/Application/Controller/AdminController.php b/pp3/module/Application/src/Application/Controller/AdminController.php index 546a77d..366ce20 100644 --- a/pp3/module/Application/src/Application/Controller/AdminController.php +++ b/pp3/module/Application/src/Application/Controller/AdminController.php @@ -588,23 +588,37 @@ NetBeans development team $this->params()->fromPost('license'), $this->params()->fromPost('description'), $this->params()->fromPost('short_description'), - $this->params()->fromPost('category') + $this->params()->fromPost('category'), + $this->params()->fromPost('homepage'), + array_key_exists('image-file', $_FILES) ? $_FILES['image-file'] : false ); if ($validatedData) { $plugin->setName($validatedData['name']); $plugin->setLicense($validatedData['license']); $plugin->setDescription($validatedData['description']); $plugin->setShortDescription($validatedData['short_description']); + $plugin->setHomepage($validatedData['homepage']); $plugin->setLastUpdatedAt(new \DateTime('now')); + $imageDir = $this->_config['pp3']['catalogSavepath'] . '/plugins/' . $plugin->getId(); + + $oldImage = $plugin->getImage(); + // save image - $im = $this->handleImgUpload($this->_config['pp3']['catalogSavepath'] . '/plugins/' . $plugin->getId()); + $im = $this->handleImgUpload($validatedData, $imageDir); if ($im) { $plugin->setImage($im); } + if($this->params()->fromPost('image-file-delete') == 'true') { + $plugin->setImage(null); + } - // categ + if($oldImage && $oldImage != $plugin->getImage()) { + unlink($imageDir . '/' . $oldImage); + } + + // category $plugin->removeCategories(); $this->_pluginRepository->persist($plugin); $cat = $this->_categoryRepository->find($validatedData['category']); @@ -637,14 +651,29 @@ NetBeans development team return new ViewModel(array( 'plugin' => $plugin, 'categories' => $this->_categoryRepository->getAllCategoriesSortByName(), - 'activeTab' => $activeTab + 'activeTab' => $activeTab, + 'imageTypes' => $this->_config['imageTypes'] )); } - private function _validateAndCleanPluginData($name, $license, $description, $shortDescription, $category) { - if (empty($name) || empty($license) || empty($category) || empty($shortDescription)) { + private function _validateAndCleanPluginData($name, $license, $description, $shortDescription, $category, $homepage, $imageFileData) { + $fileType = false; + if($imageFileData && $imageFileData['size'] > 0) { + $baseName = basename(strtolower($imageFileData['name'])); + $pathInfo = pathinfo($baseName); + $imageFileNameType = $pathInfo["extension"]; + foreach($this->_config['imageTypes'] as $imageType) { + if($imageFileNameType == $imageType) { + $fileType = $imageType; + break; + } + } + } + + if (empty($name) || empty($license) || empty($category) || empty($shortDescription) || ($imageFileData && $imageFileData['size'] > 0 && (!$fileType))) { return false; } + $config = HTMLPurifier_Config::createDefault(); $purifier = new HTMLPurifier($config); return array( @@ -652,7 +681,9 @@ NetBeans development team 'license' => $purifier->purify($license), 'description' => $purifier->purify($description), 'short_description' => $purifier->purify($shortDescription), - 'category' => $category + 'category' => $category, + 'homepage' => $purifier->purify($homepage), + 'image' => $fileType ? ['tmp_name' => $imageFileData['tmp_name'], 'name' => 'image.' . $fileType] : false ); } @@ -673,16 +704,19 @@ NetBeans development team return $response; } - private function handleImgUpload($imgFolder) { - $tmp_name = $_FILES["image-file"]["tmp_name"]; + private function handleImgUpload($validatedData, $imgFolder) { + if(! $validatedData['image']) { + return false; + } + $tmp_name = $validatedData['image']['tmp_name']; // basename() may prevent filesystem traversal attacks; // further validation/sanitation of the filename may be appropriate - $name = basename($_FILES["image-file"]["name"]); + $name = $validatedData['image']['name']; if(!file_exists($imgFolder)) { mkdir($imgFolder, 0777, true); } if(move_uploaded_file($tmp_name, $imgFolder.'/'.$name)) { - return $name; - } + return $name; + } } } diff --git a/pp3/module/Application/src/Application/Controller/PluginController.php b/pp3/module/Application/src/Application/Controller/PluginController.php index bdb6cef..01ff0b7 100644 --- a/pp3/module/Application/src/Application/Controller/PluginController.php +++ b/pp3/module/Application/src/Application/Controller/PluginController.php @@ -84,17 +84,20 @@ class PluginController extends AuthenticatedController { )); } - private function handleImgUpload($imgFolder) { - $tmp_name = $_FILES["image-file"]["tmp_name"]; + private function handleImgUpload($validatedData, $imgFolder) { + if(! $validatedData['image']) { + return false; + } + $tmp_name = $validatedData['image']['tmp_name']; // basename() may prevent filesystem traversal attacks; // further validation/sanitation of the filename may be appropriate - $name = basename($_FILES["image-file"]["name"]); + $name = $validatedData['image']['name']; if(!file_exists($imgFolder)) { mkdir($imgFolder, 0777, true); } if(move_uploaded_file($tmp_name, $imgFolder.'/'.$name)) { - return $name; - } + return $name; + } } public function indexAction() { @@ -159,7 +162,8 @@ class PluginController extends AuthenticatedController { $this->params()->fromPost('description'), $this->params()->fromPost('short_description'), $this->params()->fromPost('category'), - $this->params()->fromPost('homepage') + $this->params()->fromPost('homepage'), + array_key_exists('image-file', $_FILES) ? $_FILES['image-file'] : false ); if ($validatedData) { $user = $this->_userRepository->find($this->getAuthenticatedUserId()); @@ -185,12 +189,24 @@ class PluginController extends AuthenticatedController { $plugin->addCategory($cat2); } } + + $imageDir = $this->_config['pp3']['catalogSavepath'] . '/plugins/' . $plugin->getId(); + + $oldImage = $plugin->getImage(); + // save image - $im = $this->handleImgUpload($this->_config['pp3']['catalogSavepath'].'/plugins/'.$plugin->getId()); - if ($im) { + $im = $this->handleImgUpload($validatedData, $imageDir); + if ($im) { $plugin->setImage($im); } + if($this->params()->fromPost('image-file-delete') == 'true') { + $plugin->setImage(null); + } + + if($oldImage && $oldImage != $plugin->getImage()) { + unlink($imageDir . '/' . $oldImage); + } $this->_pluginRepository->persist($plugin); $this->flashMessenger()->setNamespace('success')->addMessage('Plugin registered.'); @@ -209,6 +225,8 @@ class PluginController extends AuthenticatedController { return new ViewModel([ 'plugin' => $plugin, 'categories' => $this->_categoryRepository->getAllCategoriesSortByName(), + 'imageTypes' => $this->_config['imageTypes'], + 'editMode' => false ]); } @@ -270,7 +288,8 @@ class PluginController extends AuthenticatedController { $this->params()->fromPost('description'), $this->params()->fromPost('short_description'), $this->params()->fromPost('category'), - $this->params()->fromPost('homepage') + $this->params()->fromPost('homepage'), + array_key_exists('image-file', $_FILES) ? $_FILES['image-file'] : false ); if ($validatedData) { $plugin->setName($validatedData['name']); @@ -280,12 +299,24 @@ class PluginController extends AuthenticatedController { $plugin->setHomepage($validatedData['homepage']); $plugin->setLastUpdatedAt(new \DateTime('now')); + $imageDir = $this->_config['pp3']['catalogSavepath'] . '/plugins/' . $plugin->getId(); + + $oldImage = $plugin->getImage(); + // save image - $im = $this->handleImgUpload($this->_config['pp3']['catalogSavepath'] . '/plugins/' . $plugin->getId()); + $im = $this->handleImgUpload($validatedData, $imageDir); if ($im) { $plugin->setImage($im); } + if($this->params()->fromPost('image-file-delete') == 'true') { + $plugin->setImage(null); + } + + if($oldImage && $oldImage != $plugin->getImage()) { + unlink($imageDir . '/' . $oldImage); + } + // categ $plugin->removeCategories(); $this->_pluginRepository->persist($plugin); @@ -320,7 +351,9 @@ class PluginController extends AuthenticatedController { return new ViewModel(array( 'plugin' => $plugin, 'categories' => $this->_categoryRepository->getAllCategoriesSortByName(), - 'activeTab' => $activeTab + 'activeTab' => $activeTab, + 'imageTypes' => $this->_config['imageTypes'], + 'editMode' => true )); } @@ -348,10 +381,24 @@ class PluginController extends AuthenticatedController { } } - private function _validateAndCleanPluginData($name, $license, $description, $shortDescription, $category, $homepage) { - if (empty($name) || empty($license) || empty($category) || empty($shortDescription)) { + private function _validateAndCleanPluginData($name, $license, $description, $shortDescription, $category, $homepage, $imageFileData) { + $fileType = false; + if($imageFileData && $imageFileData['size'] > 0) { + $baseName = basename(strtolower($imageFileData['name'])); + $pathInfo = pathinfo($baseName); + $imageFileNameType = $pathInfo["extension"]; + foreach($this->_config['imageTypes'] as $imageType) { + if($imageFileNameType == $imageType) { + $fileType = $imageType; + break; + } + } + } + + if (empty($name) || empty($license) || empty($category) || empty($shortDescription) || ($imageFileData && $imageFileData['size'] > 0 && (!$fileType))) { return false; } + $config = HTMLPurifier_Config::createDefault(); $purifier = new HTMLPurifier($config); return array( @@ -361,6 +408,7 @@ class PluginController extends AuthenticatedController { 'short_description' => $purifier->purify($shortDescription), 'category' => $category, 'homepage' => $purifier->purify($homepage), + 'image' => $fileType ? ['tmp_name' => $imageFileData['tmp_name'], 'name' => 'image.' . $fileType] : false ); } diff --git a/pp3/module/Application/view/application/admin/edit.phtml b/pp3/module/Application/view/application/admin/edit.phtml index 2a51f1a..c852635 100644 --- a/pp3/module/Application/view/application/admin/edit.phtml +++ b/pp3/module/Application/view/application/admin/edit.phtml @@ -30,7 +30,7 @@ <div class="row"> <div class="col col-sm-6"> <form method="post" action="" class="needs-validation" enctype="multipart/form-data"> - <?= $this->partial('application/plugin/_plugin-form.phtml', array('plugin' => $this->plugin, 'categories' => $this->categories)); ?> + <?= $this->partial('application/plugin/_plugin-form.phtml', array('plugin' => $this->plugin, 'categories' => $this->categories, 'imageTypes'=>$this->imageTypes, 'editMode' => true)); ?> <a class="btn btn-secondary" href="<?= $this->url('admin') ?>" role="button">Return</a> <button type="submit" class="btn btn-primary">Save Plugin</button> </form> diff --git a/pp3/module/Application/view/application/plugin/_plugin-form.phtml b/pp3/module/Application/view/application/plugin/_plugin-form.phtml index f8b438a..11c1e3f 100644 --- a/pp3/module/Application/view/application/plugin/_plugin-form.phtml +++ b/pp3/module/Application/view/application/plugin/_plugin-form.phtml @@ -65,5 +65,14 @@ </div> <div class="form-group"> <label for="image-file">Image</label> - <input type="file" name="image-file" id="image-file"> + <?php + $imageTypes = implode(array_map(function($a) {return '.' . $a;}, $this->imageTypes), ','); + ?> + <input type="file" name="image-file" id="image-file" accept="<?php echo $imageTypes ?>"> + <?php if ($this->editMode) { ?> + <p> + <input type="checkbox" name="image-file-delete" id="image-file-delete" value="true"> + <label for="image-file-delete" style="font-weight: normal">Remove Image</label> + </p> + <?php } ?> </div> diff --git a/pp3/module/Application/view/application/plugin/confirm.phtml b/pp3/module/Application/view/application/plugin/confirm.phtml index fd0ca5e..c8acf1f 100644 --- a/pp3/module/Application/view/application/plugin/confirm.phtml +++ b/pp3/module/Application/view/application/plugin/confirm.phtml @@ -23,7 +23,7 @@ <div class="col col-sm-6"> <?= $this->partial('layout/flash.phtml'); ?> <form method="post" action="" class="needs-validation" enctype="multipart/form-data"> - <?= $this->partial('application/plugin/_plugin-form.phtml', array('plugin' => $this->plugin, 'categories'=>$this->categories)); ?> + <?= $this->partial('application/plugin/_plugin-form.phtml', array('plugin' => $this->plugin, 'categories'=>$this->categories, 'imageTypes'=>$this->imageTypes, 'editMode' => false)); ?> <a class="btn btn-secondary" href="../plugin/" role="button">Cancel</a> <button type="submit" class="btn btn-primary">Save Plugin</button> </form> diff --git a/pp3/module/Application/view/application/plugin/edit.phtml b/pp3/module/Application/view/application/plugin/edit.phtml index abeeedd..2eec7c6 100644 --- a/pp3/module/Application/view/application/plugin/edit.phtml +++ b/pp3/module/Application/view/application/plugin/edit.phtml @@ -30,7 +30,7 @@ <div class="row"> <div class="col col-sm-6"> <form method="post" action="" class="needs-validation" enctype="multipart/form-data"> - <?= $this->partial('application/plugin/_plugin-form.phtml', array('plugin' => $this->plugin, 'categories' => $this->categories)); ?> + <?= $this->partial('application/plugin/_plugin-form.phtml', array('plugin' => $this->plugin, 'categories' => $this->categories, 'imageTypes'=>$this->imageTypes, 'editMode' => true)); ?> <a class="btn btn-secondary" href="../plugin/list" role="button">Return</a> <button type="submit" class="btn btn-primary">Save Plugin</button> </form> --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@netbeans.apache.org For additional commands, e-mail: commits-h...@netbeans.apache.org For further information about the NetBeans mailing lists, visit: https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists