Skip to content

Commit

Permalink
Added uploaded to book/page filters & search in image manager
Browse files Browse the repository at this point in the history
Also refactored tab styles which affected the settings area.

Closes #41
  • Loading branch information
ssddanbrown committed Apr 3, 2016
1 parent 8e614ec commit cbff2c6
Show file tree
Hide file tree
Showing 10 changed files with 234 additions and 27 deletions.
46 changes: 40 additions & 6 deletions app/Http/Controllers/ImageController.php
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
<?php

namespace BookStack\Http\Controllers;
<?php namespace BookStack\Http\Controllers;

use BookStack\Exceptions\ImageUploadException;
use BookStack\Repos\ImageRepo;
use Illuminate\Filesystem\Filesystem as File;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Intervention\Image\Facades\Image as ImageTool;
use Illuminate\Support\Facades\DB;
use BookStack\Image;
use BookStack\Repos\PageRepo;

Expand Down Expand Up @@ -44,6 +39,24 @@ public function getAllByType($type, $page = 0)
return response()->json($imgData);
}

/**
* Search through images within a particular type.
* @param $type
* @param int $page
* @param Request $request
* @return mixed
*/
public function searchByType($type, $page = 0, Request $request)
{
$this->validate($request, [
'term' => 'required|string'
]);

$searchTerm = $request->get('term');
$imgData = $this->imageRepo->searchPaginatedByType($type, $page,24, $searchTerm);
return response()->json($imgData);
}

/**
* Get all images for a user.
* @param int $page
Expand All @@ -55,6 +68,27 @@ public function getAllForUserType($page = 0)
return response()->json($imgData);
}

/**
* Get gallery images with a specific filter such as book or page
* @param $filter
* @param int $page
* @param Request $request
*/
public function getGalleryFiltered($filter, $page = 0, Request $request)
{
$this->validate($request, [
'page_id' => 'required|integer'
]);

$validFilters = collect(['page', 'book']);
if (!$validFilters->contains($filter)) return response('Invalid filter', 500);

$pageId = $request->get('page_id');
$imgData = $this->imageRepo->getGalleryFiltered($page, 24, strtolower($filter), $pageId);

return response()->json($imgData);
}

/**
* Handles image uploads for use on pages.
* @param string $type
Expand Down
2 changes: 2 additions & 0 deletions app/Http/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@
Route::post('/{type}/upload', 'ImageController@uploadByType');
Route::get('/{type}/all', 'ImageController@getAllByType');
Route::get('/{type}/all/{page}', 'ImageController@getAllByType');
Route::get('/{type}/search/{page}', 'ImageController@searchByType');
Route::get('/gallery/{filter}/{page}', 'ImageController@getGalleryFiltered');
Route::delete('/{imageId}', 'ImageController@destroy');
});

Expand Down
80 changes: 68 additions & 12 deletions app/Repos/ImageRepo.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@


use BookStack\Image;
use BookStack\Page;
use BookStack\Services\ImageService;
use BookStack\Services\RestrictionService;
use Setting;
Expand All @@ -13,18 +14,21 @@ class ImageRepo
protected $image;
protected $imageService;
protected $restictionService;
protected $page;

/**
* ImageRepo constructor.
* @param Image $image
* @param ImageService $imageService
* @param RestrictionService $restrictionService
* @param Page $page
*/
public function __construct(Image $image, ImageService $imageService, RestrictionService $restrictionService)
public function __construct(Image $image, ImageService $imageService, RestrictionService $restrictionService, Page $page)
{
$this->image = $image;
$this->imageService = $imageService;
$this->restictionService = $restrictionService;
$this->page = $page;
}


Expand All @@ -39,22 +43,16 @@ public function getById($id)
}

/**
* Gets a load images paginated, filtered by image type.
* @param string $type
* Execute a paginated query, returning in a standard format.
* Also runs the query through the restriction system.
* @param $query
* @param int $page
* @param int $pageSize
* @param bool|int $userFilter
* @return array
*/
public function getPaginatedByType($type, $page = 0, $pageSize = 24, $userFilter = false)
private function returnPaginated($query, $page = 0, $pageSize = 24)
{
$images = $this->image->where('type', '=', strtolower($type));

if ($userFilter !== false) {
$images = $images->where('created_by', '=', $userFilter);
}

$images = $this->restictionService->filterRelatedPages($images, 'images', 'uploaded_to');
$images = $this->restictionService->filterRelatedPages($query, 'images', 'uploaded_to');
$images = $images->orderBy('created_at', 'desc')->skip($pageSize * $page)->take($pageSize + 1)->get();
$hasMore = count($images) > $pageSize;

Expand All @@ -69,6 +67,64 @@ public function getPaginatedByType($type, $page = 0, $pageSize = 24, $userFilter
];
}

/**
* Gets a load images paginated, filtered by image type.
* @param string $type
* @param int $page
* @param int $pageSize
* @param bool|int $userFilter
* @return array
*/
public function getPaginatedByType($type, $page = 0, $pageSize = 24, $userFilter = false)
{
$images = $this->image->where('type', '=', strtolower($type));

if ($userFilter !== false) {
$images = $images->where('created_by', '=', $userFilter);
}

return $this->returnPaginated($images, $page, $pageSize);
}

/**
* Search for images by query, of a particular type.
* @param string $type
* @param int $page
* @param int $pageSize
* @param string $searchTerm
* @return array
*/
public function searchPaginatedByType($type, $page = 0, $pageSize = 24, $searchTerm)
{
$images = $this->image->where('type', '=', strtolower($type))->where('name', 'LIKE', '%' . $searchTerm . '%');
return $this->returnPaginated($images, $page, $pageSize);
}

