From 26f3cbe9949a2007706e162e2a905a6161409ddd Mon Sep 17 00:00:00 2001 From: Ro Date: Tue, 3 Jan 2023 16:08:50 -0800 Subject: [PATCH] Location Editing Part 2 Bulk uploading has been added and some inconsistencies in the templates have been addressed. Still needs work but it's starting to feel like a cohesive experience. With the base data entry funcationality in place, now really polishing can begin as well as establishing what roles can do what. Smoothing out entry editing will be addressed as well. --- composer.json | 1 + composer.lock | 86 +++++++++++++++++++++- public/assets/css/front/frame.css | 3 +- public/assets/css/front/index-den.css | 5 ++ src/Controller/Routes/Back/Locations.php | 88 ++++++++++++++++++++++ src/Service/HandleLocations.php | 94 ++++++++++++++++++++++++ templates/back/locations.twig | 23 ++++-- templates/forms/bulk-add-location.twig | 8 ++ templates/forms/edit-location.twig | 11 ++- 9 files changed, 309 insertions(+), 10 deletions(-) create mode 100644 templates/forms/bulk-add-location.twig diff --git a/composer.json b/composer.json index adf2356..03aee07 100644 --- a/composer.json +++ b/composer.json @@ -10,6 +10,7 @@ "doctrine/doctrine-bundle": "^2.7", "doctrine/doctrine-migrations-bundle": "^3.2", "doctrine/orm": "^2.13", + "league/csv": "^9.0", "rbdwllr/reallysimplejwt": "^5.0", "sensio/framework-extra-bundle": "^6.2", "symfony/console": "6.1.*", diff --git a/composer.lock b/composer.lock index 8963d5a..dc6a7fe 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "eb3c50bec813d049150ad9f4cf2b9617", + "content-hash": "f31b264b29ff1c91409f2abfcd475ad0", "packages": [ { "name": "doctrine/annotations", @@ -1524,6 +1524,90 @@ ], "time": "2022-11-21T01:32:31+00:00" }, + { + "name": "league/csv", + "version": "9.8.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/csv.git", + "reference": "9d2e0265c5d90f5dd601bc65ff717e05cec19b47" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/csv/zipball/9d2e0265c5d90f5dd601bc65ff717e05cec19b47", + "reference": "9d2e0265c5d90f5dd601bc65ff717e05cec19b47", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-mbstring": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "ext-curl": "*", + "ext-dom": "*", + "friendsofphp/php-cs-fixer": "^v3.4.0", + "phpstan/phpstan": "^1.3.0", + "phpstan/phpstan-phpunit": "^1.0.0", + "phpstan/phpstan-strict-rules": "^1.1.0", + "phpunit/phpunit": "^9.5.11" + }, + "suggest": { + "ext-dom": "Required to use the XMLConverter and or the HTMLConverter classes", + "ext-iconv": "Needed to ease transcoding CSV using iconv stream filters" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.x-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "League\\Csv\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://github.com/nyamsprod/", + "role": "Developer" + } + ], + "description": "CSV data manipulation made easy in PHP", + "homepage": "https://csv.thephpleague.com", + "keywords": [ + "convert", + "csv", + "export", + "filter", + "import", + "read", + "transform", + "write" + ], + "support": { + "docs": "https://csv.thephpleague.com", + "issues": "https://github.com/thephpleague/csv/issues", + "rss": "https://github.com/thephpleague/csv/releases.atom", + "source": "https://github.com/thephpleague/csv" + }, + "funding": [ + { + "url": "https://github.com/sponsors/nyamsprod", + "type": "github" + } + ], + "time": "2022-01-04T00:13:07+00:00" + }, { "name": "psr/cache", "version": "3.0.0", diff --git a/public/assets/css/front/frame.css b/public/assets/css/front/frame.css index e7bd387..be623b0 100644 --- a/public/assets/css/front/frame.css +++ b/public/assets/css/front/frame.css @@ -50,5 +50,6 @@ sup { color: var(--white); padding: 2px; border-radius: 3px; - vertical-align: text-bottom; + vertical-align: baseline; + font-family: var(--mono-type); } diff --git a/public/assets/css/front/index-den.css b/public/assets/css/front/index-den.css index 8005d6b..dbf7c3a 100644 --- a/public/assets/css/front/index-den.css +++ b/public/assets/css/front/index-den.css @@ -18,5 +18,10 @@ section[role="loc-index"] { section a { color: var(--white); + border-bottom: 1px solid var(--highlight); +} + +section a:hover { border-bottom: 1px solid var(--secondary); + padding-bottom: 2px; } diff --git a/src/Controller/Routes/Back/Locations.php b/src/Controller/Routes/Back/Locations.php index ddb160a..c3da8cb 100644 --- a/src/Controller/Routes/Back/Locations.php +++ b/src/Controller/Routes/Back/Locations.php @@ -12,6 +12,7 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\RequestStack; use Doctrine\Persistence\ManagerRegistry; use App\Service\HandleLocations; +use Doctrine\DBAL\Connection; //use App\Utils\PageRender; //use App\Utils\StringTools; use App\Service\Auth; @@ -36,6 +37,8 @@ class Locations extends AbstractController RequestStack $requestStack, Auth $auth, HandleLocations $locations, + ManagerRegistry $doctrine, + Connection $connection, string $pageNum ): Response { $result = $auth->status(); @@ -43,6 +46,11 @@ class Locations extends AbstractController $session = $requestStack->getSession(); $member = $session->get("member"); $list = $locations->getLocationsPage($pageNum); + + //$search = $connection->fetchAllAssociative("SELECT * FROM searchlocations('agenda')"); + + //var_dump($search[0]["name"]); + return $this->render("back/locations.twig", [ "title" => "Bad Space | Locations", "handle" => $member->getHandle(), @@ -140,6 +148,86 @@ class Locations extends AbstractController } } + /** + * @Route("/den/locations/bulk-add", name="location-bulk-add") + */ + public function bulkAddLocation( + Request $request, + Auth $auth, + HandleLocations $locations, + ManagerRegistry $doctrine, + FileUploader $uploader + ): Response { + $result = $auth->status(); + if ($result["status"]) { + if ($request->getMethod() == "GET") { + return $this->render("back/locations.twig", [ + "title" => "Bad Space | Locations | Bulk Add", + "mode" => "bulk-add" + ]); + } else { + // do posting stuff + $token = $request->get("token"); + $entityManager = $doctrine->getManager(); + $notice = ''; + + if (!$this->isCsrfTokenValid("upload", $token)) { + $logger->info("CSRF failure"); + return new Response( + "Operation not allowed", + Response::HTTP_BAD_REQUEST, + [ + "content-type" => "text/plain", + ] + ); + } + //get file from post + $file = $request->files->get("myfile"); + //grab extension + if (!empty($file)) { + $extention = substr(strrchr($file->getClientOriginalName(), "."), 1); + } + + //check it out to make sure it's cool + if ( + empty($file) || + $extention != "csv" + ) { + if (empty($file)) { + $notice = 'You didn\'t select a file, boss'; + } elseif ($extention != "csv") { + $notice = "Only files of type .csv are accepted, slick. " . $extention; + } + + return $this->render("back/locations.twig", [ + "title" => "Bad Space | Locations | Add", + "notice" => $notice, + "mode" => "bulk-add" + ]); + } + //if it's cool, send it to be processed + $response = $locations->addMultipleLocations($file, $result["id"]); + if ($response["status"]) { + $notice = "New locations added! Take a break."; + return $this->render("back/locations.twig", [ + "title" => "Bad Space | Locations | Add", + "notice" => $response["message"], + "mode" => "bulk-add" + ]); + } else { + return $this->render("back/locations.twig", [ + "title" => "Bad Space | Locations | Add", + "notice" => $response["message"], + "mode" => "bulk-add" + ]); + } + } + } else { + header("Location:/den"); + return new Response("LOGGED IN"); + } + } + /** * @Route("/den/locations/edit/{uuid}", name="location-edit") */ diff --git a/src/Service/HandleLocations.php b/src/Service/HandleLocations.php index ccd1faa..d9f10d7 100644 --- a/src/Service/HandleLocations.php +++ b/src/Service/HandleLocations.php @@ -12,6 +12,7 @@ use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Uid\Uuid; use App\Entity\Location; +use League\Csv\Reader; //use App\Utils\StringTools; @@ -139,4 +140,97 @@ class HandleLocations return $response = ["status" => false, "message" => $errorMessage]; } } + + /** + * Add new location to db + * + * @param Request $file object containing posted data + * @return Object + */ + public function addMultipleLocations($file, $memberId) + { + //read csv + $csv = Reader::createFromPath($file, "r"); + $csv->setHeaderOffset(0); + $records = $csv->getRecords(); + $recordCount = count($csv); + $duplicates = 0; + $errorMessage = null; + // Save image + + //extract data row by row + foreach ($records as $offset => $row) { + $name = $row["Name"]; + $url = $row["Url"]; + $images = $row["Images"]; + $desc = $row["Description"]; + $tags = $row["Tags"]; + $ratings = $row["Rating"]; + $imgs = explode(',', $images); + $examples = []; + + //check to see if location already exists + $list = $this->entityManager->getRepository(Location::class); + $entry = $list->findOneBy(["name" => $name]); + if ($entry) { + ++$duplicates; + } else { + $errorMessage = null; + $location = new Location(); + + $location->setName($name); + $location->setUrl($url); + $location->setDescription($desc); + $location->setTags($tags); + $location->setRating($ratings); + + //grab images, move them to dir and set image array + foreach ($imgs as $img) { + $imageName = uniqid() . ".jpg"; + $path = "../public/assets/images/examples/" . $imageName; + array_push($examples, $imageName); + file_put_contents($path, file_get_contents(trim($img))); + } + $location->setImages($examples); + + //set defaults + $location->setUuid(Uuid::v4()); + $location->setActive(false); + $location->setCreatedAt(new \DateTimeImmutable()); + $location->setUpdatedAt(new \DateTimeImmutable()); + $location->setAddedBy($memberId); + + $this->entityManager->persist($location); + } + } + + try { + $this->entityManager->flush(); + } catch (PDOException $error) { + $errorMessage = $error->getMessage(); + } catch (DBALException $error) { + $errorMessage = $error->getMessage(); + } catch (ORMException $error) { + $errorMessage = $error->getMessage(); + } catch (Exception $error) { + $errorMessage = $error->getMessage(); + } catch (SyntaxErrorException $e) { + $errorMessage = $error->getMessage(); + } + + if ($duplicates > 0) { + $message = $duplicates . " of " . $recordCount . " location entries were duplicates"; + } else { + $message = "Locations Added. Nice Job!"; + } + // return result status + if ($errorMessage == null) { + return $response = [ + "status" => true, + "message" => $message, + ]; + } else { + return $response = ["status" => false, "message" => $errorMessage]; + } + } } diff --git a/templates/back/locations.twig b/templates/back/locations.twig index dbbeb5c..c6997c2 100644 --- a/templates/back/locations.twig +++ b/templates/back/locations.twig @@ -17,18 +17,27 @@ {% if mode == "add" %}

Add New Location

{{ include("forms/add-location.twig") }} + {% elseif mode =='bulk-add' %} +

Add Multiple Locations

+ {{ include("forms/bulk-add-location.twig") }} {% elseif mode == "edit" %}

Editing {{ location.name }}

{{ include("forms/edit-location.twig") }} {% else %}

Take care. These are bad places.

- {% for location in list.locations %} - + Add Location + | + Add Multiple Locations +
+

Bad Spaces

+ {% for location in list.locations %} ID:{{ location.id }} - {{ location.name }}
- {% endfor %} - {% endif %} + - - {% endblock %} + {{ location.name }}
+ {% endfor %} + {% endif %} + + + {% endblock %} diff --git a/templates/forms/bulk-add-location.twig b/templates/forms/bulk-add-location.twig new file mode 100644 index 0000000..a58e426 --- /dev/null +++ b/templates/forms/bulk-add-location.twig @@ -0,0 +1,8 @@ +
+ +
+ +
+ + +
diff --git a/templates/forms/edit-location.twig b/templates/forms/edit-location.twig index 9b74a86..3771bd4 100644 --- a/templates/forms/edit-location.twig +++ b/templates/forms/edit-location.twig @@ -21,7 +21,16 @@ {% endif %} - +
+
+