Added navbar and button to skip automatic search of book info online.
This commit is contained in:
@@ -1,14 +1,20 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="row g-3 align-items-center">
|
<div class="row g-3 align-items-center" v-if="!manualMode">
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
<input name="searchTerm" class="input form-control" placeholder="book title to search" @keypress.enter="search"
|
<input name="searchTerm" class="input form-control" placeholder="book title to search" @keypress.enter="search"
|
||||||
v-model="searchTerm" type="text"/>
|
v-model="searchTerm" type="text"/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
<button class="btn btn-info" @click="search">Szukaj</button>
|
<button class="btn btn-info" @click="search">Szukaj</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row mt-4" v-if="!manualMode">
|
||||||
|
<div class="col-auto">
|
||||||
|
<a class="link-primary cursor-pointer" @click="manualMode=true">Let me fill in data manually</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div v-if="selectedBook && selectedBook.cover_url.small">
|
<div v-if="selectedBook && selectedBook.cover_url.small">
|
||||||
<img :src="selectedBook.cover_url.small" class="img-thumbnail"/>
|
<img :src="selectedBook.cover_url.small" class="img-thumbnail"/>
|
||||||
</div>
|
</div>
|
||||||
@@ -23,7 +29,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<h1 v-else>Oh no 😢</h1>
|
<h1 v-else>Oh no 😢</h1>
|
||||||
|
|
||||||
<div v-show="manualMode" >
|
<div v-show="manualMode">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
<BookForm></BookForm>
|
<BookForm></BookForm>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class BookController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/new', name: 'app_book_new', methods: ['GET', 'POST'])]
|
#[Route('/new', name: 'app_book_new', methods: ['GET', 'POST'])]
|
||||||
public function new(Request $request, BookRepository $bookRepository): Response
|
public function new(Request $request, BookRepository $bookRepository, FileService $fileService): Response
|
||||||
{
|
{
|
||||||
$book = new Book();
|
$book = new Book();
|
||||||
$form = $this->createForm(BookType::class, $book);
|
$form = $this->createForm(BookType::class, $book);
|
||||||
@@ -55,15 +55,15 @@ class BookController extends AbstractController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$ebook = $request->files->get('book')['ebook'];
|
/** @var UploadedFile[] $ebooks */
|
||||||
if ($ebook) {
|
$ebooks = $request->files->get('book')['ebook'];
|
||||||
$ebook->move(
|
if (count($ebooks) > 0) {
|
||||||
$this->getParameter('book_files'),
|
foreach ($ebooks as $ebook) {
|
||||||
'ebook_' . $book->getId() . '.' . $ebook->guessClientExtension()
|
$fileService->saveFile($ebook, $book);
|
||||||
);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->redirectToRoute('app_book_index', [], Response::HTTP_SEE_OTHER);
|
return $this->redirectToRoute('app_book_index', status: Response::HTTP_SEE_OTHER);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->renderForm('book/new.html.twig', [
|
return $this->renderForm('book/new.html.twig', [
|
||||||
@@ -87,8 +87,12 @@ class BookController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/{id}', name: 'app_book_show', methods: ['GET', 'POST'])]
|
#[Route('/{id}', name: 'app_book_show', methods: ['GET', 'POST'])]
|
||||||
public function show(Book $book, Request $request, FileRepository $fileRepository, FileService $fileService): Response
|
public function show(
|
||||||
{
|
Book $book,
|
||||||
|
Request $request,
|
||||||
|
FileRepository $fileRepository,
|
||||||
|
FileService $fileService
|
||||||
|
): Response {
|
||||||
$fileForm = $this->createForm(FileType::class);
|
$fileForm = $this->createForm(FileType::class);
|
||||||
$fileForm->handleRequest($request);
|
$fileForm->handleRequest($request);
|
||||||
|
|
||||||
@@ -150,7 +154,7 @@ class BookController extends AbstractController
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/{id}', name: 'app_book_delete', methods: ['POST'])]
|
#[Route('/{id}/delete', name: 'app_book_delete', methods: ['POST'])]
|
||||||
public function delete(
|
public function delete(
|
||||||
Request $request,
|
Request $request,
|
||||||
Book $book,
|
Book $book,
|
||||||
@@ -162,6 +166,6 @@ class BookController extends AbstractController
|
|||||||
$bookRepository->remove($book, true);
|
$bookRepository->remove($book, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->redirectToRoute('app_book_index', [], Response::HTTP_SEE_OTHER);
|
return $this->redirectToRoute('app_book_index', status: Response::HTTP_SEE_OTHER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ namespace App\Controller;
|
|||||||
use App\Entity\Book;
|
use App\Entity\Book;
|
||||||
use App\Entity\File;
|
use App\Entity\File;
|
||||||
use App\Repository\FileRepository;
|
use App\Repository\FileRepository;
|
||||||
|
use App\Service\FileService;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\Filesystem\Filesystem;
|
use Symfony\Component\Filesystem\Filesystem;
|
||||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||||
@@ -27,27 +28,16 @@ class FileController extends AbstractController
|
|||||||
Request $request,
|
Request $request,
|
||||||
FileRepository $fileRepository,
|
FileRepository $fileRepository,
|
||||||
File $file,
|
File $file,
|
||||||
Filesystem $filesystem
|
FileService $fileService
|
||||||
): Response {
|
): Response {
|
||||||
$filePath = $this->getParameter('book_files') . '/' . 'ebook_' . $file->getBook()->getId() . '_' .
|
$fileService->removeFiles($file);
|
||||||
md5($file->getFileName()) . '.' .
|
|
||||||
$file->getExtension();
|
|
||||||
$filesystem->remove($filePath);
|
|
||||||
|
|
||||||
if (!$filesystem->exists($filePath)) {
|
|
||||||
$fileRepository->remove($file, 'true');
|
$fileRepository->remove($file, 'true');
|
||||||
}
|
|
||||||
return $this->redirect($request->headers->get('referer'));
|
return $this->redirect($request->headers->get('referer'));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/file/{id}', name: 'app_file_download', methods: ['GET'])]
|
#[Route('/file/{id}', name: 'app_file_download', methods: ['GET'])]
|
||||||
public function get(File $file)
|
public function get(File $file, FileService $fileService)
|
||||||
{
|
{
|
||||||
return $this->file(
|
return $this->file($fileService->getFilePath($file), $file->getFileName());
|
||||||
$this->getParameter('book_files') . '/' . 'ebook_' . $file->getBook()->getId() . '_' .
|
|
||||||
md5($file->getFileName()) . '.' .
|
|
||||||
$file->getExtension(),
|
|
||||||
$file->getFileName()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ namespace App\Service;
|
|||||||
use App\Entity\Book;
|
use App\Entity\Book;
|
||||||
use App\Entity\File;
|
use App\Entity\File;
|
||||||
use App\Repository\FileRepository;
|
use App\Repository\FileRepository;
|
||||||
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
use Doctrine\Common\Collections\Collection;
|
use Doctrine\Common\Collections\Collection;
|
||||||
use Symfony\Component\Filesystem\Filesystem;
|
use Symfony\Component\Filesystem\Filesystem;
|
||||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||||
@@ -23,11 +24,15 @@ class FileService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Collection $files
|
* @param Collection|File $files
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function removeFiles(Collection $files)
|
public function removeFiles(Collection|File $files)
|
||||||
{
|
{
|
||||||
|
if (!$files instanceof Collection) {
|
||||||
|
$files = new ArrayCollection([$files]);
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($files as $file) {
|
foreach ($files as $file) {
|
||||||
$this->fileSystem->remove($this->getFilePath($file));
|
$this->fileSystem->remove($this->getFilePath($file));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,48 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
|
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<a class="navbar-brand" href="{{ path('app_book_index') }}">Biblio</a>
|
||||||
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent"
|
||||||
|
aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||||
|
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link active" aria-current="page" href="{{ path('app_book_index') }}">Home</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="#">Link</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item dropdown">
|
||||||
|
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button"
|
||||||
|
data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
|
Dropdown
|
||||||
|
</a>
|
||||||
|
<ul class="dropdown-menu" aria-labelledby="navbarDropdown">
|
||||||
|
<li><a class="dropdown-item" href="#">Action</a></li>
|
||||||
|
<li><a class="dropdown-item" href="#">Another action</a></li>
|
||||||
|
<li>
|
||||||
|
<hr class="dropdown-divider">
|
||||||
|
</li>
|
||||||
|
<li><a class="dropdown-item" href="#">Something else here</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a href="{{ path('app_book_new') }}" class="btn btn-primary">Add new book</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<form class="d-flex">
|
||||||
|
<input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
|
||||||
|
<button class="btn btn-outline-success" type="submit">Search</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
{% block body %}{% endblock %}
|
{% block body %}{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,10 +5,10 @@
|
|||||||
{% block body %}
|
{% block body %}
|
||||||
<div class="d-flex flex-row justify-content-between align-items-center">
|
<div class="d-flex flex-row justify-content-between align-items-center">
|
||||||
<div>
|
<div>
|
||||||
<h1>Book index</h1>
|
<h1>Book list</h1>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a href="{{ path('app_book_new') }}" class="btn btn-primary">Create new</a>
|
<a href="{{ path('app_book_new') }}" class="btn btn-primary">Add new</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
{% block title %}New Book{% endblock %}
|
{% block title %}New Book{% endblock %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<h1>Create new Book</h1>
|
<h1>Add new book</h1>
|
||||||
<div id="app">
|
<div id="app">
|
||||||
<book>
|
<book>
|
||||||
{{ include('book/_form.html.twig') }}
|
{{ include('book/_form.html.twig') }}
|
||||||
|
|||||||
Reference in New Issue
Block a user