]>
BookStack Code Mirror - bookstack/commitdiff
projects
/
bookstack
/ commitdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
| commitdiff |
tree
raw
| inline |
side by side
(parent:
0513239
)
Added permission system
author
Dan Brown
<redacted>
Sat, 29 Aug 2015 14:03:42 +0000
(15:03 +0100)
committer
Dan Brown
<redacted>
Sat, 29 Aug 2015 14:03:42 +0000
(15:03 +0100)
24 files changed:
app/Http/Controllers/BookController.php
patch
|
blob
|
history
app/Http/Controllers/ChapterController.php
patch
|
blob
|
history
app/Http/Controllers/Controller.php
patch
|
blob
|
history
app/Http/Controllers/HomeController.php
patch
|
blob
|
history
app/Http/Controllers/ImageController.php
patch
|
blob
|
history
app/Http/Controllers/PageController.php
patch
|
blob
|
history
app/Http/Controllers/UserController.php
patch
|
blob
|
history
app/Http/Kernel.php
patch
|
blob
|
history
app/Http/Middleware/PermissionMiddleware.php
[new file with mode: 0644]
patch
|
blob
app/Http/routes.php
patch
|
blob
|
history
app/Permission.php
[new file with mode: 0644]
patch
|
blob
app/Providers/AppServiceProvider.php
patch
|
blob
|
history
app/Role.php
[new file with mode: 0644]
patch
|
blob
app/User.php
patch
|
blob
|
history
database/migrations/2014_10_12_000000_create_users_table.php
patch
|
blob
|
history
database/migrations/2015_08_29_105422_add_roles_and_permissions.php
[new file with mode: 0644]
patch
|
blob
database/seeds/DatabaseSeeder.php
patch
|
blob
|
history
resources/assets/sass/_blocks.scss
patch
|
blob
|
history
resources/assets/sass/_text.scss
patch
|
blob
|
history
resources/lang/en/errors.php
[new file with mode: 0644]
patch
|
blob
resources/views/form/model-select.blade.php
[new file with mode: 0644]
patch
|
blob
resources/views/users/edit.blade.php
patch
|
blob
|
history
resources/views/users/form.blade.php
patch
|
blob
|
history
resources/views/users/index.blade.php
patch
|
blob
|
history
diff --git
a/app/Http/Controllers/BookController.php
b/app/Http/Controllers/BookController.php
index dd919c6c268a317f0228f5015b16eac51a929523..91cd4bd518ddf67158c38d85d0c0962a06a3bb4d 100644
(file)
--- a/
app/Http/Controllers/BookController.php
+++ b/
app/Http/Controllers/BookController.php
@@
-26,6
+26,7
@@
class BookController extends Controller
{
$this->bookRepo = $bookRepo;
$this->pageRepo = $pageRepo;
+ parent::__construct();
}
/**
@@
-46,19
+47,21
@@
class BookController extends Controller
*/
public function create()
{
+ $this->checkPermission('book-create');
return view('books/create');
}
/**
* Store a newly created book in storage.
*
- * @param Request
$request
+ * @param Request $request
* @return Response
*/
public function store(Request $request)
{
+ $this->checkPermission('book-create');
$this->validate($request, [
- 'name' => 'required|string|max:255',
+ 'name'
=> 'required|string|max:255',
'description' => 'string|max:1000'
]);
$book = $this->bookRepo->newFromInput($request->all());
@@
-90,6
+93,7
@@
class BookController extends Controller
*/
public function edit($slug)
{
+ $this->checkPermission('book-update');
$book = $this->bookRepo->getBySlug($slug);
return view('books/edit', ['book' => $book, 'current' => $book]);
}
@@
-98,14
+102,15
@@
class BookController extends Controller
* Update the specified book in storage.
*
* @param Request $request
- * @param $slug
+ * @param
$slug
* @return Response
*/
public function update(Request $request, $slug)
{
+ $this->checkPermission('book-update');
$book = $this->bookRepo->getBySlug($slug);
$this->validate($request, [
- 'name' => 'required|string|max:255',
+ 'name'
=> 'required|string|max:255',
'description' => 'string|max:1000'
]);
$book->fill($request->all());
@@
-123,6
+128,7
@@
class BookController extends Controller
*/
public function showDelete($bookSlug)
{
+ $this->checkPermission('book-delete');
$book = $this->bookRepo->getBySlug($bookSlug);
return view('books/delete', ['book' => $book, 'current' => $book]);
}
@@
-135,6
+141,7
@@
class BookController extends Controller
*/
public function destroy($bookSlug)
{
+ $this->checkPermission('book-delete');
$book = $this->bookRepo->getBySlug($bookSlug);
Activity::addMessage('book_delete', 0, $book->name);
$this->bookRepo->destroyBySlug($bookSlug);
diff --git
a/app/Http/Controllers/ChapterController.php
b/app/Http/Controllers/ChapterController.php
index 12bbeeab04a636a0aa1bd62b36032550f6c2e5a8..98e7a66781ba978e2b092346ba01fb93c6c59143 100644
(file)
--- a/
app/Http/Controllers/ChapterController.php
+++ b/
app/Http/Controllers/ChapterController.php
@@
-22,12
+22,13
@@
class ChapterController extends Controller
* @param $bookRepo
* @param $chapterRepo
*/
- public function __construct(BookRepo $bookRepo,ChapterRepo $chapterRepo)
+ public function __construct(BookRepo $bookRepo,
ChapterRepo $chapterRepo)
{
$this->bookRepo = $bookRepo;
$this->chapterRepo = $chapterRepo;
+ parent::__construct();
}
-
+
/**
* Show the form for creating a new chapter.
@@
-37,6
+38,7
@@
class ChapterController extends Controller
*/
public function create($bookSlug)
{
+ $this->checkPermission('chapter-create');
$book = $this->bookRepo->getBySlug($bookSlug);
return view('chapters/create', ['book' => $book, 'current' => $book]);
}
@@
-44,12
+46,13
@@
class ChapterController extends Controller
/**
* Store a newly created chapter in storage.
*
- * @param $bookSlug
+ * @param
$bookSlug
* @param Request $request
* @return Response
*/
public function store($bookSlug, Request $request)
{
+ $this->checkPermission('chapter-create');
$this->validate($request, [
'name' => 'required|string|max:255'
]);
@@
-88,6
+91,7
@@
class ChapterController extends Controller
*/
public function edit($bookSlug, $chapterSlug)
{
+ $this->checkPermission('chapter-update');
$book = $this->bookRepo->getBySlug($bookSlug);
$chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id);
return view('chapters/edit', ['book' => $book, 'chapter' => $chapter, 'current' => $chapter]);
@@
-97,12
+101,13
@@
class ChapterController extends Controller
* Update the specified chapter in storage.
*
* @param Request $request
- * @param $bookSlug
- * @param $chapterSlug
+ * @param
$bookSlug
+ * @param
$chapterSlug
* @return Response
*/
public function update(Request $request, $bookSlug, $chapterSlug)
{
+ $this->checkPermission('chapter-update');
$book = $this->bookRepo->getBySlug($bookSlug);
$chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id);
$chapter->fill($request->all());
@@
-121,6
+126,7
@@
class ChapterController extends Controller
*/
public function showDelete($bookSlug, $chapterSlug)
{
+ $this->checkPermission('chapter-delete');
$book = $this->bookRepo->getBySlug($bookSlug);
$chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id);
return view('chapters/delete', ['book' => $book, 'chapter' => $chapter, 'current' => $chapter]);
@@
-135,10
+141,11
@@
class ChapterController extends Controller
*/
public function destroy($bookSlug, $chapterSlug)
{
+ $this->checkPermission('chapter-delete');
$book = $this->bookRepo->getBySlug($bookSlug);
$chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id);
- if(count($chapter->pages) > 0) {
- foreach($chapter->pages as $page) {
+ if
(count($chapter->pages) > 0) {
+ foreach
($chapter->pages as $page) {
$page->chapter_id = 0;
$page->save();
}
diff --git
a/app/Http/Controllers/Controller.php
b/app/Http/Controllers/Controller.php
index 48a58ca990d02f3501175ff49f0f268b994bbcc4..2db96ccf7a60fab8cdc49017db4635ba88e57674 100644
(file)
--- a/
app/Http/Controllers/Controller.php
+++ b/
app/Http/Controllers/Controller.php
@@
-2,27
+2,69
@@
namespace Oxbow\Http\Controllers;
+use HttpRequestException;
use Illuminate\Foundation\Bus\DispatchesJobs;
+use Illuminate\Http\Exception\HttpResponseException;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Support\Facades\Auth;
+use Illuminate\Support\Facades\Session;
use Oxbow\User;
abstract class Controller extends BaseController
{
use DispatchesJobs, ValidatesRequests;
+ /**
+ * @var User static
+ */
+ protected $currentUser;
+ /**
+ * @var bool
+ */
+ protected $signedIn;
+
/**
* Controller constructor.
*/
public function __construct()
{
- view()->share('signedIn', Auth::check());
+ // Get a user instance for the current user
$user = Auth::user();
- if(!$user) {
+ if
(!$user) {
$user = User::getDefault();
}
- view()->share('user', $user);
+ // Share variables with views
+ view()->share('signedIn', Auth::check());
+ view()->share('currentUser', $user);
+ // Share variables with controllers
+ $this->currentUser = $user;
+ $this->signedIn = Auth::check();
+ }
+
+ /**
+ * Checks for a permission.
+ *
+ * @param $permissionName
+ * @return bool|\Illuminate\Http\RedirectResponse
+ */
+ protected function checkPermission($permissionName)
+ {
+ if (!$this->currentUser || !$this->currentUser->can($permissionName)) {
+ Session::flash('error', trans('errors.permission'));
+ throw new HttpResponseException(
+ redirect()->back()
+ );
+ }
+
+ return true;
+ }
+
+ protected function checkPermissionOr($permissionName, $callback)
+ {
+ $callbackResult = $callback();
+ if ($callbackResult === false) $this->checkPermission($permissionName);
+ return true;
}
}
diff --git
a/app/Http/Controllers/HomeController.php
b/app/Http/Controllers/HomeController.php
index ad87188b718de5aede5d2cbc6d74f10c66cc3eff..3ed1da4c1c0b38c14f40a9b39052cbb56489dffb 100644
(file)
--- a/
app/Http/Controllers/HomeController.php
+++ b/
app/Http/Controllers/HomeController.php
@@
-19,12
+19,13
@@
class HomeController extends Controller
/**
* HomeController constructor.
* @param ActivityService $activityService
- * @param BookRepo $bookRepo
+ * @param BookRepo
$bookRepo
*/
public function __construct(ActivityService $activityService, BookRepo $bookRepo)
{
$this->activityService = $activityService;
$this->bookRepo = $bookRepo;
+ parent::__construct();
}
diff --git
a/app/Http/Controllers/ImageController.php
b/app/Http/Controllers/ImageController.php
index 50341fe1fdeb1c99b081571c372976c17b16b08b..6d01fe2ccc423c15062ebeec1a48f93e88e236f0 100644
(file)
--- a/
app/Http/Controllers/ImageController.php
+++ b/
app/Http/Controllers/ImageController.php
@@
-18,12
+18,13
@@
class ImageController extends Controller
/**
* ImageController constructor.
* @param Image $image
- * @param File $file
+ * @param File
$file
*/
public function __construct(Image $image, File $file)
{
$this->image = $image;
$this->file = $file;
+ parent::__construct();
}
/**
@@
-33,7
+34,7
@@
class ImageController extends Controller
*/
public function getImage(Request $request)
{
- $cacheTime = 60
*60*
24;
+ $cacheTime = 60
* 60 *
24;
$path = storage_path() . '/' . $request->path();
$modifiedTime = $this->file->lastModified($path);
$eTag = md5($modifiedTime . $path);
@@
-43,20
+44,20
@@
class ImageController extends Controller
$headers = [
'Last-Modified' => $headerLastModified,
'Cache-Control' => 'must-revalidate',
- 'Pragma' => 'public',
- 'Expires' => $headerExpires,
- 'Etag' => $eTag
+ 'Pragma'
=> 'public',
+ 'Expires'
=> $headerExpires,
+ 'Etag'
=> $eTag
];
$browserModifiedSince = $request->header('If-Modified-Since');
$browserNoneMatch = $request->header('If-None-Match');
- if($browserModifiedSince !== null && file_exists($path) && ($browserModifiedSince == $headerLastModified || $browserNoneMatch == $eTag)) {
+ if
($browserModifiedSince !== null && file_exists($path) && ($browserModifiedSince == $headerLastModified || $browserNoneMatch == $eTag)) {
return response()->make('', 304, $headers);
}
- if(file_exists($path)) {
+ if
(file_exists($path)) {
return response()->make(file_get_contents($path), 200, array_merge($headers, [
- 'Content-Type' => $this->file->mimeType($path),
+ 'Content-Type'
=> $this->file->mimeType($path),
'Content-Length' => filesize($path),
]));
}
@@
-72,21
+73,21
@@
class ImageController extends Controller
{
$pageSize = 30;
$images = DB::table('images')->orderBy('created_at', 'desc')
- ->skip($page
*
$pageSize)->take($pageSize)->get();
- foreach($images as $image) {
+ ->skip($page
*
$pageSize)->take($pageSize)->get();
+ foreach
($images as $image) {
$image->thumbnail = $this->getThumbnail($image, 150, 150);
}
$hasMore = count(DB::table('images')->orderBy('created_at', 'desc')
-
->skip(($page+1)*
$pageSize)->take($pageSize)->get()) > 0;
+
->skip(($page + 1) *
$pageSize)->take($pageSize)->get()) > 0;
return response()->json([
- 'images' => $images,
+ 'images'
=> $images,
'hasMore' => $hasMore
]);
}
/**
* Get the thumbnail for an image.
- * @param $image
+ * @param
$image
* @param int $width
* @param int $height
* @return string
@@
-99,7
+100,7
@@
class ImageController extends Controller
$thumbFilePath = public_path() . $thumbPath;
// Return the thumbnail url path if already exists
- if(file_exists($thumbFilePath)) {
+ if
(file_exists($thumbFilePath)) {
return $thumbPath;
}
@@
-108,7
+109,7
@@
class ImageController extends Controller
$thumb->fit($width, $height);
// Create thumbnail folder if it does not exist
- if(!file_exists(dirname($thumbFilePath))) {
+ if
(!file_exists(dirname($thumbFilePath))) {
mkdir(dirname($thumbFilePath), 0775, true);
}
@@
-124,13
+125,14
@@
class ImageController extends Controller
*/
public function upload(Request $request)
{
+ $this->checkPermission('image-create');
$imageUpload = $request->file('file');
$name = str_replace(' ', '-', $imageUpload->getClientOriginalName());
$storageName = substr(sha1(time()), 0, 10) . '-' . $name;
- $imagePath = '/uploads/images/'
.Date('Y-m-M').
'/';
- $storagePath = public_path(). $imagePath;
+ $imagePath = '/uploads/images/'
. Date('Y-m-M') .
'/';
+ $storagePath = public_path()
. $imagePath;
$fullPath = $storagePath . $storageName;
- while(file_exists($fullPath)) {
+ while
(file_exists($fullPath)) {
$storageName = substr(sha1(rand()), 0, 3) . $storageName;
$fullPath = $storagePath . $storageName;
}
@@
-147,12
+149,13
@@
class ImageController extends Controller
/**
* Update image details
- * @param $imageId
+ * @param
$imageId
* @param Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function update($imageId, Request $request)
{
+ $this->checkPermission('image-update');
$this->validate($request, [
'name' => 'required|min:2|string'
]);
@@
-169,6
+172,7
@@
class ImageController extends Controller
*/
public function destroy($id)
{
+ $this->checkPermission('image-delete');
$image = $this->image->findOrFail($id);
// Delete files
@@
-176,14
+180,14
@@
class ImageController extends Controller
$fileName = basename($image->url);
// Delete thumbnails
- foreach(glob($folder . '/*') as $file) {
- if(is_dir($file)) {
+ foreach
(glob($folder . '/*') as $file) {
+ if
(is_dir($file)) {
$thumbName = $file . '/' . $fileName;
- if(file_exists($file)) {
+ if
(file_exists($file)) {
unlink($thumbName);
}
// Remove thumb folder if empty
- if(count(glob($file . '/*')) === 0) {
+ if
(count(glob($file . '/*')) === 0) {
rmdir($file);
}
}
@@
-194,7
+198,7
@@
class ImageController extends Controller
$image->delete();
// Delete parent folder if empty
- if(count(glob($folder . '/*')) === 0) {
+ if
(count(glob($folder . '/*')) === 0) {
rmdir($folder);
}
return response()->json('Image Deleted');
diff --git
a/app/Http/Controllers/PageController.php
b/app/Http/Controllers/PageController.php
index 5921fce3f133c995c6d98c1d27ea03a2fb584e20..b59dd2446419ce6788efa6538eae077b7c02061f 100644
(file)
--- a/
app/Http/Controllers/PageController.php
+++ b/
app/Http/Controllers/PageController.php
@@
-20,8
+20,8
@@
class PageController extends Controller
/**
* PageController constructor.
- * @param PageRepo $pageRepo
- * @param BookRepo $bookRepo
+ * @param PageRepo
$pageRepo
+ * @param BookRepo
$bookRepo
* @param ChapterRepo $chapterRepo
*/
public function __construct(PageRepo $pageRepo, BookRepo $bookRepo, ChapterRepo $chapterRepo)
@@
-29,18
+29,20
@@
class PageController extends Controller
$this->pageRepo = $pageRepo;
$this->bookRepo = $bookRepo;
$this->chapterRepo = $chapterRepo;
+ parent::__construct();
}
/**
* Show the form for creating a new page.
*
- * @param $bookSlug
+ * @param
$bookSlug
* @param bool $chapterSlug
* @return Response
* @internal param bool $pageSlug
*/
public function create($bookSlug, $chapterSlug = false)
{
+ $this->checkPermission('page-create');
$book = $this->bookRepo->getBySlug($bookSlug);
$chapter = $chapterSlug ? $this->chapterRepo->getBySlug($chapterSlug, $book->id) : false;
return view('pages/create', ['book' => $book, 'chapter' => $chapter]);
@@
-50,14
+52,15
@@
class PageController extends Controller
* Store a newly created page in storage.
*
* @param Request $request
- * @param $bookSlug
+ * @param
$bookSlug
* @return Response
*/
public function store(Request $request, $bookSlug)
{
+ $this->checkPermission('page-create');
$this->validate($request, [
- 'name' => 'required|string|max:255',
- 'html' => 'required|string',
+ 'name'
=> 'required|string|max:255',
+ 'html'
=> 'required|string',
'parent' => 'integer|exists:pages,id'
]);
$book = $this->bookRepo->getBySlug($bookSlug);
@@
-66,7
+69,7
@@
class PageController extends Controller
$page->slug = $this->pageRepo->findSuitableSlug($page->name, $book->id);
$page->priority = $this->bookRepo->getNewPriority($book);
- if($request->has('chapter') && $this->chapterRepo->idExists($request->get('chapter'))) {
+ if
($request->has('chapter') && $this->chapterRepo->idExists($request->get('chapter'))) {
$page->chapter_id = $request->get('chapter');
}
@@
-103,6
+106,7
@@
class PageController extends Controller
*/
public function edit($bookSlug, $pageSlug)
{
+ $this->checkPermission('page-update');
$book = $this->bookRepo->getBySlug($bookSlug);
$page = $this->pageRepo->getBySlug($pageSlug, $book->id);
return view('pages/edit', ['page' => $page, 'book' => $book, 'current' => $page]);
@@
-112,12
+116,13
@@
class PageController extends Controller
* Update the specified page in storage.
*
* @param Request $request
- * @param $bookSlug
- * @param $pageSlug
+ * @param
$bookSlug
+ * @param
$pageSlug
* @return Response
*/
public function update(Request $request, $bookSlug, $pageSlug)
{
+ $this->checkPermission('page-update');
$book = $this->bookRepo->getBySlug($bookSlug);
$page = $this->pageRepo->getBySlug($pageSlug, $book->id);
$this->pageRepo->updatePage($page, $book->id, $request->all());
@@
-145,7
+150,7
@@
class PageController extends Controller
public function searchAll(Request $request)
{
$searchTerm = $request->get('term');
- if(empty($searchTerm)) return redirect()->back();
+ if
(empty($searchTerm)) return redirect()->back();
$pages = $this->pageRepo->getBySearch($searchTerm);
return view('pages/search-results', ['pages' => $pages, 'searchTerm' => $searchTerm]);
@@
-158,6
+163,7
@@
class PageController extends Controller
*/
public function sortPages($bookSlug)
{
+ $this->checkPermission('book-update');
$book = $this->bookRepo->getBySlug($bookSlug);
return view('pages/sort', ['book' => $book, 'current' => $book]);
}
@@
-165,26
+171,27
@@
class PageController extends Controller
/**
* Saves an array of sort mapping to pages and chapters.
*
- * @param $bookSlug
+ * @param
$bookSlug
* @param Request $request
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function savePageSort($bookSlug, Request $request)
{
+ $this->checkPermission('book-update');
$book = $this->bookRepo->getBySlug($bookSlug);
// Return if no map sent
- if(!$request->has('sort-tree')) {
+ if
(!$request->has('sort-tree')) {
return redirect($book->getUrl());
}
// Sort pages and chapters
$sortMap = json_decode($request->get('sort-tree'));
- foreach($sortMap as $index => $bookChild) {
+ foreach
($sortMap as $index => $bookChild) {
$id = $bookChild->id;
$isPage = $bookChild->type == 'page';
$model = $isPage ? $this->pageRepo->getById($id) : $this->chapterRepo->getById($id);
$model->priority = $index;
- if($isPage) {
+ if
($isPage) {
$model->chapter_id = ($bookChild->parentChapter === false) ? 0 : $bookChild->parentChapter;
}
$model->save();
@@
-201,6
+208,7
@@
class PageController extends Controller
*/
public function showDelete($bookSlug, $pageSlug)
{
+ $this->checkPermission('page-delete');
$book = $this->bookRepo->getBySlug($bookSlug);
$page = $this->pageRepo->getBySlug($pageSlug, $book->id);
return view('pages/delete', ['book' => $book, 'page' => $page, 'current' => $page]);
@@
-216,6
+224,7
@@
class PageController extends Controller
*/
public function destroy($bookSlug, $pageSlug)
{
+ $this->checkPermission('page-delete');
$book = $this->bookRepo->getBySlug($bookSlug);
$page = $this->pageRepo->getBySlug($pageSlug, $book->id);
Activity::addMessage('page_delete', $book->id, $page->name);
@@
-255,6
+264,7
@@
class PageController extends Controller
public function restoreRevision($bookSlug, $pageSlug, $revisionId)
{
+ $this->checkPermission('page-update');
$book = $this->bookRepo->getBySlug($bookSlug);
$page = $this->pageRepo->getBySlug($pageSlug, $book->id);
$revision = $this->pageRepo->getRevisionById($revisionId);
diff --git
a/app/Http/Controllers/UserController.php
b/app/Http/Controllers/UserController.php
index 07d2cac9d2f1ce315e0d9d6fa6b605d20840ff5c..0266d26716ee9a73b976cff3cb5b57a248454c65 100644
(file)
--- a/
app/Http/Controllers/UserController.php
+++ b/
app/Http/Controllers/UserController.php
@@
-6,7
+6,6
@@
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Oxbow\Http\Requests;
-use Oxbow\Http\Controllers\Controller;
use Oxbow\User;
class UserController extends Controller
@@
-21,9
+20,9
@@
class UserController extends Controller
public function __construct(User $user)
{
$this->user = $user;
+ parent::__construct();
}
-
/**
* Display a listing of the users.
*
@@
-32,7
+31,7
@@
class UserController extends Controller
public function index()
{
$users = $this->user->all();
- return view('users/index', ['users'=> $users]);
+ return view('users/index', ['users'
=> $users]);
}
/**
@@
-42,27
+41,32
@@
class UserController extends Controller
*/
public function create()
{
+ $this->checkPermission('user-create');
return view('users/create');
}
/**
* Store a newly created user in storage.
*
- * @param Request
$request
+ * @param Request $request
* @return Response
*/
public function store(Request $request)
{
+ $this->checkPermission('user-create');
$this->validate($request, [
- 'name' => 'required',
- 'email' => 'required|email',
- 'password' => 'required|min:5',
- 'password-confirm' => 'required|same:password'
+ 'name' => 'required',
+ 'email' => 'required|email',
+ 'password' => 'required|min:5',
+ 'password-confirm' => 'required|same:password',
+ 'role' => 'required|exists:roles,id'
]);
$user = $this->user->fill($request->all());
$user->password = Hash::make($request->get('password'));
$user->save();
+
+ $user->attachRoleId($request->get('role'));
return redirect('/users');
}
@@
-70,11
+74,14
@@
class UserController extends Controller
/**
* Show the form for editing the specified user.
*
- * @param int
$id
+ * @param int $id
* @return Response
*/
public function edit($id)
{
+ $this->checkPermissionOr('user-update', function () use ($id) {
+ return $this->currentUser->id == $id;
+ });
$user = $this->user->findOrFail($id);
return view('users/edit', ['user' => $user]);
}
@@
-82,23
+89,31
@@
class UserController extends Controller
/**
* Update the specified user in storage.
*
- * @param Request
$request
- * @param int $id
+ * @param Request $request
+ * @param int
$id
* @return Response
*/
public function update(Request $request, $id)
{
+ $this->checkPermissionOr('user-update', function () use ($id) {
+ return $this->currentUser->id == $id;
+ });
$this->validate($request, [
- 'name' => 'required',
- 'email' => 'required|email',
- 'password' => 'min:5',
- 'password-confirm' => 'same:password'
+ 'name' => 'required',
+ 'email' => 'required|email',
+ 'password' => 'min:5',
+ 'password-confirm' => 'same:password',
+ 'role' => 'exists:roles,id'
]);
$user = $this->user->findOrFail($id);
$user->fill($request->all());
- if($request->has('password') && $request->get('password') != '') {
+ if ($this->currentUser->can('user-update') && $request->has('role')) {
+ $user->attachRoleId($request->get('role'));
+ }
+
+ if ($request->has('password') && $request->get('password') != '') {
$password = $request->get('password');
$user->password = Hash::make($password);
}
@@
-113,6
+128,9
@@
class UserController extends Controller
*/
public function delete($id)
{
+ $this->checkPermissionOr('user-delete', function () use ($id) {
+ return $this->currentUser->id == $id;
+ });
$user = $this->user->findOrFail($id);
return view('users/delete', ['user' => $user]);
}
@@
-120,11
+138,14
@@
class UserController extends Controller
/**
* Remove the specified user from storage.
*
- * @param int
$id
+ * @param int $id
* @return Response
*/
public function destroy($id)
{
+ $this->checkPermissionOr('user-delete', function () use ($id) {
+ return $this->currentUser->id == $id;
+ });
$user = $this->user->findOrFail($id);
$user->delete();
return redirect('/users');
diff --git
a/app/Http/Kernel.php
b/app/Http/Kernel.php
index 9be234e3fb50dae65e0c60556596dc64fcc96430..9f3444c887c5000eba36603223533141c881e261 100644
(file)
--- a/
app/Http/Kernel.php
+++ b/
app/Http/Kernel.php
@@
-26,8
+26,9
@@
class Kernel extends HttpKernel
* @var array
*/
protected $routeMiddleware = [
- 'auth' => \Oxbow\Http\Middleware\Authenticate::class,
+ 'auth'
=> \Oxbow\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
- 'guest' => \Oxbow\Http\Middleware\RedirectIfAuthenticated::class,
+ 'guest' => \Oxbow\Http\Middleware\RedirectIfAuthenticated::class,
+ 'perm' => \Oxbow\Http\Middleware\PermissionMiddleware::class
];
}
diff --git a/app/Http/Middleware/PermissionMiddleware.php
b/app/Http/Middleware/PermissionMiddleware.php
new file mode 100644
(file)
index 0000000..
c832aea
--- /dev/null
+++ b/
app/Http/Middleware/PermissionMiddleware.php
@@ -0,0
+1,28
@@
+<?php
+
+namespace Oxbow\Http\Middleware;
+
+use Closure;
+use Illuminate\Support\Facades\Session;
+
+class PermissionMiddleware
+{
+ /**
+ * Handle an incoming request.
+ *
+ * @param \Illuminate\Http\Request $request
+ * @param \Closure $next
+ * @param $permission
+ * @return mixed
+ */
+ public function handle($request, Closure $next, $permission)
+ {
+
+ if (!$request->user() || !$request->user()->can($permission)) {
+ Session::flash('error', trans('errors.permission'));
+ return redirect()->back();
+ }
+
+ return $next($request);
+ }
+}
diff --git
a/app/Http/routes.php
b/app/Http/routes.php
index 4811b74d01de13ab8039c18a26e1f93297b417d2..63b0d5262f4de2c032a733610bf864b50af2808a 100644
(file)
--- a/
app/Http/routes.php
+++ b/
app/Http/routes.php
@@
-11,12
+11,14
@@
|
*/
-
+Route::get('/test', function () {
+ return Auth::user()->can('users-edit');
+});
// Authentication routes...
-Route::group(['middleware' => 'auth'], function() {
+Route::group(['middleware' => 'auth'], function
() {
- Route::group(['prefix' => 'books'], function() {
+ Route::group(['prefix' => 'books'], function
() {
// Books
Route::get('/', 'BookController@index');
diff --git a/app/Permission.php
b/app/Permission.php
new file mode 100644
(file)
index 0000000..
4477690
--- /dev/null
+++ b/
app/Permission.php
@@ -0,0
+1,16
@@
+<?php
+
+namespace Oxbow;
+
+use Illuminate\Database\Eloquent\Model;
+
+class Permission extends Model
+{
+ /**
+ * The roles that belong to the permission.
+ */
+ public function roles()
+ {
+ return $this->belongsToMany('Oxbow\Permissions');
+ }
+}
diff --git
a/app/Providers/AppServiceProvider.php
b/app/Providers/AppServiceProvider.php
index 51e205b79e58c44b01350a33528ca37616356db5..5be29756d8b55ff6e584010d1b4a9d89d8bc63ab 100644
(file)
--- a/
app/Providers/AppServiceProvider.php
+++ b/
app/Providers/AppServiceProvider.php
@@
-2,7
+2,9
@@
namespace Oxbow\Providers;
+use Illuminate\Support\Facades\Auth;
use Illuminate\Support\ServiceProvider;
+use Oxbow\User;
class AppServiceProvider extends ServiceProvider
{
diff --git a/app/Role.php
b/app/Role.php
new file mode 100644
(file)
index 0000000..
dd95586
--- /dev/null
+++ b/
app/Role.php
@@ -0,0
+1,34
@@
+<?php
+
+namespace Oxbow;
+
+use Illuminate\Database\Eloquent\Model;
+
+class Role extends Model
+{
+ /**
+ * The roles that belong to the role.
+ */
+ public function users()
+ {
+ return $this->belongsToMany('Oxbow\User');
+ }
+
+ /**
+ * The permissions that belong to the role.
+ */
+ public function permissions()
+ {
+ return $this->belongsToMany('Oxbow\Permission');
+ }
+
+ /**
+ * Add a permission to this role.
+ * @param Permission $permission
+ */
+ public function attachPermission(Permission $permission)
+ {
+ $this->permissions()->attach($permission->id);
+ }
+
+}
diff --git
a/app/User.php
b/app/User.php
index c7f547aadf502f9ed272fd2d13c1a87fff398369..d58ded82ebc694f6bc5701e3fc265ac8d8644ff8 100644
(file)
--- a/
app/User.php
+++ b/
app/User.php
@@
-40,13
+40,63
@@
class User extends Model implements AuthenticatableContract, CanResetPasswordCon
{
return new static([
'email' => 'guest',
- 'name' => 'Guest'
+ 'name'
=> 'Guest'
]);
}
+ /**
+ * Permissions and roles
+ */
+
+ /**
+ * The roles that belong to the user.
+ */
+ public function roles()
+ {
+ return $this->belongsToMany('Oxbow\Role');
+ }
+
+ public function getRoleAttribute()
+ {
+ return $this->roles()->first();
+ }
+
+ /**
+ * Check if the user has a particular permission.
+ * @param $permissionName
+ * @return bool
+ */
+ public function can($permissionName)
+ {
+ $permissions = $this->role->permissions()->get();
+ $permissionSearch = $permissions->search(function ($item, $key) use ($permissionName) {
+ return $item->name == $permissionName;
+ });
+ return $permissionSearch !== false;
+ }
+
+ /**
+ * Attach a role to this user.
+ * @param Role $role
+ */
+ public function attachRole(Role $role)
+ {
+ $this->attachRoleId($role->id);
+ }
+
+ /**
+ * Attach a role id to this user.
+ * @param $id
+ */
+ public function attachRoleId($id)
+ {
+ $this->roles()->sync([$id]);
+ }
+
/**
* Returns the user's avatar,
* Uses Gravatar as the avatar service.
+ *
* @param int $size
* @return string
*/
diff --git
a/database/migrations/2014_10_12_000000_create_users_table.php
b/database/migrations/2014_10_12_000000_create_users_table.php
index 65d3d083882138e3d24113d29b6f575dae014231..68a2940a49f876a22c4be8f05c7b08e5d49ceef7 100644
(file)
--- a/
database/migrations/2014_10_12_000000_create_users_table.php
+++ b/
database/migrations/2014_10_12_000000_create_users_table.php
@@
-20,6
+20,12
@@
class CreateUsersTable extends Migration
$table->rememberToken();
$table->timestamps();
});
+
+ \Oxbow\User::create([
+ 'name' => 'Admin',
+ 'email' => 'admin@admin.com',
+ 'password' => \Illuminate\Support\Facades\Hash::make('password')
+ ]);
}
/**
diff --git a/database/migrations/2015_08_29_105422_add_roles_and_permissions.php
b/database/migrations/2015_08_29_105422_add_roles_and_permissions.php
new file mode 100644
(file)
index 0000000..
1f7f612
--- /dev/null
+++ b/
database/migrations/2015_08_29_105422_add_roles_and_permissions.php
@@ -0,0
+1,137
@@
+<?php
+
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Database\Migrations\Migration;
+
+/**
+ * Much of this code has been taken from entrust,
+ * a role & permission management solution for Laravel.
+ *
+ * Full attribution of the database Schema shown below goes to the entrust project.
+ *
+ * @license MIT
+ * @package Zizaco\Entrust
+ * @url https://github.com/Zizaco/entrust
+ */
+class AddRolesAndPermissions extends Migration
+{
+ /**
+ * Run the migrations.
+ *
+ * @return void
+ */
+ public function up()
+ {
+ // Create table for storing roles
+ Schema::create('roles', function (Blueprint $table) {
+ $table->increments('id');
+ $table->string('name')->unique();
+ $table->string('display_name')->nullable();
+ $table->string('description')->nullable();
+ $table->timestamps();
+ });
+
+ // Create table for associating roles to users (Many-to-Many)
+ Schema::create('role_user', function (Blueprint $table) {
+ $table->integer('user_id')->unsigned();
+ $table->integer('role_id')->unsigned();
+
+ $table->foreign('user_id')->references('id')->on('users')
+ ->onUpdate('cascade')->onDelete('cascade');
+ $table->foreign('role_id')->references('id')->on('roles')
+ ->onUpdate('cascade')->onDelete('cascade');
+
+ $table->primary(['user_id', 'role_id']);
+ });
+
+ // Create table for storing permissions
+ Schema::create('permissions', function (Blueprint $table) {
+ $table->increments('id');
+ $table->string('name')->unique();
+ $table->string('display_name')->nullable();
+ $table->string('description')->nullable();
+ $table->timestamps();
+ });
+
+ // Create table for associating permissions to roles (Many-to-Many)
+ Schema::create('permission_role', function (Blueprint $table) {
+ $table->integer('permission_id')->unsigned();
+ $table->integer('role_id')->unsigned();
+
+ $table->foreign('permission_id')->references('id')->on('permissions')
+ ->onUpdate('cascade')->onDelete('cascade');
+ $table->foreign('role_id')->references('id')->on('roles')
+ ->onUpdate('cascade')->onDelete('cascade');
+
+ $table->primary(['permission_id', 'role_id']);
+ });
+
+
+ // Create default roles
+ $admin = new \Oxbow\Role();
+ $admin->name = 'admin';
+ $admin->display_name = 'Admin';
+ $admin->description = 'Administrator of the whole application';
+ $admin->save();
+
+ $editor = new \Oxbow\Role();
+ $editor->name = 'editor';
+ $editor->display_name = 'Editor';
+ $editor->description = 'User can edit Books, Chapters & Pages';
+ $editor->save();
+
+ $viewer = new \Oxbow\Role();
+ $viewer->name = 'viewer';
+ $viewer->display_name = 'Viewer';
+ $viewer->description = 'User can view books & their content behind authentication';
+ $viewer->save();
+
+ // Create default CRUD permissions and allocate to admins and editors
+ $entities = ['Book', 'Page', 'Chapter', 'Image'];
+ $ops = ['Create', 'Update', 'Delete'];
+ foreach ($entities as $entity) {
+ foreach ($ops as $op) {
+ $newPermission = new \Oxbow\Permission();
+ $newPermission->name = strtolower($entity) . '-' . strtolower($op);
+ $newPermission->display_name = $op . ' ' . $entity . 's';
+ $newPermission->save();
+ $admin->attachPermission($newPermission);
+ $editor->attachPermission($newPermission);
+ }
+ }
+
+ // Create admin permissions
+ $entities = ['Settings', 'User'];
+ $ops = ['Create', 'Update', 'Delete'];
+ foreach ($entities as $entity) {
+ foreach ($ops as $op) {
+ $newPermission = new \Oxbow\Permission();
+ $newPermission->name = strtolower($entity) . '-' . strtolower($op);
+ $newPermission->display_name = $op . ' ' . $entity;
+ $newPermission->save();
+ $admin->attachPermission($newPermission);
+ }
+ }
+
+ // Set all current users as admins
+ // (At this point only the initially create user should be an admin)
+ $users = \Oxbow\User::all();
+ foreach ($users as $user) {
+ $user->attachRole($admin);
+ }
+
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::drop('permission_role');
+ Schema::drop('permissions');
+ Schema::drop('role_user');
+ Schema::drop('roles');
+ }
+}
diff --git
a/database/seeds/DatabaseSeeder.php
b/database/seeds/DatabaseSeeder.php
index 633b5e736f2e3c1d269c2f6f5b0dbe30f3718552..988ea2100519ef6598cc0b13f69105e8b8682355 100644
(file)
--- a/
database/seeds/DatabaseSeeder.php
+++ b/
database/seeds/DatabaseSeeder.php
@@
-15,11
+15,6
@@
class DatabaseSeeder extends Seeder
Model::unguard();
// $this->call(UserTableSeeder::class);
- \Oxbow\User::create([
- 'name' => 'Admin',
- 'email' => 'admin@admin.com',
- 'password' => \Illuminate\Support\Facades\Hash::make('password')
- ]);
Model::reguard();
}
diff --git
a/resources/assets/sass/_blocks.scss
b/resources/assets/sass/_blocks.scss
index 9ebae47c1db9bec4333f7a3e987bf0c465e600df..bf23eb565ce6a364f4ebe31a7803f79767c694df 100644
(file)
--- a/
resources/assets/sass/_blocks.scss
+++ b/
resources/assets/sass/_blocks.scss
@@
-60,6
+60,11
@@
&.large {
padding: $-xl;
}
+ >h1, >h2, >h3, >h4 {
+ &:first-child {
+ margin-top: 0.1em;
+ }
+ }
}
.padded-vertical, .padded-top {
padding-top: $-m;
@@
-67,6
+72,7
@@
padding-top: $-xl;
}
}
+
.padded-vertical, .padded-bottom {
padding-bottom: $-m;
&.large {
diff --git
a/resources/assets/sass/_text.scss
b/resources/assets/sass/_text.scss
index 3f236a9ebab697546cf529a834cd37fe3e4103c1..8d7950e2cb6326f3bfa4811b7578a8b9f48550b5 100644
(file)
--- a/
resources/assets/sass/_text.scss
+++ b/
resources/assets/sass/_text.scss
@@
-197,7
+197,7
@@
p.secondary, p .secondary, span.secondary, .text-secondary {
*/
ul {
list-style: disc;
- margin-left: $-m;
+ margin-left: $-m
*1.5
;
}
/*
diff --git a/resources/lang/en/errors.php
b/resources/lang/en/errors.php
new file mode 100644
(file)
index 0000000..
53785b6
--- /dev/null
+++ b/
resources/lang/en/errors.php
@@ -0,0
+1,11
@@
+<?php
+
+return [
+
+ /**
+ * Error text strings.
+ */
+
+ // Pages
+ 'permission' => 'You do not have permission to access the requested page.',
+];
\ No newline at end of file
diff --git a/resources/views/form/model-select.blade.php
b/resources/views/form/model-select.blade.php
new file mode 100644
(file)
index 0000000..
19b4cce
--- /dev/null
+++ b/
resources/views/form/model-select.blade.php
@@ -0,0
+1,15
@@
+
+<select id="{{ $name }}" name="{{ $name }}">
+ @foreach($options as $option)
+ <option value="{{$option->id}}"
+ @if($errors->has($name)) class="neg" @endif
+ @if(isset($model) || old($name)) @if(old($name) && old($name) === $option->id) selected @elseif(isset($model) && $model->id === $option->id) selected @endif @endif
+ >
+ {{ $option->$displayKey }}
+ </option>
+ @endforeach
+</select>
+
+@if($errors->has($name))
+ <div class="text-neg text-small">{{ $errors->first($name) }}</div>
+@endif
\ No newline at end of file
diff --git
a/resources/views/users/edit.blade.php
b/resources/views/users/edit.blade.php
index 1e23a1c3bcbd6e5cc553761e964931d2c1ac6238..cb56ad9052f06453b06a8d977e4c8de8b13c688c 100644
(file)
--- a/
resources/views/users/edit.blade.php
+++ b/
resources/views/users/edit.blade.php
@@
-14,6
+14,7
@@
<div class="row">
<div class="page-content">
+
<div class="row">
<div class="col-md-6">
<h1>Edit User</h1>
@@
-33,6
+34,24
@@
</div>
</div>
</div>
+
+ <hr class="margin-top large">
+
+ <div class="row">
+ <div class="col-md-12">
+ <h3>Permissions</h3>
+ <p>User Role: <strong>{{$user->role->display_name}}</strong>.</p>
+ <ul class="text-muted">
+ @foreach($user->role->permissions as $permission)
+ <li>
+ {{ $permission->display_name }}
+ </li>
+ @endforeach
+ </ul>
+
+ </div>
+ </div>
+
</div>
</div>
diff --git
a/resources/views/users/form.blade.php
b/resources/views/users/form.blade.php
index 5d5aa140c6eb6ae79057c651db488a49413ea6e6..f3896f2e804d9a765e711c37253709bdcf326c44 100644
(file)
--- a/
resources/views/users/form.blade.php
+++ b/
resources/views/users/form.blade.php
@@
-1,4
+1,3
@@
-
<div class="form-group">
<label for="name">Name</label>
@include('form/text', ['name' => 'name'])
@@
-10,11
+9,18
@@
</div>
@if(isset($model))
-<div class="form-group">
+
<div class="form-group">
<span class="text-muted">
Only fill the below if you would like <br>to change your password:
</span>
-</div>
+ </div>
+@endif
+
+@if($currentUser->can('user-update'))
+ <div class="form-group">
+ <label for="role">User Role</label>
+ @include('form/model-select', ['name' => 'role', 'options' => \Oxbow\Role::all(), 'displayKey' => 'display_name'])
+ </div>
@endif
<div class="form-group">
diff --git
a/resources/views/users/index.blade.php
b/resources/views/users/index.blade.php
index 2fd51decdfc1dfc465d5cd72145e8088be0b3b96..730ead8aacea6edf70b7ac517e1f9ca608eb8b43 100644
(file)
--- a/
resources/views/users/index.blade.php
+++ b/
resources/views/users/index.blade.php
@@
-8,7
+8,9
@@
<div class="col-md-6"></div>
<div class="col-md-6 faded">
<div class="action-buttons">
- <a href="/users/create" class="text-pos"><i class="zmdi zmdi-account-add"></i>New User</a>
+ @if($currentUser->can('user-create'))
+ <a href="/users/create" class="text-pos"><i class="zmdi zmdi-account-add"></i>New User</a>
+ @endif
</div>
</div>
</div>
@@
-21,12
+23,22
@@
<th></th>
<th>Name</th>
<th>Email</th>
+ <th>User Type</th>
</tr>
@foreach($users as $user)
<tr>
<td style="line-height: 0;"><img class="avatar" src="{{$user->getAvatar(40)}}" alt="{{$user->name}}"></td>
- <td><a href="/users/{{$user->id}}">{{$user->name}}</a></td>
+ <td>
+ @if($currentUser->can('user-update') || $currentUser->id == $user->id)
+ <a href="/users/{{$user->id}}">
+ @endif
+ {{$user->name}}
+ @if($currentUser->can('user-update') || $currentUser->id == $user->id)
+ </a>
+ @endif
+ </td>
<td>{{$user->email}}</td>
+ <td>{{ $user->role->display_name }}</td>
</tr>
@endforeach
</table>
hide
Morty Proxy
This is a
proxified and sanitized
view of the page, visit
original site
.