forked from projects/thebadspace
Location Editing Part. 1
Now that full-text searching is set up in the DB, the next step is data population. The adding and editing templates were added as long as routes and base functionality to add single locations. Adding works and editing is almost there but both still need to cleaned up. The basic plumbing will be completed and then the tweaking to account for roles and login status for the sake of security. Part 2 will include clean up and and bulk uploads through the use of CSV files.
This commit is contained in:
parent
e424df18aa
commit
3410abd70a
19 changed files with 879 additions and 21 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -7,8 +7,7 @@
|
||||||
.env
|
.env
|
||||||
/config/secrets/prod/prod.decrypt.private.php
|
/config/secrets/prod/prod.decrypt.private.php
|
||||||
/public/bundles/
|
/public/bundles/
|
||||||
/public/images/avatars/
|
/public/assets/images/examples/
|
||||||
/public/images/blog/
|
|
||||||
/var/
|
/var/
|
||||||
/vendor/
|
/vendor/
|
||||||
/assets/node_modules
|
/assets/node_modules
|
||||||
|
|
36
migrations/Version20221226225509.php
Normal file
36
migrations/Version20221226225509.php
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace DoctrineMigrations;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-generated Migration: Please modify to your needs!
|
||||||
|
*/
|
||||||
|
final class Version20221226225509 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this up() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('CREATE SEQUENCE location_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
|
||||||
|
$this->addSql('CREATE TABLE location (id INT NOT NULL, uuid VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, url VARCHAR(255) NOT NULL, description TEXT NOT NULL, images JSON DEFAULT NULL, active BOOLEAN NOT NULL, rating VARCHAR(255) NOT NULL, added_by INT NOT NULL, created_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, updated_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, PRIMARY KEY(id))');
|
||||||
|
$this->addSql('COMMENT ON COLUMN location.created_at IS \'(DC2Type:datetime_immutable)\'');
|
||||||
|
$this->addSql('COMMENT ON COLUMN location.updated_at IS \'(DC2Type:datetime_immutable)\'');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this down() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('CREATE SCHEMA public');
|
||||||
|
$this->addSql('DROP SEQUENCE location_id_seq CASCADE');
|
||||||
|
$this->addSql('DROP TABLE location');
|
||||||
|
}
|
||||||
|
}
|
32
migrations/Version20221226230207.php
Normal file
32
migrations/Version20221226230207.php
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace DoctrineMigrations;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-generated Migration: Please modify to your needs!
|
||||||
|
*/
|
||||||
|
final class Version20221226230207 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this up() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('ALTER TABLE location ADD tags VARCHAR(255) NOT NULL');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this down() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('CREATE SCHEMA public');
|
||||||
|
$this->addSql('ALTER TABLE location DROP tags');
|
||||||
|
}
|
||||||
|
}
|
39
public/assets/css/front/forms.css
Normal file
39
public/assets/css/front/forms.css
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
input[type="email"],
|
||||||
|
input[type="password"],
|
||||||
|
input[type="text"] {
|
||||||
|
border: 0;
|
||||||
|
padding: 5px;
|
||||||
|
border-radius: 5px;
|
||||||
|
font: 18px var(--base-type);
|
||||||
|
display: inline-block;
|
||||||
|
background: var(--white);
|
||||||
|
color: var(--primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
border: 0;
|
||||||
|
border-radius: 3px;
|
||||||
|
color: var(--primary);
|
||||||
|
background: var(--white);
|
||||||
|
}
|
||||||
|
|
||||||
|
button,
|
||||||
|
input[type="submit"] {
|
||||||
|
background: var(--highlight);
|
||||||
|
color: var(--white);
|
||||||
|
font: 20px var(--base-type);
|
||||||
|
border-radius: 5px;
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
border: 0;
|
||||||
|
transition: all 0.3s linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
font: 20px var(--base-type);
|
||||||
|
border-radius: 5px;
|
||||||
|
border: 1px solid var(--primary);
|
||||||
|
appearance: none;
|
||||||
|
color: var(--primary);
|
||||||
|
background: var(--secondary);
|
||||||
|
}
|
|
@ -16,22 +16,39 @@ html body {
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
width: 100%;
|
||||||
|
color: var(--primary);
|
||||||
|
background: var(--secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
header > nav {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 200px 1fr;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
header > nav > div[role="nav-right"] {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
/* GLOBALS */
|
/* GLOBALS */
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: var(--primary);
|
color: var(--primary);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
border-bottom: 1px solid var(--secondary);
|
border-bottom: 1px solid var(--white);
|
||||||
transition: all 0.2s linear;
|
transition: all 0.2s linear;
|
||||||
}
|
}
|
||||||
|
|
||||||
a:hover {
|
a:hover {
|
||||||
border-bottom: 1px solid var(--highlight);
|
border-bottom: 1px solid var(--primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
sup {
|
sup {
|
||||||
background: var(--black);
|
background: var(--black);
|
||||||
color: var(--white);
|
color: var(--white);
|
||||||
padding: 3px;
|
padding: 2px;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
|
vertical-align: text-bottom;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,3 +10,13 @@ section[role="den-login"] div[role="system-notice"] {
|
||||||
background: var(--highlight);
|
background: var(--highlight);
|
||||||
color: var(--primary);
|
color: var(--primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
section[role="den-index"],
|
||||||
|
section[role="loc-index"] {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
section a {
|
||||||
|
color: var(--white);
|
||||||
|
border-bottom: 1px solid var(--secondary);
|
||||||
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ h3 {
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
font-size: 2em;
|
font-size: 2.5em;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ h2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
font-size: 1.5em;
|
font-size: 1.2em;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
167
src/Controller/Routes/Back/Locations.php
Normal file
167
src/Controller/Routes/Back/Locations.php
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// src/Controller/DataImport.php
|
||||||
|
// Grab data from transfer app
|
||||||
|
|
||||||
|
namespace App\Controller\Routes\Back;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\RequestStack;
|
||||||
|
use Doctrine\Persistence\ManagerRegistry;
|
||||||
|
use App\Service\HandleLocations;
|
||||||
|
//use App\Utils\PageRender;
|
||||||
|
//use App\Utils\StringTools;
|
||||||
|
use App\Service\Auth;
|
||||||
|
use App\Service\FileUploader;
|
||||||
|
|
||||||
|
class Locations extends AbstractController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @Route("/den/locations", name="den-reroute-index")
|
||||||
|
*/
|
||||||
|
public function rerouteIndex()
|
||||||
|
{
|
||||||
|
header("Location:/den/locations/page/1");
|
||||||
|
return new Response("<html><body>LOGGED IN</body></html>");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/den/locations/page/{pageNum}", name="den-locations")
|
||||||
|
*/
|
||||||
|
public function locationIndex(
|
||||||
|
Request $request,
|
||||||
|
RequestStack $requestStack,
|
||||||
|
Auth $auth,
|
||||||
|
HandleLocations $locations,
|
||||||
|
string $pageNum
|
||||||
|
): Response {
|
||||||
|
$result = $auth->status();
|
||||||
|
if ($result["status"]) {
|
||||||
|
$session = $requestStack->getSession();
|
||||||
|
$member = $session->get("member");
|
||||||
|
$list = $locations->getLocationsPage($pageNum);
|
||||||
|
return $this->render("back/locations.twig", [
|
||||||
|
"title" => "Bad Space | Locations",
|
||||||
|
"handle" => $member->getHandle(),
|
||||||
|
"list" => $list,
|
||||||
|
"mode" => "index"
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
return $this->render("back/index.twig", [
|
||||||
|
"title" => "Close the door behind you",
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/den/locations/add", name="location-add")
|
||||||
|
*/
|
||||||
|
public function addLocation(
|
||||||
|
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 | Add",
|
||||||
|
"mode" => "add"
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
//add new member
|
||||||
|
$token = $request->get("token");
|
||||||
|
$notice = "";
|
||||||
|
$entityManager = $doctrine->getManager();
|
||||||
|
|
||||||
|
//token check
|
||||||
|
if (!$this->isCsrfTokenValid("upload", $token)) {
|
||||||
|
$logger->info("CSRF failure");
|
||||||
|
|
||||||
|
return new Response(
|
||||||
|
"Operation not allowed",
|
||||||
|
Response::HTTP_BAD_REQUEST,
|
||||||
|
[
|
||||||
|
"content-type" => "text/plain",
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$examples = [];
|
||||||
|
$files = $request->files->get("loc_examples");
|
||||||
|
if (!empty($files)) {
|
||||||
|
for ($i = 0; $i < count($files); $i++) {
|
||||||
|
$path = $files[$i]->getClientOriginalName();
|
||||||
|
array_push($examples, ["image_index" => $i, "path" => urlencode($path)]);
|
||||||
|
$uploader->uploadExamples("../public/assets/images/examples", $files[$i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
$request->request->get("loc_name") == "" ||
|
||||||
|
$request->request->get("loc_url") == "" ||
|
||||||
|
$request->request->get("loc_desc") == "" ||
|
||||||
|
$request->request->get("loc_tags") == ""
|
||||||
|
) {
|
||||||
|
$notice = "All fields are required, champ.";
|
||||||
|
return $this->render("back/locations.twig", [
|
||||||
|
"title" => "Bad Space | Locations | Add",
|
||||||
|
"notice" => $notice,
|
||||||
|
"mode" => "add"
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
//check clear, call add method
|
||||||
|
$response = $locations->addLocation($request, $result["id"]);
|
||||||
|
if ($response["status"]) {
|
||||||
|
$notice = "New location added! Take a break.";
|
||||||
|
return $this->render("back/locations.twig", [
|
||||||
|
"title" => "Bad Space | Locations | Add",
|
||||||
|
"notice" => $notice,
|
||||||
|
"mode" => "add"
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
return $this->render("back/locations.twig", [
|
||||||
|
"title" => "Bad Space | Locations | Add",
|
||||||
|
"notice" => $response["message"],
|
||||||
|
"mode" => "add"
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//back to index to login
|
||||||
|
header("Location:/den");
|
||||||
|
return new Response("<html><body>LOGGED IN</body></html>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/den/locations/edit/{uuid}", name="location-edit")
|
||||||
|
*/
|
||||||
|
public function editLocation(
|
||||||
|
Request $request,
|
||||||
|
Auth $auth,
|
||||||
|
HandleLocations $locations,
|
||||||
|
ManagerRegistry $doctrine,
|
||||||
|
FileUploader $uploader,
|
||||||
|
string $uuid = "1"
|
||||||
|
): Response {
|
||||||
|
$result = $auth->status();
|
||||||
|
if ($result["status"]) {
|
||||||
|
$location = $locations->getLocationbyUUID($uuid);
|
||||||
|
return $this->render("back/locations.twig", [
|
||||||
|
"title" => "Bad Space | Locations | Edit",
|
||||||
|
"mode" => "edit",
|
||||||
|
"location" => $location[0]
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
header("Location:/den");
|
||||||
|
return new Response("<html><body>LOGGED IN</body></html>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -137,7 +137,7 @@ class Members extends AbstractController
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//back to index to login
|
//back to index to login
|
||||||
header("Location:/knockknock");
|
header("Location:/den");
|
||||||
return new Response("<html><body>LOGGED IN</body></html>");
|
return new Response("<html><body>LOGGED IN</body></html>");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
186
src/Entity/Location.php
Normal file
186
src/Entity/Location.php
Normal file
|
@ -0,0 +1,186 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Entity;
|
||||||
|
|
||||||
|
use App\Repository\LocationRepository;
|
||||||
|
use Doctrine\DBAL\Types\Types;
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
|
||||||
|
#[ORM\Entity(repositoryClass: LocationRepository::class)]
|
||||||
|
class Location
|
||||||
|
{
|
||||||
|
#[ORM\Id]
|
||||||
|
#[ORM\GeneratedValue]
|
||||||
|
#[ORM\Column]
|
||||||
|
private ?int $id = null;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 255)]
|
||||||
|
private ?string $uuid = null;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 255)]
|
||||||
|
private ?string $name = null;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 255)]
|
||||||
|
private ?string $url = null;
|
||||||
|
|
||||||
|
#[ORM\Column(type: Types::TEXT)]
|
||||||
|
private ?string $description = null;
|
||||||
|
|
||||||
|
#[ORM\Column(nullable: true)]
|
||||||
|
private array $images = [];
|
||||||
|
|
||||||
|
#[ORM\Column]
|
||||||
|
private ?bool $active = null;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 255)]
|
||||||
|
private ?string $rating = null;
|
||||||
|
|
||||||
|
#[ORM\Column]
|
||||||
|
private ?int $addedBy = null;
|
||||||
|
|
||||||
|
#[ORM\Column]
|
||||||
|
private ?\DateTimeImmutable $createdAt = null;
|
||||||
|
|
||||||
|
#[ORM\Column]
|
||||||
|
private ?\DateTimeImmutable $updatedAt = null;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 255)]
|
||||||
|
private ?string $tags = null;
|
||||||
|
|
||||||
|
public function getId(): ?int
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUuid(): ?string
|
||||||
|
{
|
||||||
|
return $this->uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setUuid(string $uuid): self
|
||||||
|
{
|
||||||
|
$this->uuid = $uuid;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName(): ?string
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setName(string $name): self
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUrl(): ?string
|
||||||
|
{
|
||||||
|
return $this->url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setUrl(string $url): self
|
||||||
|
{
|
||||||
|
$this->url = $url;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDescription(): ?string
|
||||||
|
{
|
||||||
|
return $this->description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDescription(string $description): self
|
||||||
|
{
|
||||||
|
$this->description = $description;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getImages(): array
|
||||||
|
{
|
||||||
|
return $this->images;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setImages(?array $images): self
|
||||||
|
{
|
||||||
|
$this->images = $images;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isActive(): ?bool
|
||||||
|
{
|
||||||
|
return $this->active;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setActive(bool $active): self
|
||||||
|
{
|
||||||
|
$this->active = $active;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRating(): ?string
|
||||||
|
{
|
||||||
|
return $this->rating;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setRating(string $rating): self
|
||||||
|
{
|
||||||
|
$this->rating = $rating;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAddedBy(): ?int
|
||||||
|
{
|
||||||
|
return $this->addedBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setAddedBy(int $addedBy): self
|
||||||
|
{
|
||||||
|
$this->addedBy = $addedBy;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCreatedAt(): ?\DateTimeImmutable
|
||||||
|
{
|
||||||
|
return $this->createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setCreatedAt(\DateTimeImmutable $createdAt): self
|
||||||
|
{
|
||||||
|
$this->createdAt = $createdAt;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUpdatedAt(): ?\DateTimeImmutable
|
||||||
|
{
|
||||||
|
return $this->updatedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setUpdatedAt(\DateTimeImmutable $updatedAt): self
|
||||||
|
{
|
||||||
|
$this->updatedAt = $updatedAt;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTags(): ?string
|
||||||
|
{
|
||||||
|
return $this->tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setTags(string $tags): self
|
||||||
|
{
|
||||||
|
$this->tags = $tags;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
66
src/Repository/LocationRepository.php
Normal file
66
src/Repository/LocationRepository.php
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Repository;
|
||||||
|
|
||||||
|
use App\Entity\Location;
|
||||||
|
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||||
|
use Doctrine\Persistence\ManagerRegistry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends ServiceEntityRepository<Location>
|
||||||
|
*
|
||||||
|
* @method Location|null find($id, $lockMode = null, $lockVersion = null)
|
||||||
|
* @method Location|null findOneBy(array $criteria, array $orderBy = null)
|
||||||
|
* @method Location[] findAll()
|
||||||
|
* @method Location[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||||
|
*/
|
||||||
|
class LocationRepository extends ServiceEntityRepository
|
||||||
|
{
|
||||||
|
public function __construct(ManagerRegistry $registry)
|
||||||
|
{
|
||||||
|
parent::__construct($registry, Location::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function save(Location $entity, bool $flush = false): void
|
||||||
|
{
|
||||||
|
$this->getEntityManager()->persist($entity);
|
||||||
|
|
||||||
|
if ($flush) {
|
||||||
|
$this->getEntityManager()->flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function remove(Location $entity, bool $flush = false): void
|
||||||
|
{
|
||||||
|
$this->getEntityManager()->remove($entity);
|
||||||
|
|
||||||
|
if ($flush) {
|
||||||
|
$this->getEntityManager()->flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * @return Location[] Returns an array of Location objects
|
||||||
|
// */
|
||||||
|
// public function findByExampleField($value): array
|
||||||
|
// {
|
||||||
|
// return $this->createQueryBuilder('l')
|
||||||
|
// ->andWhere('l.exampleField = :val')
|
||||||
|
// ->setParameter('val', $value)
|
||||||
|
// ->orderBy('l.id', 'ASC')
|
||||||
|
// ->setMaxResults(10)
|
||||||
|
// ->getQuery()
|
||||||
|
// ->getResult()
|
||||||
|
// ;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public function findOneBySomeField($value): ?Location
|
||||||
|
// {
|
||||||
|
// return $this->createQueryBuilder('l')
|
||||||
|
// ->andWhere('l.exampleField = :val')
|
||||||
|
// ->setParameter('val', $value)
|
||||||
|
// ->getQuery()
|
||||||
|
// ->getOneOrNullResult()
|
||||||
|
// ;
|
||||||
|
// }
|
||||||
|
}
|
|
@ -81,16 +81,23 @@ class Auth
|
||||||
public function status()
|
public function status()
|
||||||
{
|
{
|
||||||
$response = [];
|
$response = [];
|
||||||
|
//checks to see if member session exists
|
||||||
if ($this->session->get("member")) {
|
if ($this->session->get("member")) {
|
||||||
//$member = $this->session->get("member");
|
//checks if token is still valid
|
||||||
|
$verify = Token::validateExpiration($this->session->get("token"), $this->secret);
|
||||||
|
if ($verify) {
|
||||||
$response = [
|
$response = [
|
||||||
"status" => true,
|
"status" => true,
|
||||||
"role" => $this->session->get("member")->getRole(),
|
"role" => $this->session->get("member")->getRole(),
|
||||||
|
"id" => $this->session->get("member")->getId(),
|
||||||
"token" => $this->session->get("token"),
|
"token" => $this->session->get("token"),
|
||||||
];
|
];
|
||||||
} else {
|
} else {
|
||||||
$response = ["status" => false, "role" => null];
|
$response = ["status" => false, "role" => null];
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
$response = ["status" => false, "role" => null];
|
||||||
|
}
|
||||||
|
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
46
src/Service/FileUploader.php
Normal file
46
src/Service/FileUploader.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Service;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\File\Exception\FileException;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
|
class FileUploader
|
||||||
|
{
|
||||||
|
private $logger;
|
||||||
|
|
||||||
|
public function __construct(LoggerInterface $logger)
|
||||||
|
{
|
||||||
|
$this->logger = $logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function upload($uploadDir, $file, $filename)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$file->move($uploadDir, $filename);
|
||||||
|
} catch (FileException $e) {
|
||||||
|
$this->logger->error("failed to upload image: " . $e->getMessage());
|
||||||
|
throw new FileException("Failed to upload file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function uploadExamples($examplesDir, $file)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$file->move($examplesDir, urldecode($file->getClientOriginalName()));
|
||||||
|
} catch (FileException $e) {
|
||||||
|
$this->logger->error("failed to upload image: " . $e->getMessage());
|
||||||
|
throw new FileException("Failed to upload image file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function uploadAvatar($avatarsDir, $file)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$file->move($avatarsDir, $file->getClientOriginalName());
|
||||||
|
} catch (FileException $e) {
|
||||||
|
$this->logger->error("failed to upload image: " . $e->getMessage());
|
||||||
|
throw new FileException("Failed to upload image file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
142
src/Service/HandleLocations.php
Normal file
142
src/Service/HandleLocations.php
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// src/Controller/ProductController.php
|
||||||
|
|
||||||
|
namespace App\Service;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\DBALException;
|
||||||
|
use Doctrine\ORM\ORMException;
|
||||||
|
use PDOException;
|
||||||
|
use Exception;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Symfony\Component\HttpFoundation\RequestStack;
|
||||||
|
use Symfony\Component\Uid\Uuid;
|
||||||
|
use App\Entity\Location;
|
||||||
|
|
||||||
|
//use App\Utils\StringTools;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Members
|
||||||
|
*
|
||||||
|
* Data class for interacting with Member data from the DB
|
||||||
|
*/
|
||||||
|
class HandleLocations
|
||||||
|
{
|
||||||
|
private $session;
|
||||||
|
private $entityManager;
|
||||||
|
private $limit = 4;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
EntityManagerInterface $entityManager,
|
||||||
|
RequestStack $requestStack
|
||||||
|
) {
|
||||||
|
$this->entityManager = $entityManager;
|
||||||
|
$this->session = $requestStack->getSession();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getActiveLocations()
|
||||||
|
{
|
||||||
|
$listings = $this->entityManager->getRepository(Location::class);
|
||||||
|
$locations = $listings->findBy(["active" => true]);
|
||||||
|
|
||||||
|
return $locations;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLocationByUUID(string $uuid)
|
||||||
|
{
|
||||||
|
return $this->entityManager->getRepository(Location::class)->findBy(["uuid" => $uuid]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLocationsPage(int $page)
|
||||||
|
{
|
||||||
|
$locations = $this->entityManager->getRepository(Location::class);
|
||||||
|
$list = $locations->findBy(
|
||||||
|
[],
|
||||||
|
["id" => "ASC"]
|
||||||
|
);
|
||||||
|
|
||||||
|
$count = ceil(count($list) / $this->limit);
|
||||||
|
$totalCount = count($list);
|
||||||
|
|
||||||
|
$shelf = [];
|
||||||
|
$range = $page * $this->limit - $this->limit;
|
||||||
|
for ($i = 0; $i <= $this->limit; $i++) {
|
||||||
|
try {
|
||||||
|
array_push($shelf, $list[$i + $range]);
|
||||||
|
} catch (Exception $error) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
"locations" => $shelf,
|
||||||
|
"total" => $count,
|
||||||
|
"totalLocations" => $totalCount,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add new location to db
|
||||||
|
*
|
||||||
|
* @param Request $request object containing posted data
|
||||||
|
* @return JSON
|
||||||
|
*/
|
||||||
|
public function addLocation($request, $memberId)
|
||||||
|
{
|
||||||
|
$errorMessage = null;
|
||||||
|
$location = new Location();
|
||||||
|
|
||||||
|
//submitted values
|
||||||
|
$name = $request->request->get("loc_name");
|
||||||
|
$location->setName($name);
|
||||||
|
$url = $request->request->get("loc_url");
|
||||||
|
$location->setUrl($url);
|
||||||
|
$desc = $request->request->get("loc_desc");
|
||||||
|
$location->setDescription($desc);
|
||||||
|
$tags = $request->request->get("loc_tags");
|
||||||
|
$location->setTags($tags);
|
||||||
|
$rating = $request->request->get("rating");
|
||||||
|
$location->setRating($rating);
|
||||||
|
//get images
|
||||||
|
$files = $request->files->get("loc_examples");
|
||||||
|
if (!empty($files)) {
|
||||||
|
$examples = [];
|
||||||
|
for ($i = 0; $i < count($files); $i++) {
|
||||||
|
$path = $files[$i]->getClientOriginalName();
|
||||||
|
array_push($examples, ["image_index" => $i, "path" => urlencode($path)]);
|
||||||
|
}
|
||||||
|
$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();
|
||||||
|
}
|
||||||
|
// return result status
|
||||||
|
if ($errorMessage == null) {
|
||||||
|
return $response = [
|
||||||
|
"status" => true,
|
||||||
|
"message" => "New member added. Woohoo!",
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
return $response = ["status" => false, "message" => $errorMessage];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
34
templates/back/locations.twig
Normal file
34
templates/back/locations.twig
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
{% extends "base/frame.twig" %}
|
||||||
|
{% block stylesheets %}
|
||||||
|
<link rel="stylesheet" type="text/css" href="/assets/css/front/start.css?=sdfsdf">
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<section role="loc-index">
|
||||||
|
<h1>
|
||||||
|
Location Listing
|
||||||
|
</h1>
|
||||||
|
{% if notice is defined %}
|
||||||
|
<div role="system-notice">
|
||||||
|
{{ notice }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if mode == "add" %}
|
||||||
|
<h2>Add New Location</h2>
|
||||||
|
{{ include("forms/add-location.twig") }}
|
||||||
|
{% elseif mode == "edit" %}
|
||||||
|
<h2>Editing
|
||||||
|
{{ location.name }}</h2>
|
||||||
|
{{ include("forms/edit-location.twig") }}
|
||||||
|
{% else %}
|
||||||
|
<h2>Take care. These are bad places.</h2>
|
||||||
|
{% for location in list.locations %}
|
||||||
|
<a href="/den/locations/edit/{{ location.uuid }}">
|
||||||
|
<sup>ID:{{ location.id }}</sup>
|
||||||
|
{{ location.name }}</a><br/>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
</section>
|
||||||
|
{% endblock %}
|
|
@ -1,17 +1,14 @@
|
||||||
{% extends "base/frame.twig" %}
|
{% extends "base/frame.twig" %}
|
||||||
{% block stylesheets %}
|
{% block stylesheets %}
|
||||||
<link rel="stylesheet" type="text/css" href="/assets/css/front/start.css?=sdfsdf">
|
<link rel="stylesheet" type="text/css" href="/assets/css/front/start.css?=dfdferer">
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<section>
|
<section role="den-index">
|
||||||
<h1>
|
<h1>
|
||||||
Welcome to the Den.
|
Welcome to the Den.
|
||||||
</h1>
|
|
||||||
Hey
|
|
||||||
{{ handle }}
|
|
||||||
. Nice to see you again.
|
|
||||||
<a href="/logout">Bye bye</a>
|
|
||||||
|
|
||||||
|
</h1>
|
||||||
|
Remember to pace yourself because you're working with some of the worse places on the web. Drink water, takes lot of breaks and remember you are the reason the interent is becoming safer.
|
||||||
</section>
|
</section>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -10,6 +10,28 @@
|
||||||
{% block stylesheets %}{% endblock %}
|
{% block stylesheets %}{% endblock %}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<header>
|
||||||
|
<nav>
|
||||||
|
<div role="nav-left">
|
||||||
|
<a href="/den">The Bad Space</a>
|
||||||
|
</div>
|
||||||
|
<div role="nav-right">
|
||||||
|
|
||||||
|
{% if handle is defined %}
|
||||||
|
<strong>Hey
|
||||||
|
{{ handle }}
|
||||||
|
</strong>
|
||||||
|
{% endif %}
|
||||||
|
<a href="/den/members">Members
|
||||||
|
</a>
|
||||||
|
<a href="/den/locations/page/1">Locations
|
||||||
|
</a>
|
||||||
|
<a href="/logout">Bye</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
</header>
|
||||||
<main>
|
<main>
|
||||||
{% block main %}{% endblock %}
|
{% block main %}{% endblock %}
|
||||||
</main>
|
</main>
|
||||||
|
|
27
templates/forms/add-location.twig
Normal file
27
templates/forms/add-location.twig
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<form action="{{ path('location-add') }}" method="post" enctype="multipart/form-data">
|
||||||
|
<div>
|
||||||
|
<label>Name</label><br/>
|
||||||
|
<input type="text" name="loc_name" value=""/>
|
||||||
|
<br/>
|
||||||
|
<label>URL</label><br/>
|
||||||
|
<input type="text" name="loc_url" value=""/>
|
||||||
|
<br/>
|
||||||
|
<label>Tags</label><br/>
|
||||||
|
<input type="text" name="loc_tags" value=""/>
|
||||||
|
<br/>
|
||||||
|
<label>Description</label><br/>
|
||||||
|
<textarea name="loc_desc"></textarea>
|
||||||
|
<br/>
|
||||||
|
<label>Rating</label><br/>
|
||||||
|
<select name="rating">
|
||||||
|
<option value="" disabled selected>Choose Rating
|
||||||
|
</option>
|
||||||
|
<option value="silence">Silence</option>
|
||||||
|
<option value="defederate">Defederate</option>
|
||||||
|
</select>
|
||||||
|
<br/>
|
||||||
|
<label>Images</label><br/>
|
||||||
|
<input type="file" id="loc_examples" name="loc_examples[]" multiple/>
|
||||||
|
</div>
|
||||||
|
<input type="hidden" name="token" value="{{ csrf_token('upload') }}"/>
|
||||||
|
<input type="submit" value="Edit Location" name="submit_button"></form>
|
31
templates/forms/edit-location.twig
Normal file
31
templates/forms/edit-location.twig
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
<form action="{{ path('location-edit') }}" method="post" enctype="multipart/form-data">
|
||||||
|
<div>
|
||||||
|
<label>Name</label><br/>
|
||||||
|
<input type="text" name="loc_name" value="{{ location.name }}"/>
|
||||||
|
<br/>
|
||||||
|
<label>URL</label><br/>
|
||||||
|
<input type="text" name="loc_url" value="{{ location.url }}"/>
|
||||||
|
<br/>
|
||||||
|
<label>Tags</label><br/>
|
||||||
|
<input type="text" name="loc_tags" value="{{ location.tags }}"/>
|
||||||
|
<br/>
|
||||||
|
<label>Description</label><br/>
|
||||||
|
<textarea name="loc_desc">{{ location.description }}</textarea>
|
||||||
|
<br/>
|
||||||
|
<label>Rating</label><br/>
|
||||||
|
<select name="rating">
|
||||||
|
{% if location.rating == "silence" %}
|
||||||
|
<option value="silence" selected>Silence</option>
|
||||||
|
<option value="defederate">Defederate</option>
|
||||||
|
{% else %}
|
||||||
|
<option value="silence">Silence</option>
|
||||||
|
<option value="defederate" selected>Defederate</option>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
</select>
|
||||||
|
<br/>
|
||||||
|
<label>Images</label><br/>
|
||||||
|
<input type="file" id="loc_examples" name="loc_examples[]" multiple/>
|
||||||
|
</div>
|
||||||
|
<input type="hidden" name="token" value="{{ csrf_token('upload') }}"/>
|
||||||
|
<input type="submit" value="Edit Location" name="submit_button"></form>
|
Loading…
Reference in a new issue