/**
* Get gallery images with a particular filter criteria such as
* being within the current book or page.
* @param int $pagination
* @param int $pageSize
* @param $filter
* @param $pageId
* @return array
*/
public function getGalleryFiltered($pagination = 0, $pageSize = 24, $filter, $pageId)
{
$images = $this->image->where('type', '=', 'gallery');

$page = $this->page->findOrFail($pageId);

if ($filter === 'page') {
$images = $images->where('uploaded_to', '=', $page->id);
} elseif ($filter === 'book') {
$validPageIds = $page->book->pages->pluck('id')->toArray();
$images = $images->whereIn('uploaded_to', $validPageIds);
}

return $this->returnPaginated($images, $pagination, $pageSize);
}

/**
* Save a new image into storage and return the new image.
* @param UploadedFile $uploadFile
Expand Down
78 changes: 74 additions & 4 deletions resources/assets/js/controllers.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,40 @@ module.exports = function (ngApp, events) {
$scope.imageUpdateSuccess = false;
$scope.imageDeleteSuccess = false;
$scope.uploadedTo = $attrs.uploadedTo;
$scope.view = 'all';

$scope.searching = false;
$scope.searchTerm = '';

var page = 0;
var previousClickTime = 0;
var previousClickImage = 0;
var dataLoaded = false;
var callback = false;

var preSearchImages = [];
var preSearchHasMore = false;

/**
* Simple returns the appropriate upload url depending on the image type set.
* Used by dropzone to get the endpoint to upload to.
* @returns {string}
*/
$scope.getUploadUrl = function () {
return '/images/' + $scope.imageType + '/upload';
};

/**
* Cancel the current search operation.
*/
function cancelSearch() {
$scope.searching = false;
$scope.searchTerm = '';
$scope.images = preSearchImages;
$scope.hasMore = preSearchHasMore;
}
$scope.cancelSearch = cancelSearch;


/**
* Runs on image upload, Adds an image to local list of images
* and shows a success message to the user.
Expand Down Expand Up @@ -59,7 +79,7 @@ module.exports = function (ngApp, events) {
var currentTime = Date.now();
var timeDiff = currentTime - previousClickTime;

if (timeDiff < dblClickTime) {
if (timeDiff < dblClickTime && image.id === previousClickImage) {
// If double click
callbackAndHide(image);
} else {
Expand All @@ -68,6 +88,7 @@ module.exports = function (ngApp, events) {
$scope.dependantPages = false;
}
previousClickTime = currentTime;
previousClickImage = image.id;
};

/**
Expand Down Expand Up @@ -110,20 +131,69 @@ module.exports = function (ngApp, events) {
$scope.showing = false;
};

var baseUrl = '/images/' + $scope.imageType + '/all/'

/**
* Fetch the list image data from the server.
*/
function fetchData() {
var url = '/images/' + $scope.imageType + '/all/' + page;
var url = baseUrl + page + '?';
var components = {};
if ($scope.uploadedTo) components['page_id'] = $scope.uploadedTo;
if ($scope.searching) components['term'] = $scope.searchTerm;


var urlQueryString = Object.keys(components).map((key) => {
return key + '=' + encodeURIComponent(components[key]);
}).join('&');
url += urlQueryString;

$http.get(url).then((response) => {
$scope.images = $scope.images.concat(response.data.images);
$scope.hasMore = response.data.hasMore;
page++;
});
}

$scope.fetchData = fetchData;

/**
* Start a search operation
* @param searchTerm
*/
$scope.searchImages = function() {

if ($scope.searchTerm === '') {
cancelSearch();
return;
}

if (!$scope.searching) {
preSearchImages = $scope.images;
preSearchHasMore = $scope.hasMore;
}

$scope.searching = true;
$scope.images = [];
$scope.hasMore = false;
page = 0;
baseUrl = '/images/' + $scope.imageType + '/search/';
fetchData();
};

/**
* Set the current image listing view.
* @param viewName
*/
$scope.setView = function(viewName) {
cancelSearch();
$scope.images = [];
$scope.hasMore = false;
page = 0;
$scope.view = viewName;
baseUrl = '/images/' + $scope.imageType + '/' + viewName + '/';
fetchData();
}

/**
* Save the details of an image.
* @param event
Expand Down
5 changes: 3 additions & 2 deletions resources/assets/sass/_header.scss
Original file line number Diff line number Diff line change
Expand Up @@ -189,12 +189,13 @@ form.search-box {
}
}

.setting-nav {
.nav-tabs {
text-align: center;
a {
a, .tab-item {
padding: $-m;
display: inline-block;
color: #666;
cursor: pointer;
&.selected {
border-bottom: 2px solid $primary;
}
Expand Down
7 changes: 6 additions & 1 deletion resources/assets/sass/_image-manager.scss
Original file line number Diff line number Diff line change
Expand Up @@ -120,14 +120,19 @@
.image-manager-list {
overflow-y: scroll;
flex: 1;
border-top: 1px solid #ddd;
}

.image-manager-content {
display: flex;
flex-direction: column;
height: 100%;
flex: 1;
.container {
width: 100%;
}
.full-tab {
text-align: center;
}
}

// Dropzone
Expand Down
Loading

0 comments on commit cbff2c6

Please sign in to comment.