Add attachments, more pages
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This commit is contained in:
parent
d086b29bcc
commit
a1ac81a73a
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\Book;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
class BookController extends Controller {
|
class BookController extends Controller {
|
||||||
|
@ -40,7 +41,13 @@ class BookController extends Controller {
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\Response
|
||||||
*/
|
*/
|
||||||
public function show($id) {
|
public function show($id) {
|
||||||
//
|
$book = Book::find($id);
|
||||||
|
|
||||||
|
if (!$book) {
|
||||||
|
abort(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
return view('books.show', [ 'book' => $book ]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -71,6 +78,16 @@ class BookController extends Controller {
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\Response
|
||||||
*/
|
*/
|
||||||
public function destroy($id) {
|
public function destroy($id) {
|
||||||
//
|
$book = Book::find($id);
|
||||||
|
|
||||||
|
if (!$book) {
|
||||||
|
abort(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
$book->delete();
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ class LocationController extends Controller {
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\Response
|
||||||
*/
|
*/
|
||||||
public function index() {
|
public function index() {
|
||||||
//
|
return view('locations.index', [ 'locations' => Location::paginate(15) ]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -47,7 +47,7 @@ class LocationController extends Controller {
|
||||||
abort(404);
|
abort(404);
|
||||||
}
|
}
|
||||||
|
|
||||||
return view('location', [ 'location' => $location ]);
|
return view('locations.show', [ 'location' => $location, 'rows' => $location->books()->paginate(15) ]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -2,20 +2,31 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\Book;
|
||||||
|
use App\Services\BookInformation\BookLookupService;
|
||||||
use Cache;
|
use Cache;
|
||||||
use App\Services\BookInformation\GoogleBooks;
|
|
||||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
|
||||||
|
|
||||||
class LookupController {
|
class LookupController {
|
||||||
public function lookup($isbn) {
|
public function lookup(BookLookupService $service, $isbn) {
|
||||||
if (!preg_match('/^(\d+)$/', $isbn)) {
|
$result = $service->lookup($isbn);
|
||||||
throw new HttpException(400);
|
|
||||||
|
$arr = [
|
||||||
|
'success' => false
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($result) {
|
||||||
|
$arr = array_merge($arr, [
|
||||||
|
'success' => true,
|
||||||
|
'data' => $result
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Cache::remember('isbn_' . $isbn, 86400, function() use ($isbn) {
|
$book = Book::where('barcode', $isbn)->first();
|
||||||
$google_books = new GoogleBooks();
|
|
||||||
|
|
||||||
return $google_books->lookup($isbn);
|
if ($book) {
|
||||||
});
|
$arr['warning'] = 'Item already exists.<br />Location: ' . $book->location->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json($arr);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,6 +5,9 @@ namespace App\Http\Controllers;
|
||||||
use App\Models\Author;
|
use App\Models\Author;
|
||||||
use App\Models\Book;
|
use App\Models\Book;
|
||||||
use App\Models\Location;
|
use App\Models\Location;
|
||||||
|
use App\Services\BookInformation\BookLookupService;
|
||||||
|
use App\Services\BookInformation\GoogleBooks;
|
||||||
|
use GuzzleHttp\Client;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
|
|
||||||
|
@ -16,24 +19,21 @@ class MainController extends Controller {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function search(Request $request) {
|
public function search(Request $request) {
|
||||||
$this->validate($request, [
|
$rows = Book::search($request->get('query'))->paginate(15);
|
||||||
'query' => [ 'required' ]
|
|
||||||
]);
|
|
||||||
|
|
||||||
$rows = Book::where('name', 'LIKE', '%' . $request->get('query') . '%')->paginate(15);
|
|
||||||
|
|
||||||
return view('index', [ 'rows' => $rows ]);
|
return view('index', [ 'rows' => $rows ]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function add(Request $request) {
|
public function add(Request $request) {
|
||||||
return view('add', [
|
return view('add', [
|
||||||
|
'locations' => Location::get(),
|
||||||
'old' => array_filter($request->old('books', []), function($item) {
|
'old' => array_filter($request->old('books', []), function($item) {
|
||||||
return !empty($item['barcode']);
|
return !empty($item['barcode']);
|
||||||
})
|
})
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function save(Request $request) {
|
public function save(Request $request, BookLookupService $service) {
|
||||||
$this->validate($request, [
|
$this->validate($request, [
|
||||||
'location' => [ 'required' ]
|
'location' => [ 'required' ]
|
||||||
]);
|
]);
|
||||||
|
@ -69,6 +69,39 @@ class MainController extends Controller {
|
||||||
$authors = array_map(function($author) { return $author->id; }, $authors);
|
$authors = array_map(function($author) { return $author->id; }, $authors);
|
||||||
|
|
||||||
$book->authors()->attach($authors);
|
$book->authors()->attach($authors);
|
||||||
|
|
||||||
|
// Lookup info from cache
|
||||||
|
$res = $service->lookup($item['barcode']);
|
||||||
|
|
||||||
|
if (!empty($res)) {
|
||||||
|
if ($thumbnail = data_get('images.thumbnail', $res)) {
|
||||||
|
$file = $this->downloadFile($thumbnail);
|
||||||
|
|
||||||
|
$book->attach('thumbnail', $file);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Download a file and return the local temp path.
|
||||||
|
*
|
||||||
|
* @param $url
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
private function downloadFile($url) {
|
||||||
|
$client = new Client();
|
||||||
|
|
||||||
|
$path = tempnam(storage_path('app/temp'), 'image');
|
||||||
|
|
||||||
|
$res = $client->get($url, [
|
||||||
|
'sink' => $path
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($res->getStatusCode() != 200) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,12 +3,13 @@
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Services\Search\BookConfigurator;
|
use App\Services\Search\BookConfigurator;
|
||||||
|
use Bnb\Laravel\Attachments\HasAttachment;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use ScoutElastic\Searchable;
|
use ScoutElastic\Searchable;
|
||||||
|
|
||||||
class Book extends Model {
|
class Book extends Model {
|
||||||
|
|
||||||
use Searchable;
|
use Searchable, HasAttachment;
|
||||||
|
|
||||||
protected $indexConfigurator = BookConfigurator::class;
|
protected $indexConfigurator = BookConfigurator::class;
|
||||||
|
|
||||||
|
|
|
@ -14,4 +14,8 @@ class Location extends Model {
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'name',
|
'name',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public function books() {
|
||||||
|
return $this->hasMany(Book::class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,9 @@
|
||||||
|
|
||||||
namespace App\Providers;
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use App\Services\BookInformation\BookLookupService;
|
||||||
|
use App\Services\BookInformation\CachedService;
|
||||||
|
use App\Services\BookInformation\GoogleBooks;
|
||||||
use Illuminate\Pagination\Paginator;
|
use Illuminate\Pagination\Paginator;
|
||||||
use Schema;
|
use Schema;
|
||||||
use Illuminate\Support\ServiceProvider;
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
@ -23,6 +26,8 @@ class AppServiceProvider extends ServiceProvider {
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function register() {
|
public function register() {
|
||||||
//
|
$this->app->singleton(BookLookupService::class, function() {
|
||||||
|
return new CachedService(new GoogleBooks());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\BookInformation;
|
||||||
|
|
||||||
|
use Cache;
|
||||||
|
|
||||||
|
class CachedService implements BookLookupService {
|
||||||
|
private $service;
|
||||||
|
|
||||||
|
public function __construct($service) {
|
||||||
|
$this->service = $service;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function lookup($isbn) {
|
||||||
|
return Cache::remember('isbn_' . $isbn, 86400, function() use ($isbn) {
|
||||||
|
return $this->service->lookup($isbn);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,9 +22,10 @@ class GoogleBooks implements BookLookupService {
|
||||||
*/
|
*/
|
||||||
$volume = Arr::first($results->getItems())->getVolumeInfo();
|
$volume = Arr::first($results->getItems())->getVolumeInfo();
|
||||||
|
|
||||||
return [
|
return (object) [
|
||||||
'title' => $volume->getTitle(),
|
'title' => $volume->getTitle(),
|
||||||
'authors' => $volume->getAuthors()
|
'authors' => $volume->getAuthors(),
|
||||||
|
'images' => $volume->getImageLinks(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,6 +7,7 @@
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^7.3|^8.0",
|
"php": "^7.3|^8.0",
|
||||||
"babenkoivan/scout-elasticsearch-driver": "^4.2",
|
"babenkoivan/scout-elasticsearch-driver": "^4.2",
|
||||||
|
"bnbwebexpertise/laravel-attachments": "^1.0",
|
||||||
"fideloper/proxy": "^4.4",
|
"fideloper/proxy": "^4.4",
|
||||||
"fruitcake/laravel-cors": "^2.0",
|
"fruitcake/laravel-cors": "^2.0",
|
||||||
"google/apiclient": "^2.2",
|
"google/apiclient": "^2.2",
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "10a519557c1fd55683da44313588c40e",
|
"content-hash": "7921640c91682ddbd453b7e9bb3f8e2c",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "asm89/stack-cors",
|
"name": "asm89/stack-cors",
|
||||||
|
@ -119,6 +119,107 @@
|
||||||
],
|
],
|
||||||
"time": "2020-08-13T17:57:09+00:00"
|
"time": "2020-08-13T17:57:09+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "bnbwebexpertise/laravel-attachments",
|
||||||
|
"version": "1.0.22",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/bnbwebexpertise/laravel-attachments.git",
|
||||||
|
"reference": "d3f4aa024449ad938d564aede64d05e19bfc5ff5"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/bnbwebexpertise/laravel-attachments/zipball/d3f4aa024449ad938d564aede64d05e19bfc5ff5",
|
||||||
|
"reference": "d3f4aa024449ad938d564aede64d05e19bfc5ff5",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"bnbwebexpertise/php-uuid": ">=0.0.2",
|
||||||
|
"doctrine/dbal": "~2.5",
|
||||||
|
"illuminate/console": ">=5.5",
|
||||||
|
"illuminate/database": ">=5.5",
|
||||||
|
"illuminate/encryption": ">=5.5",
|
||||||
|
"illuminate/routing": ">=5.5",
|
||||||
|
"illuminate/support": ">=5.5",
|
||||||
|
"nesbot/carbon": "^1.20 || ^2.0",
|
||||||
|
"php": ">=7.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"laravel/framework": ">=5.5"
|
||||||
|
},
|
||||||
|
"type": "package",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "1.x-dev",
|
||||||
|
"dev-L5.4": "0.x-dev"
|
||||||
|
},
|
||||||
|
"laravel": {
|
||||||
|
"providers": [
|
||||||
|
"Bnb\\Laravel\\Attachments\\AttachmentsServiceProvider"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Bnb\\Laravel\\Attachments\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "B&B Web Expertise",
|
||||||
|
"email": "support@bnb.re"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Attach files to your models, retrievable by key, group name or using the Eloquent relationship.",
|
||||||
|
"time": "2020-06-24T15:19:20+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "bnbwebexpertise/php-uuid",
|
||||||
|
"version": "0.0.3",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/bnbwebexpertise/php-uuid.git",
|
||||||
|
"reference": "d60bf8054db1d062f2fc79c43af0ff499a49fbfa"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/bnbwebexpertise/php-uuid/zipball/d60bf8054db1d062f2fc79c43af0ff499a49fbfa",
|
||||||
|
"reference": "d60bf8054db1d062f2fc79c43af0ff499a49fbfa",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-bcmath": "*",
|
||||||
|
"php": ">=5.5"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^4.0"
|
||||||
|
},
|
||||||
|
"type": "package",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Bnb\\Uuid\\": "src/"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"src/helpers.php"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "B&B Web Expertise",
|
||||||
|
"email": "support@bnb.re"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "UUID helpers",
|
||||||
|
"time": "2017-11-18T13:18:41+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "brick/math",
|
"name": "brick/math",
|
||||||
"version": "0.9.1",
|
"version": "0.9.1",
|
||||||
|
@ -204,6 +305,299 @@
|
||||||
"description": "implementation of xdg base directory specification for php",
|
"description": "implementation of xdg base directory specification for php",
|
||||||
"time": "2019-12-04T15:06:13+00:00"
|
"time": "2019-12-04T15:06:13+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "doctrine/cache",
|
||||||
|
"version": "1.10.2",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/doctrine/cache.git",
|
||||||
|
"reference": "13e3381b25847283a91948d04640543941309727"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/doctrine/cache/zipball/13e3381b25847283a91948d04640543941309727",
|
||||||
|
"reference": "13e3381b25847283a91948d04640543941309727",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "~7.1 || ^8.0"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"doctrine/common": ">2.2,<2.4"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"alcaeus/mongo-php-adapter": "^1.1",
|
||||||
|
"doctrine/coding-standard": "^6.0",
|
||||||
|
"mongodb/mongodb": "^1.1",
|
||||||
|
"phpunit/phpunit": "^7.0",
|
||||||
|
"predis/predis": "~1.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"alcaeus/mongo-php-adapter": "Required to use legacy MongoDB driver"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "1.9.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Guilherme Blanco",
|
||||||
|
"email": "guilhermeblanco@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Roman Borschel",
|
||||||
|
"email": "roman@code-factory.org"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Benjamin Eberlei",
|
||||||
|
"email": "kontakt@beberlei.de"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jonathan Wage",
|
||||||
|
"email": "jonwage@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Johannes Schmitt",
|
||||||
|
"email": "schmittjoh@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "PHP Doctrine Cache library is a popular cache implementation that supports many different drivers such as redis, memcache, apc, mongodb and others.",
|
||||||
|
"homepage": "https://www.doctrine-project.org/projects/cache.html",
|
||||||
|
"keywords": [
|
||||||
|
"abstraction",
|
||||||
|
"apcu",
|
||||||
|
"cache",
|
||||||
|
"caching",
|
||||||
|
"couchdb",
|
||||||
|
"memcached",
|
||||||
|
"php",
|
||||||
|
"redis",
|
||||||
|
"xcache"
|
||||||
|
],
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://www.doctrine-project.org/sponsorship.html",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://www.patreon.com/phpdoctrine",
|
||||||
|
"type": "patreon"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/doctrine%2Fcache",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2020-07-07T18:54:01+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "doctrine/dbal",
|
||||||
|
"version": "2.12.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/doctrine/dbal.git",
|
||||||
|
"reference": "adce7a954a1c2f14f85e94aed90c8489af204086"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/doctrine/dbal/zipball/adce7a954a1c2f14f85e94aed90c8489af204086",
|
||||||
|
"reference": "adce7a954a1c2f14f85e94aed90c8489af204086",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"doctrine/cache": "^1.0",
|
||||||
|
"doctrine/event-manager": "^1.0",
|
||||||
|
"ext-pdo": "*",
|
||||||
|
"php": "^7.3 || ^8"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"doctrine/coding-standard": "^8.1",
|
||||||
|
"jetbrains/phpstorm-stubs": "^2019.1",
|
||||||
|
"phpstan/phpstan": "^0.12.40",
|
||||||
|
"phpunit/phpunit": "^9.4",
|
||||||
|
"psalm/plugin-phpunit": "^0.10.0",
|
||||||
|
"symfony/console": "^2.0.5|^3.0|^4.0|^5.0",
|
||||||
|
"vimeo/psalm": "^3.17.2"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"symfony/console": "For helpful console commands such as SQL execution and import of files."
|
||||||
|
},
|
||||||
|
"bin": [
|
||||||
|
"bin/doctrine-dbal"
|
||||||
|
],
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "4.0.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Doctrine\\DBAL\\": "lib/Doctrine/DBAL"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Guilherme Blanco",
|
||||||
|
"email": "guilhermeblanco@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Roman Borschel",
|
||||||
|
"email": "roman@code-factory.org"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Benjamin Eberlei",
|
||||||
|
"email": "kontakt@beberlei.de"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jonathan Wage",
|
||||||
|
"email": "jonwage@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Powerful PHP database abstraction layer (DBAL) with many features for database schema introspection and management.",
|
||||||
|
"homepage": "https://www.doctrine-project.org/projects/dbal.html",
|
||||||
|
"keywords": [
|
||||||
|
"abstraction",
|
||||||
|
"database",
|
||||||
|
"db2",
|
||||||
|
"dbal",
|
||||||
|
"mariadb",
|
||||||
|
"mssql",
|
||||||
|
"mysql",
|
||||||
|
"oci8",
|
||||||
|
"oracle",
|
||||||
|
"pdo",
|
||||||
|
"pgsql",
|
||||||
|
"postgresql",
|
||||||
|
"queryobject",
|
||||||
|
"sasql",
|
||||||
|
"sql",
|
||||||
|
"sqlanywhere",
|
||||||
|
"sqlite",
|
||||||
|
"sqlserver",
|
||||||
|
"sqlsrv"
|
||||||
|
],
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://www.doctrine-project.org/sponsorship.html",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://www.patreon.com/phpdoctrine",
|
||||||
|
"type": "patreon"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdbal",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2020-11-14T20:26:58+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "doctrine/event-manager",
|
||||||
|
"version": "1.1.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/doctrine/event-manager.git",
|
||||||
|
"reference": "41370af6a30faa9dc0368c4a6814d596e81aba7f"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/doctrine/event-manager/zipball/41370af6a30faa9dc0368c4a6814d596e81aba7f",
|
||||||
|
"reference": "41370af6a30faa9dc0368c4a6814d596e81aba7f",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^7.1 || ^8.0"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"doctrine/common": "<2.9@dev"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"doctrine/coding-standard": "^6.0",
|
||||||
|
"phpunit/phpunit": "^7.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "1.0.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Doctrine\\Common\\": "lib/Doctrine/Common"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Guilherme Blanco",
|
||||||
|
"email": "guilhermeblanco@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Roman Borschel",
|
||||||
|
"email": "roman@code-factory.org"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Benjamin Eberlei",
|
||||||
|
"email": "kontakt@beberlei.de"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jonathan Wage",
|
||||||
|
"email": "jonwage@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Johannes Schmitt",
|
||||||
|
"email": "schmittjoh@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Marco Pivetta",
|
||||||
|
"email": "ocramius@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "The Doctrine Event Manager is a simple PHP event system that was built to be used with the various Doctrine projects.",
|
||||||
|
"homepage": "https://www.doctrine-project.org/projects/event-manager.html",
|
||||||
|
"keywords": [
|
||||||
|
"event",
|
||||||
|
"event dispatcher",
|
||||||
|
"event manager",
|
||||||
|
"event system",
|
||||||
|
"events"
|
||||||
|
],
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://www.doctrine-project.org/sponsorship.html",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://www.patreon.com/phpdoctrine",
|
||||||
|
"type": "patreon"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/doctrine%2Fevent-manager",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2020-05-29T18:28:51+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "doctrine/inflector",
|
"name": "doctrine/inflector",
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Routes
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Determine whether or not to automatically define attachments routes.
|
||||||
|
| Used for local storage only as other storage should define their public URL.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'routes' => [
|
||||||
|
'publish' => true,
|
||||||
|
'prefix' => 'attachments',
|
||||||
|
'middleware' => 'web',
|
||||||
|
'pattern' => '/{id}/{name}',
|
||||||
|
'shared_pattern' => '/shared/{token}',
|
||||||
|
'dropzone' => [
|
||||||
|
'upload_pattern' => '/dropzone',
|
||||||
|
'delete_pattern' => '/dropzone/{id}',
|
||||||
|
]
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Model
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Attachment model used
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'attachment_model' => env('ATTACHMENTS_MODEL', \Bnb\Laravel\Attachments\Attachment::class),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Uuid
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Default attachment model uses an UUID column. You can define your own UUID
|
||||||
|
| generator here : a global function name or a static class method in the form :
|
||||||
|
| App\Namespace\ClassName@method
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'uuid_provider' => 'uuid_v4_base36',
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Behaviors
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Configurable behaviors :
|
||||||
|
| - Concrete files can be delete when the database entry is deleted
|
||||||
|
| - Dropzone delete can check for CSRF token match (set on upload)
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'behaviors' => [
|
||||||
|
'cascade_delete' => env('ATTACHMENTS_CASCADE_DELETE', true),
|
||||||
|
'dropzone_check_csrf' => env('ATTACHMENTS_DROPZONE_CHECK_CSRF', true),
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Declare the attachment model attributes
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This allow to extend the attachment model with new columns
|
||||||
|
| `dropzone_attributes` holds the public fields returned after a successful upload via DropzoneController
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'attributes' => ['title', 'description', 'key', 'disk', 'filepath', 'group'],
|
||||||
|
|
||||||
|
'dropzone_attributes' => ['uuid', 'url', 'url_inline', 'filename', 'filetype', 'filesize', 'title', 'description', 'key', 'group'],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Attachment Storage Directory
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Defines the directory prefix where new attachment files are stored
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'storage_directory' => [
|
||||||
|
'prefix' => rtrim(env('ATTACHMENTS_STORAGE_DIRECTORY_PREFIX', 'attachments'), '/'),
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Database configuration
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Allows to set the database connection name for the module's models
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'database' => [
|
||||||
|
'connection' => env('ATTACHMENTS_DATABASE_CONNECTION'),
|
||||||
|
],
|
||||||
|
];
|
|
@ -0,0 +1,106 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Default Search Engine
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This option controls the default search connection that gets used while
|
||||||
|
| using Laravel Scout. This connection is used when syncing all models
|
||||||
|
| to the search service. You should adjust this based on your needs.
|
||||||
|
|
|
||||||
|
| Supported: "algolia", "null"
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'driver' => env('SCOUT_DRIVER', 'elastic'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Index Prefix
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may specify a prefix that will be applied to all search index
|
||||||
|
| names used by Scout. This prefix may be useful if you have multiple
|
||||||
|
| "tenants" or applications sharing the same search infrastructure.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'prefix' => env('SCOUT_PREFIX', ''),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Queue Data Syncing
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This option allows you to control if the operations that sync your data
|
||||||
|
| with your search engines are queued. When this is set to "true" then
|
||||||
|
| all automatic data syncing will get queued for better performance.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'queue' => env('SCOUT_QUEUE', false),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Chunk Sizes
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| These options allow you to control the maximum chunk size when you are
|
||||||
|
| mass importing data into the search engine. This allows you to fine
|
||||||
|
| tune each of these chunk sizes based on the power of the servers.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'chunk' => [
|
||||||
|
'searchable' => 500,
|
||||||
|
'unsearchable' => 500,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Soft Deletes
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This option allows to control whether to keep soft deleted records in
|
||||||
|
| the search indexes. Maintaining soft deleted records can be useful
|
||||||
|
| if your application still needs to search for the records later.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'soft_delete' => false,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Identify User
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This option allows you to control whether to notify the search engine
|
||||||
|
| of the user performing the search. This is sometimes useful if the
|
||||||
|
| engine supports any analytics based on this application's users.
|
||||||
|
|
|
||||||
|
| Supported engines: "algolia"
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'identify' => env('SCOUT_IDENTIFY', false),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Algolia Configuration
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may configure your Algolia settings. Algolia is a cloud hosted
|
||||||
|
| search engine which works great with Scout out of the box. Just plug
|
||||||
|
| in your application ID and admin API key to get started searching.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'algolia' => [
|
||||||
|
'id' => env('ALGOLIA_APP_ID', ''),
|
||||||
|
'secret' => env('ALGOLIA_SECRET', ''),
|
||||||
|
],
|
||||||
|
|
||||||
|
];
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
'client' => [
|
||||||
|
'hosts' => [
|
||||||
|
env('SCOUT_ELASTIC_HOST', 'localhost:9200'),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'update_mapping' => env('SCOUT_ELASTIC_UPDATE_MAPPING', true),
|
||||||
|
'indexer' => env('SCOUT_ELASTIC_INDEXER', 'single'),
|
||||||
|
'document_refresh' => env('SCOUT_ELASTIC_DOCUMENT_REFRESH'),
|
||||||
|
];
|
10
package.json
10
package.json
|
@ -12,10 +12,9 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@ttskch/select2-bootstrap4-theme": "^1.3.4",
|
"@ttskch/select2-bootstrap4-theme": "^1.3.4",
|
||||||
"axios": "^0.19",
|
"axios": "^0.19",
|
||||||
|
"bootbox": "^5.5.2",
|
||||||
"bootstrap": "^4.0.0",
|
"bootstrap": "^4.0.0",
|
||||||
"cross-env": "^7.0",
|
"cross-env": "^7.0",
|
||||||
"datatables.net-bs4": "^1.10.23",
|
|
||||||
"datatables.net-buttons-bs4": "^1.6.5",
|
|
||||||
"jquery": "^3.2",
|
"jquery": "^3.2",
|
||||||
"laravel-mix": "^5.0.1",
|
"laravel-mix": "^5.0.1",
|
||||||
"lodash": "^4.17.19",
|
"lodash": "^4.17.19",
|
||||||
|
@ -23,11 +22,6 @@
|
||||||
"resolve-url-loader": "^2.3.1",
|
"resolve-url-loader": "^2.3.1",
|
||||||
"sass": "^1.20.1",
|
"sass": "^1.20.1",
|
||||||
"sass-loader": "^8.0.0",
|
"sass-loader": "^8.0.0",
|
||||||
"select2": "^4.0.13",
|
"select2": "^4.0.13"
|
||||||
"vue": "^2.5.17",
|
|
||||||
"vue-template-compiler": "^2.6.10"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"vue-router": "^3.4.9"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -8,18 +8,6 @@
|
||||||
require('./bootstrap');
|
require('./bootstrap');
|
||||||
|
|
||||||
$(document).ready(function(e) {
|
$(document).ready(function(e) {
|
||||||
|
|
||||||
$.fn.dataTable.render.authorValue = function(_, context, book) {
|
|
||||||
let authors = [];
|
|
||||||
|
|
||||||
console.log(book);
|
|
||||||
for (let author of book.authors) {
|
|
||||||
authors.push(author.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
return authors.join(', ');
|
|
||||||
};
|
|
||||||
|
|
||||||
var authorOptions = {
|
var authorOptions = {
|
||||||
placeholder: 'Authors',
|
placeholder: 'Authors',
|
||||||
tags: true,
|
tags: true,
|
||||||
|
@ -64,23 +52,35 @@ $(document).ready(function(e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
$.get('/lookup/' + barcodeValue, function(res) {
|
$.get('/lookup/' + barcodeValue, function(res) {
|
||||||
$row.find('input[name*=name]').val(res.title);
|
if (res.warning) {
|
||||||
|
bootbox.alert({
|
||||||
var $authors = $row.find('.select2-author');
|
title: 'Warning',
|
||||||
|
message: res.warning,
|
||||||
$authors.children('option').remove();
|
callback: function() {
|
||||||
|
$('.barcode_input').filter(function() {
|
||||||
for (var i = 0; i < res.authors.length; i++) {
|
return !this.value;
|
||||||
$authors.append($('<option>', {value: res.authors[i], text: res.authors[i], selected: 'selected'}));
|
}).focus();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$authors.trigger('change');
|
if (res.success) {
|
||||||
|
$row.find('input[name*=name]').val(res.data.title);
|
||||||
|
|
||||||
|
var $authors = $row.find('.select2-author');
|
||||||
|
|
||||||
|
$authors.children('option').remove();
|
||||||
|
|
||||||
|
for (var i = 0; i < res.data.authors.length; i++) {
|
||||||
|
$authors.append($('<option>', {value: res.data.authors[i], text: res.data.authors[i], selected: 'selected'}));
|
||||||
|
}
|
||||||
|
|
||||||
|
$authors.trigger('change');
|
||||||
|
}
|
||||||
}, 'json');
|
}, 'json');
|
||||||
|
|
||||||
var count = emptyRowCount();
|
var count = emptyRowCount();
|
||||||
|
|
||||||
console.log('Empty rows:', count);
|
|
||||||
|
|
||||||
if (count < 1) {
|
if (count < 1) {
|
||||||
var firstIndex = 0,
|
var firstIndex = 0,
|
||||||
$container = $row.closest('.row-container');
|
$container = $row.closest('.row-container');
|
||||||
|
@ -116,6 +116,26 @@ $(document).ready(function(e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('.remove-item').click(function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
var $this = $(this),
|
||||||
|
$row = $this.closest('tr');
|
||||||
|
|
||||||
|
bootbox.confirm('Are you sure?', function(result) {
|
||||||
|
if (!result) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
axios.delete($row.data('url')).then(function(res) {
|
||||||
|
if (res.data.success) {
|
||||||
|
|
||||||
|
$row.remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
function emptyRowCount() {
|
function emptyRowCount() {
|
||||||
|
|
|
@ -12,8 +12,7 @@ try {
|
||||||
|
|
||||||
require('bootstrap');
|
require('bootstrap');
|
||||||
require('select2');
|
require('select2');
|
||||||
require('datatables.net-bs4');
|
window.bootbox = require('bootbox');
|
||||||
require('datatables.net-buttons-bs4');
|
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -24,21 +23,4 @@ try {
|
||||||
|
|
||||||
window.axios = require('axios');
|
window.axios = require('axios');
|
||||||
|
|
||||||
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
|
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
|
||||||
|
|
||||||
/**
|
|
||||||
* Echo exposes an expressive API for subscribing to channels and listening
|
|
||||||
* for events that are broadcast by Laravel. Echo and event broadcasting
|
|
||||||
* allows your team to easily build robust real-time web applications.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// import Echo from 'laravel-echo';
|
|
||||||
|
|
||||||
// window.Pusher = require('pusher-js');
|
|
||||||
|
|
||||||
// window.Echo = new Echo({
|
|
||||||
// broadcaster: 'pusher',
|
|
||||||
// key: process.env.MIX_PUSHER_APP_KEY,
|
|
||||||
// cluster: process.env.MIX_PUSHER_APP_CLUSTER,
|
|
||||||
// forceTLS: true
|
|
||||||
// });
|
|
|
@ -6,6 +6,9 @@
|
||||||
<div class="form-row justify-content-md-center">
|
<div class="form-row justify-content-md-center">
|
||||||
<div class="col-4">
|
<div class="col-4">
|
||||||
<select name="location" class="form-control select2-location">
|
<select name="location" class="form-control select2-location">
|
||||||
|
@foreach ($locations as $location)
|
||||||
|
<option value="{{ $location->name }}">{{ $location->name }}</option>
|
||||||
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -21,9 +24,11 @@
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<button class="btn btn-primary" name="save" type="submit">
|
<div class="col-2">
|
||||||
Save
|
<button class="btn btn-primary" name="save" type="submit" style="width:100%">
|
||||||
</button>
|
Save
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@include('partials/row', [ 'id' => 'add-template', 'htmlClass' => 'invisible' ])
|
@include('partials/row', [ 'id' => 'add-template', 'htmlClass' => 'invisible' ])
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
@extends('layouts.main')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<h3>{{ $book->name }}</h3>
|
||||||
|
<h5>By: {{ $book->authors->pluck('name')->join(', ') }}</h5>
|
||||||
|
<br />
|
||||||
|
@if ($thumbnail = $book->attachment('thumbnail'))
|
||||||
|
<h5>Image</h5>
|
||||||
|
<p>
|
||||||
|
<img src="{{ $thumbnail->url }}" />
|
||||||
|
</p>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<h5>Location:</h5>
|
||||||
|
<p>
|
||||||
|
{{ $book->location->name }}
|
||||||
|
</p>
|
||||||
|
@endsection
|
|
@ -1,11 +1,12 @@
|
||||||
@extends('layouts.main')
|
@extends('layouts.main')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<table class="table table-compact">
|
<table class="table table-compact table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
<th>Authors</th>
|
<th>Authors</th>
|
||||||
<th>Location</th>
|
<th>Location</th>
|
||||||
|
<th>Actions</th>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@foreach ($rows as $row)
|
@foreach ($rows as $row)
|
||||||
|
@ -13,6 +14,9 @@
|
||||||
<td>{{ $row->name }}</td>
|
<td>{{ $row->name }}</td>
|
||||||
<td>{{ $row->authors->pluck('name')->join(', ') }}</td>
|
<td>{{ $row->authors->pluck('name')->join(', ') }}</td>
|
||||||
<td>{{ $row->location->name }}</td>
|
<td>{{ $row->location->name }}</td>
|
||||||
|
<td>
|
||||||
|
<a class="btn btn-info btn-sm" href="{{ route('books.show', $row->id) }}">View</a>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
</main><!-- /.container -->
|
</main><!-- /.container -->
|
||||||
|
|
||||||
<script src="{{ mix('js/app.js') }}"></script>
|
<script src="{{ mix('js/app.js') }}"></script>
|
||||||
<script src="{{ asset('vendor/datatables/buttons.server-side.js') }}"></script>
|
|
||||||
@stack('scripts')
|
@stack('scripts')
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
@extends('layouts.main')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<table class="table table-compact">
|
||||||
|
<thead>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach ($locations as $row)
|
||||||
|
<tr>
|
||||||
|
<td>{{ $row->name }}</td>
|
||||||
|
<td>
|
||||||
|
<a href="{{ route('locations.show', $row->id) }}" class="btn btn-info btn-sm">View</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{{ $locations->links() }}
|
||||||
|
@endsection
|
|
@ -0,0 +1,24 @@
|
||||||
|
@extends('layouts.main')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<h3>{{ $location->name }}</h3>
|
||||||
|
<table class="table table-compact">
|
||||||
|
<thead>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Authors</th>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach ($rows as $row)
|
||||||
|
<tr data-id="{{ $row->id }}" data-url="{{ route('books.show', $row->id) }}">
|
||||||
|
<td>{{ $row->name }}</td>
|
||||||
|
<td>{{ $row->authors->pluck('name')->join(', ') }}</td>
|
||||||
|
<td>
|
||||||
|
<a class="btn btn-info btn-sm" href="{{ route('books.show', $row->id) }}">View</a>
|
||||||
|
<button class="remove-item btn btn-danger btn-sm">Remove</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{{ $rows->links() }}
|
||||||
|
@endsection
|
|
@ -11,7 +11,10 @@
|
||||||
<a class="nav-link" href="/">Home <span class="sr-only">(current)</span></a>
|
<a class="nav-link" href="/">Home <span class="sr-only">(current)</span></a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/add">Add</a>
|
<a class="nav-link" href="{{ route('locations.index') }}">Locations</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="{{ route('add') }}">Add</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<form class="form-inline my-2 my-lg-0" action="{{ route('search') }}">
|
<form class="form-inline my-2 my-lg-0" action="{{ route('search') }}">
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Route::get('/', 'MainController@index');
|
Route::get('/', 'MainController@index');
|
||||||
Route::get('/add', 'MainController@add');
|
Route::get('/add', 'MainController@add')->name('add');
|
||||||
Route::post('/save', 'MainController@save')->name('save');
|
Route::post('/save', 'MainController@save')->name('save');
|
||||||
Route::get('/search', 'MainController@search')->name('search');
|
Route::get('/search', 'MainController@search')->name('search');
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
*
|
*
|
||||||
!public/
|
!public/
|
||||||
|
!temp/
|
||||||
!.gitignore
|
!.gitignore
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
*
|
.gitignore
|
||||||
!.gitignore
|
!.gitignore
|
Loading…
Reference in New Issue