Showing
24 changed files
with
478 additions
and
46 deletions
| ... | @@ -26,6 +26,7 @@ class BookController extends Controller | ... | @@ -26,6 +26,7 @@ class BookController extends Controller |
| 26 | { | 26 | { |
| 27 | $this->bookRepo = $bookRepo; | 27 | $this->bookRepo = $bookRepo; |
| 28 | $this->pageRepo = $pageRepo; | 28 | $this->pageRepo = $pageRepo; |
| 29 | + parent::__construct(); | ||
| 29 | } | 30 | } |
| 30 | 31 | ||
| 31 | /** | 32 | /** |
| ... | @@ -46,6 +47,7 @@ class BookController extends Controller | ... | @@ -46,6 +47,7 @@ class BookController extends Controller |
| 46 | */ | 47 | */ |
| 47 | public function create() | 48 | public function create() |
| 48 | { | 49 | { |
| 50 | + $this->checkPermission('book-create'); | ||
| 49 | return view('books/create'); | 51 | return view('books/create'); |
| 50 | } | 52 | } |
| 51 | 53 | ||
| ... | @@ -57,6 +59,7 @@ class BookController extends Controller | ... | @@ -57,6 +59,7 @@ class BookController extends Controller |
| 57 | */ | 59 | */ |
| 58 | public function store(Request $request) | 60 | public function store(Request $request) |
| 59 | { | 61 | { |
| 62 | + $this->checkPermission('book-create'); | ||
| 60 | $this->validate($request, [ | 63 | $this->validate($request, [ |
| 61 | 'name' => 'required|string|max:255', | 64 | 'name' => 'required|string|max:255', |
| 62 | 'description' => 'string|max:1000' | 65 | 'description' => 'string|max:1000' |
| ... | @@ -90,6 +93,7 @@ class BookController extends Controller | ... | @@ -90,6 +93,7 @@ class BookController extends Controller |
| 90 | */ | 93 | */ |
| 91 | public function edit($slug) | 94 | public function edit($slug) |
| 92 | { | 95 | { |
| 96 | + $this->checkPermission('book-update'); | ||
| 93 | $book = $this->bookRepo->getBySlug($slug); | 97 | $book = $this->bookRepo->getBySlug($slug); |
| 94 | return view('books/edit', ['book' => $book, 'current' => $book]); | 98 | return view('books/edit', ['book' => $book, 'current' => $book]); |
| 95 | } | 99 | } |
| ... | @@ -103,6 +107,7 @@ class BookController extends Controller | ... | @@ -103,6 +107,7 @@ class BookController extends Controller |
| 103 | */ | 107 | */ |
| 104 | public function update(Request $request, $slug) | 108 | public function update(Request $request, $slug) |
| 105 | { | 109 | { |
| 110 | + $this->checkPermission('book-update'); | ||
| 106 | $book = $this->bookRepo->getBySlug($slug); | 111 | $book = $this->bookRepo->getBySlug($slug); |
| 107 | $this->validate($request, [ | 112 | $this->validate($request, [ |
| 108 | 'name' => 'required|string|max:255', | 113 | 'name' => 'required|string|max:255', |
| ... | @@ -123,6 +128,7 @@ class BookController extends Controller | ... | @@ -123,6 +128,7 @@ class BookController extends Controller |
| 123 | */ | 128 | */ |
| 124 | public function showDelete($bookSlug) | 129 | public function showDelete($bookSlug) |
| 125 | { | 130 | { |
| 131 | + $this->checkPermission('book-delete'); | ||
| 126 | $book = $this->bookRepo->getBySlug($bookSlug); | 132 | $book = $this->bookRepo->getBySlug($bookSlug); |
| 127 | return view('books/delete', ['book' => $book, 'current' => $book]); | 133 | return view('books/delete', ['book' => $book, 'current' => $book]); |
| 128 | } | 134 | } |
| ... | @@ -135,6 +141,7 @@ class BookController extends Controller | ... | @@ -135,6 +141,7 @@ class BookController extends Controller |
| 135 | */ | 141 | */ |
| 136 | public function destroy($bookSlug) | 142 | public function destroy($bookSlug) |
| 137 | { | 143 | { |
| 144 | + $this->checkPermission('book-delete'); | ||
| 138 | $book = $this->bookRepo->getBySlug($bookSlug); | 145 | $book = $this->bookRepo->getBySlug($bookSlug); |
| 139 | Activity::addMessage('book_delete', 0, $book->name); | 146 | Activity::addMessage('book_delete', 0, $book->name); |
| 140 | $this->bookRepo->destroyBySlug($bookSlug); | 147 | $this->bookRepo->destroyBySlug($bookSlug); | ... | ... |
| ... | @@ -22,10 +22,11 @@ class ChapterController extends Controller | ... | @@ -22,10 +22,11 @@ class ChapterController extends Controller |
| 22 | * @param $bookRepo | 22 | * @param $bookRepo |
| 23 | * @param $chapterRepo | 23 | * @param $chapterRepo |
| 24 | */ | 24 | */ |
| 25 | - public function __construct(BookRepo $bookRepo,ChapterRepo $chapterRepo) | 25 | + public function __construct(BookRepo $bookRepo, ChapterRepo $chapterRepo) |
| 26 | { | 26 | { |
| 27 | $this->bookRepo = $bookRepo; | 27 | $this->bookRepo = $bookRepo; |
| 28 | $this->chapterRepo = $chapterRepo; | 28 | $this->chapterRepo = $chapterRepo; |
| 29 | + parent::__construct(); | ||
| 29 | } | 30 | } |
| 30 | 31 | ||
| 31 | 32 | ||
| ... | @@ -37,6 +38,7 @@ class ChapterController extends Controller | ... | @@ -37,6 +38,7 @@ class ChapterController extends Controller |
| 37 | */ | 38 | */ |
| 38 | public function create($bookSlug) | 39 | public function create($bookSlug) |
| 39 | { | 40 | { |
| 41 | + $this->checkPermission('chapter-create'); | ||
| 40 | $book = $this->bookRepo->getBySlug($bookSlug); | 42 | $book = $this->bookRepo->getBySlug($bookSlug); |
| 41 | return view('chapters/create', ['book' => $book, 'current' => $book]); | 43 | return view('chapters/create', ['book' => $book, 'current' => $book]); |
| 42 | } | 44 | } |
| ... | @@ -50,6 +52,7 @@ class ChapterController extends Controller | ... | @@ -50,6 +52,7 @@ class ChapterController extends Controller |
| 50 | */ | 52 | */ |
| 51 | public function store($bookSlug, Request $request) | 53 | public function store($bookSlug, Request $request) |
| 52 | { | 54 | { |
| 55 | + $this->checkPermission('chapter-create'); | ||
| 53 | $this->validate($request, [ | 56 | $this->validate($request, [ |
| 54 | 'name' => 'required|string|max:255' | 57 | 'name' => 'required|string|max:255' |
| 55 | ]); | 58 | ]); |
| ... | @@ -88,6 +91,7 @@ class ChapterController extends Controller | ... | @@ -88,6 +91,7 @@ class ChapterController extends Controller |
| 88 | */ | 91 | */ |
| 89 | public function edit($bookSlug, $chapterSlug) | 92 | public function edit($bookSlug, $chapterSlug) |
| 90 | { | 93 | { |
| 94 | + $this->checkPermission('chapter-update'); | ||
| 91 | $book = $this->bookRepo->getBySlug($bookSlug); | 95 | $book = $this->bookRepo->getBySlug($bookSlug); |
| 92 | $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id); | 96 | $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id); |
| 93 | return view('chapters/edit', ['book' => $book, 'chapter' => $chapter, 'current' => $chapter]); | 97 | return view('chapters/edit', ['book' => $book, 'chapter' => $chapter, 'current' => $chapter]); |
| ... | @@ -103,6 +107,7 @@ class ChapterController extends Controller | ... | @@ -103,6 +107,7 @@ class ChapterController extends Controller |
| 103 | */ | 107 | */ |
| 104 | public function update(Request $request, $bookSlug, $chapterSlug) | 108 | public function update(Request $request, $bookSlug, $chapterSlug) |
| 105 | { | 109 | { |
| 110 | + $this->checkPermission('chapter-update'); | ||
| 106 | $book = $this->bookRepo->getBySlug($bookSlug); | 111 | $book = $this->bookRepo->getBySlug($bookSlug); |
| 107 | $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id); | 112 | $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id); |
| 108 | $chapter->fill($request->all()); | 113 | $chapter->fill($request->all()); |
| ... | @@ -121,6 +126,7 @@ class ChapterController extends Controller | ... | @@ -121,6 +126,7 @@ class ChapterController extends Controller |
| 121 | */ | 126 | */ |
| 122 | public function showDelete($bookSlug, $chapterSlug) | 127 | public function showDelete($bookSlug, $chapterSlug) |
| 123 | { | 128 | { |
| 129 | + $this->checkPermission('chapter-delete'); | ||
| 124 | $book = $this->bookRepo->getBySlug($bookSlug); | 130 | $book = $this->bookRepo->getBySlug($bookSlug); |
| 125 | $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id); | 131 | $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id); |
| 126 | return view('chapters/delete', ['book' => $book, 'chapter' => $chapter, 'current' => $chapter]); | 132 | return view('chapters/delete', ['book' => $book, 'chapter' => $chapter, 'current' => $chapter]); |
| ... | @@ -135,10 +141,11 @@ class ChapterController extends Controller | ... | @@ -135,10 +141,11 @@ class ChapterController extends Controller |
| 135 | */ | 141 | */ |
| 136 | public function destroy($bookSlug, $chapterSlug) | 142 | public function destroy($bookSlug, $chapterSlug) |
| 137 | { | 143 | { |
| 144 | + $this->checkPermission('chapter-delete'); | ||
| 138 | $book = $this->bookRepo->getBySlug($bookSlug); | 145 | $book = $this->bookRepo->getBySlug($bookSlug); |
| 139 | $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id); | 146 | $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id); |
| 140 | - if(count($chapter->pages) > 0) { | 147 | + if (count($chapter->pages) > 0) { |
| 141 | - foreach($chapter->pages as $page) { | 148 | + foreach ($chapter->pages as $page) { |
| 142 | $page->chapter_id = 0; | 149 | $page->chapter_id = 0; |
| 143 | $page->save(); | 150 | $page->save(); |
| 144 | } | 151 | } | ... | ... |
| ... | @@ -2,10 +2,13 @@ | ... | @@ -2,10 +2,13 @@ |
| 2 | 2 | ||
| 3 | namespace Oxbow\Http\Controllers; | 3 | namespace Oxbow\Http\Controllers; |
| 4 | 4 | ||
| 5 | +use HttpRequestException; | ||
| 5 | use Illuminate\Foundation\Bus\DispatchesJobs; | 6 | use Illuminate\Foundation\Bus\DispatchesJobs; |
| 7 | +use Illuminate\Http\Exception\HttpResponseException; | ||
| 6 | use Illuminate\Routing\Controller as BaseController; | 8 | use Illuminate\Routing\Controller as BaseController; |
| 7 | use Illuminate\Foundation\Validation\ValidatesRequests; | 9 | use Illuminate\Foundation\Validation\ValidatesRequests; |
| 8 | use Illuminate\Support\Facades\Auth; | 10 | use Illuminate\Support\Facades\Auth; |
| 11 | +use Illuminate\Support\Facades\Session; | ||
| 9 | use Oxbow\User; | 12 | use Oxbow\User; |
| 10 | 13 | ||
| 11 | abstract class Controller extends BaseController | 14 | abstract class Controller extends BaseController |
| ... | @@ -13,16 +16,55 @@ abstract class Controller extends BaseController | ... | @@ -13,16 +16,55 @@ abstract class Controller extends BaseController |
| 13 | use DispatchesJobs, ValidatesRequests; | 16 | use DispatchesJobs, ValidatesRequests; |
| 14 | 17 | ||
| 15 | /** | 18 | /** |
| 19 | + * @var User static | ||
| 20 | + */ | ||
| 21 | + protected $currentUser; | ||
| 22 | + /** | ||
| 23 | + * @var bool | ||
| 24 | + */ | ||
| 25 | + protected $signedIn; | ||
| 26 | + | ||
| 27 | + /** | ||
| 16 | * Controller constructor. | 28 | * Controller constructor. |
| 17 | */ | 29 | */ |
| 18 | public function __construct() | 30 | public function __construct() |
| 19 | { | 31 | { |
| 20 | - view()->share('signedIn', Auth::check()); | 32 | + // Get a user instance for the current user |
| 21 | $user = Auth::user(); | 33 | $user = Auth::user(); |
| 22 | - if(!$user) { | 34 | + if (!$user) { |
| 23 | $user = User::getDefault(); | 35 | $user = User::getDefault(); |
| 24 | } | 36 | } |
| 25 | - view()->share('user', $user); | 37 | + // Share variables with views |
| 38 | + view()->share('signedIn', Auth::check()); | ||
| 39 | + view()->share('currentUser', $user); | ||
| 40 | + // Share variables with controllers | ||
| 41 | + $this->currentUser = $user; | ||
| 42 | + $this->signedIn = Auth::check(); | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + /** | ||
| 46 | + * Checks for a permission. | ||
| 47 | + * | ||
| 48 | + * @param $permissionName | ||
| 49 | + * @return bool|\Illuminate\Http\RedirectResponse | ||
| 50 | + */ | ||
| 51 | + protected function checkPermission($permissionName) | ||
| 52 | + { | ||
| 53 | + if (!$this->currentUser || !$this->currentUser->can($permissionName)) { | ||
| 54 | + Session::flash('error', trans('errors.permission')); | ||
| 55 | + throw new HttpResponseException( | ||
| 56 | + redirect()->back() | ||
| 57 | + ); | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + return true; | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + protected function checkPermissionOr($permissionName, $callback) | ||
| 64 | + { | ||
| 65 | + $callbackResult = $callback(); | ||
| 66 | + if ($callbackResult === false) $this->checkPermission($permissionName); | ||
| 67 | + return true; | ||
| 26 | } | 68 | } |
| 27 | 69 | ||
| 28 | } | 70 | } | ... | ... |
| ... | @@ -25,6 +25,7 @@ class HomeController extends Controller | ... | @@ -25,6 +25,7 @@ class HomeController extends Controller |
| 25 | { | 25 | { |
| 26 | $this->activityService = $activityService; | 26 | $this->activityService = $activityService; |
| 27 | $this->bookRepo = $bookRepo; | 27 | $this->bookRepo = $bookRepo; |
| 28 | + parent::__construct(); | ||
| 28 | } | 29 | } |
| 29 | 30 | ||
| 30 | 31 | ... | ... |
| ... | @@ -24,6 +24,7 @@ class ImageController extends Controller | ... | @@ -24,6 +24,7 @@ class ImageController extends Controller |
| 24 | { | 24 | { |
| 25 | $this->image = $image; | 25 | $this->image = $image; |
| 26 | $this->file = $file; | 26 | $this->file = $file; |
| 27 | + parent::__construct(); | ||
| 27 | } | 28 | } |
| 28 | 29 | ||
| 29 | /** | 30 | /** |
| ... | @@ -33,7 +34,7 @@ class ImageController extends Controller | ... | @@ -33,7 +34,7 @@ class ImageController extends Controller |
| 33 | */ | 34 | */ |
| 34 | public function getImage(Request $request) | 35 | public function getImage(Request $request) |
| 35 | { | 36 | { |
| 36 | - $cacheTime = 60*60*24; | 37 | + $cacheTime = 60 * 60 * 24; |
| 37 | $path = storage_path() . '/' . $request->path(); | 38 | $path = storage_path() . '/' . $request->path(); |
| 38 | $modifiedTime = $this->file->lastModified($path); | 39 | $modifiedTime = $this->file->lastModified($path); |
| 39 | $eTag = md5($modifiedTime . $path); | 40 | $eTag = md5($modifiedTime . $path); |
| ... | @@ -50,11 +51,11 @@ class ImageController extends Controller | ... | @@ -50,11 +51,11 @@ class ImageController extends Controller |
| 50 | 51 | ||
| 51 | $browserModifiedSince = $request->header('If-Modified-Since'); | 52 | $browserModifiedSince = $request->header('If-Modified-Since'); |
| 52 | $browserNoneMatch = $request->header('If-None-Match'); | 53 | $browserNoneMatch = $request->header('If-None-Match'); |
| 53 | - if($browserModifiedSince !== null && file_exists($path) && ($browserModifiedSince == $headerLastModified || $browserNoneMatch == $eTag)) { | 54 | + if ($browserModifiedSince !== null && file_exists($path) && ($browserModifiedSince == $headerLastModified || $browserNoneMatch == $eTag)) { |
| 54 | return response()->make('', 304, $headers); | 55 | return response()->make('', 304, $headers); |
| 55 | } | 56 | } |
| 56 | 57 | ||
| 57 | - if(file_exists($path)) { | 58 | + if (file_exists($path)) { |
| 58 | return response()->make(file_get_contents($path), 200, array_merge($headers, [ | 59 | return response()->make(file_get_contents($path), 200, array_merge($headers, [ |
| 59 | 'Content-Type' => $this->file->mimeType($path), | 60 | 'Content-Type' => $this->file->mimeType($path), |
| 60 | 'Content-Length' => filesize($path), | 61 | 'Content-Length' => filesize($path), |
| ... | @@ -72,12 +73,12 @@ class ImageController extends Controller | ... | @@ -72,12 +73,12 @@ class ImageController extends Controller |
| 72 | { | 73 | { |
| 73 | $pageSize = 30; | 74 | $pageSize = 30; |
| 74 | $images = DB::table('images')->orderBy('created_at', 'desc') | 75 | $images = DB::table('images')->orderBy('created_at', 'desc') |
| 75 | - ->skip($page*$pageSize)->take($pageSize)->get(); | 76 | + ->skip($page * $pageSize)->take($pageSize)->get(); |
| 76 | - foreach($images as $image) { | 77 | + foreach ($images as $image) { |
| 77 | $image->thumbnail = $this->getThumbnail($image, 150, 150); | 78 | $image->thumbnail = $this->getThumbnail($image, 150, 150); |
| 78 | } | 79 | } |
| 79 | $hasMore = count(DB::table('images')->orderBy('created_at', 'desc') | 80 | $hasMore = count(DB::table('images')->orderBy('created_at', 'desc') |
| 80 | - ->skip(($page+1)*$pageSize)->take($pageSize)->get()) > 0; | 81 | + ->skip(($page + 1) * $pageSize)->take($pageSize)->get()) > 0; |
| 81 | return response()->json([ | 82 | return response()->json([ |
| 82 | 'images' => $images, | 83 | 'images' => $images, |
| 83 | 'hasMore' => $hasMore | 84 | 'hasMore' => $hasMore |
| ... | @@ -99,7 +100,7 @@ class ImageController extends Controller | ... | @@ -99,7 +100,7 @@ class ImageController extends Controller |
| 99 | $thumbFilePath = public_path() . $thumbPath; | 100 | $thumbFilePath = public_path() . $thumbPath; |
| 100 | 101 | ||
| 101 | // Return the thumbnail url path if already exists | 102 | // Return the thumbnail url path if already exists |
| 102 | - if(file_exists($thumbFilePath)) { | 103 | + if (file_exists($thumbFilePath)) { |
| 103 | return $thumbPath; | 104 | return $thumbPath; |
| 104 | } | 105 | } |
| 105 | 106 | ||
| ... | @@ -108,7 +109,7 @@ class ImageController extends Controller | ... | @@ -108,7 +109,7 @@ class ImageController extends Controller |
| 108 | $thumb->fit($width, $height); | 109 | $thumb->fit($width, $height); |
| 109 | 110 | ||
| 110 | // Create thumbnail folder if it does not exist | 111 | // Create thumbnail folder if it does not exist |
| 111 | - if(!file_exists(dirname($thumbFilePath))) { | 112 | + if (!file_exists(dirname($thumbFilePath))) { |
| 112 | mkdir(dirname($thumbFilePath), 0775, true); | 113 | mkdir(dirname($thumbFilePath), 0775, true); |
| 113 | } | 114 | } |
| 114 | 115 | ||
| ... | @@ -124,13 +125,14 @@ class ImageController extends Controller | ... | @@ -124,13 +125,14 @@ class ImageController extends Controller |
| 124 | */ | 125 | */ |
| 125 | public function upload(Request $request) | 126 | public function upload(Request $request) |
| 126 | { | 127 | { |
| 128 | + $this->checkPermission('image-create'); | ||
| 127 | $imageUpload = $request->file('file'); | 129 | $imageUpload = $request->file('file'); |
| 128 | $name = str_replace(' ', '-', $imageUpload->getClientOriginalName()); | 130 | $name = str_replace(' ', '-', $imageUpload->getClientOriginalName()); |
| 129 | $storageName = substr(sha1(time()), 0, 10) . '-' . $name; | 131 | $storageName = substr(sha1(time()), 0, 10) . '-' . $name; |
| 130 | - $imagePath = '/uploads/images/'.Date('Y-m-M').'/'; | 132 | + $imagePath = '/uploads/images/' . Date('Y-m-M') . '/'; |
| 131 | - $storagePath = public_path(). $imagePath; | 133 | + $storagePath = public_path() . $imagePath; |
| 132 | $fullPath = $storagePath . $storageName; | 134 | $fullPath = $storagePath . $storageName; |
| 133 | - while(file_exists($fullPath)) { | 135 | + while (file_exists($fullPath)) { |
| 134 | $storageName = substr(sha1(rand()), 0, 3) . $storageName; | 136 | $storageName = substr(sha1(rand()), 0, 3) . $storageName; |
| 135 | $fullPath = $storagePath . $storageName; | 137 | $fullPath = $storagePath . $storageName; |
| 136 | } | 138 | } |
| ... | @@ -153,6 +155,7 @@ class ImageController extends Controller | ... | @@ -153,6 +155,7 @@ class ImageController extends Controller |
| 153 | */ | 155 | */ |
| 154 | public function update($imageId, Request $request) | 156 | public function update($imageId, Request $request) |
| 155 | { | 157 | { |
| 158 | + $this->checkPermission('image-update'); | ||
| 156 | $this->validate($request, [ | 159 | $this->validate($request, [ |
| 157 | 'name' => 'required|min:2|string' | 160 | 'name' => 'required|min:2|string' |
| 158 | ]); | 161 | ]); |
| ... | @@ -169,6 +172,7 @@ class ImageController extends Controller | ... | @@ -169,6 +172,7 @@ class ImageController extends Controller |
| 169 | */ | 172 | */ |
| 170 | public function destroy($id) | 173 | public function destroy($id) |
| 171 | { | 174 | { |
| 175 | + $this->checkPermission('image-delete'); | ||
| 172 | $image = $this->image->findOrFail($id); | 176 | $image = $this->image->findOrFail($id); |
| 173 | 177 | ||
| 174 | // Delete files | 178 | // Delete files |
| ... | @@ -176,14 +180,14 @@ class ImageController extends Controller | ... | @@ -176,14 +180,14 @@ class ImageController extends Controller |
| 176 | $fileName = basename($image->url); | 180 | $fileName = basename($image->url); |
| 177 | 181 | ||
| 178 | // Delete thumbnails | 182 | // Delete thumbnails |
| 179 | - foreach(glob($folder . '/*') as $file) { | 183 | + foreach (glob($folder . '/*') as $file) { |
| 180 | - if(is_dir($file)) { | 184 | + if (is_dir($file)) { |
| 181 | $thumbName = $file . '/' . $fileName; | 185 | $thumbName = $file . '/' . $fileName; |
| 182 | - if(file_exists($file)) { | 186 | + if (file_exists($file)) { |
| 183 | unlink($thumbName); | 187 | unlink($thumbName); |
| 184 | } | 188 | } |
| 185 | // Remove thumb folder if empty | 189 | // Remove thumb folder if empty |
| 186 | - if(count(glob($file . '/*')) === 0) { | 190 | + if (count(glob($file . '/*')) === 0) { |
| 187 | rmdir($file); | 191 | rmdir($file); |
| 188 | } | 192 | } |
| 189 | } | 193 | } |
| ... | @@ -194,7 +198,7 @@ class ImageController extends Controller | ... | @@ -194,7 +198,7 @@ class ImageController extends Controller |
| 194 | $image->delete(); | 198 | $image->delete(); |
| 195 | 199 | ||
| 196 | // Delete parent folder if empty | 200 | // Delete parent folder if empty |
| 197 | - if(count(glob($folder . '/*')) === 0) { | 201 | + if (count(glob($folder . '/*')) === 0) { |
| 198 | rmdir($folder); | 202 | rmdir($folder); |
| 199 | } | 203 | } |
| 200 | return response()->json('Image Deleted'); | 204 | return response()->json('Image Deleted'); | ... | ... |
| ... | @@ -29,6 +29,7 @@ class PageController extends Controller | ... | @@ -29,6 +29,7 @@ class PageController extends Controller |
| 29 | $this->pageRepo = $pageRepo; | 29 | $this->pageRepo = $pageRepo; |
| 30 | $this->bookRepo = $bookRepo; | 30 | $this->bookRepo = $bookRepo; |
| 31 | $this->chapterRepo = $chapterRepo; | 31 | $this->chapterRepo = $chapterRepo; |
| 32 | + parent::__construct(); | ||
| 32 | } | 33 | } |
| 33 | 34 | ||
| 34 | /** | 35 | /** |
| ... | @@ -41,6 +42,7 @@ class PageController extends Controller | ... | @@ -41,6 +42,7 @@ class PageController extends Controller |
| 41 | */ | 42 | */ |
| 42 | public function create($bookSlug, $chapterSlug = false) | 43 | public function create($bookSlug, $chapterSlug = false) |
| 43 | { | 44 | { |
| 45 | + $this->checkPermission('page-create'); | ||
| 44 | $book = $this->bookRepo->getBySlug($bookSlug); | 46 | $book = $this->bookRepo->getBySlug($bookSlug); |
| 45 | $chapter = $chapterSlug ? $this->chapterRepo->getBySlug($chapterSlug, $book->id) : false; | 47 | $chapter = $chapterSlug ? $this->chapterRepo->getBySlug($chapterSlug, $book->id) : false; |
| 46 | return view('pages/create', ['book' => $book, 'chapter' => $chapter]); | 48 | return view('pages/create', ['book' => $book, 'chapter' => $chapter]); |
| ... | @@ -55,6 +57,7 @@ class PageController extends Controller | ... | @@ -55,6 +57,7 @@ class PageController extends Controller |
| 55 | */ | 57 | */ |
| 56 | public function store(Request $request, $bookSlug) | 58 | public function store(Request $request, $bookSlug) |
| 57 | { | 59 | { |
| 60 | + $this->checkPermission('page-create'); | ||
| 58 | $this->validate($request, [ | 61 | $this->validate($request, [ |
| 59 | 'name' => 'required|string|max:255', | 62 | 'name' => 'required|string|max:255', |
| 60 | 'html' => 'required|string', | 63 | 'html' => 'required|string', |
| ... | @@ -66,7 +69,7 @@ class PageController extends Controller | ... | @@ -66,7 +69,7 @@ class PageController extends Controller |
| 66 | $page->slug = $this->pageRepo->findSuitableSlug($page->name, $book->id); | 69 | $page->slug = $this->pageRepo->findSuitableSlug($page->name, $book->id); |
| 67 | $page->priority = $this->bookRepo->getNewPriority($book); | 70 | $page->priority = $this->bookRepo->getNewPriority($book); |
| 68 | 71 | ||
| 69 | - if($request->has('chapter') && $this->chapterRepo->idExists($request->get('chapter'))) { | 72 | + if ($request->has('chapter') && $this->chapterRepo->idExists($request->get('chapter'))) { |
| 70 | $page->chapter_id = $request->get('chapter'); | 73 | $page->chapter_id = $request->get('chapter'); |
| 71 | } | 74 | } |
| 72 | 75 | ||
| ... | @@ -103,6 +106,7 @@ class PageController extends Controller | ... | @@ -103,6 +106,7 @@ class PageController extends Controller |
| 103 | */ | 106 | */ |
| 104 | public function edit($bookSlug, $pageSlug) | 107 | public function edit($bookSlug, $pageSlug) |
| 105 | { | 108 | { |
| 109 | + $this->checkPermission('page-update'); | ||
| 106 | $book = $this->bookRepo->getBySlug($bookSlug); | 110 | $book = $this->bookRepo->getBySlug($bookSlug); |
| 107 | $page = $this->pageRepo->getBySlug($pageSlug, $book->id); | 111 | $page = $this->pageRepo->getBySlug($pageSlug, $book->id); |
| 108 | return view('pages/edit', ['page' => $page, 'book' => $book, 'current' => $page]); | 112 | return view('pages/edit', ['page' => $page, 'book' => $book, 'current' => $page]); |
| ... | @@ -118,6 +122,7 @@ class PageController extends Controller | ... | @@ -118,6 +122,7 @@ class PageController extends Controller |
| 118 | */ | 122 | */ |
| 119 | public function update(Request $request, $bookSlug, $pageSlug) | 123 | public function update(Request $request, $bookSlug, $pageSlug) |
| 120 | { | 124 | { |
| 125 | + $this->checkPermission('page-update'); | ||
| 121 | $book = $this->bookRepo->getBySlug($bookSlug); | 126 | $book = $this->bookRepo->getBySlug($bookSlug); |
| 122 | $page = $this->pageRepo->getBySlug($pageSlug, $book->id); | 127 | $page = $this->pageRepo->getBySlug($pageSlug, $book->id); |
| 123 | $this->pageRepo->updatePage($page, $book->id, $request->all()); | 128 | $this->pageRepo->updatePage($page, $book->id, $request->all()); |
| ... | @@ -145,7 +150,7 @@ class PageController extends Controller | ... | @@ -145,7 +150,7 @@ class PageController extends Controller |
| 145 | public function searchAll(Request $request) | 150 | public function searchAll(Request $request) |
| 146 | { | 151 | { |
| 147 | $searchTerm = $request->get('term'); | 152 | $searchTerm = $request->get('term'); |
| 148 | - if(empty($searchTerm)) return redirect()->back(); | 153 | + if (empty($searchTerm)) return redirect()->back(); |
| 149 | 154 | ||
| 150 | $pages = $this->pageRepo->getBySearch($searchTerm); | 155 | $pages = $this->pageRepo->getBySearch($searchTerm); |
| 151 | return view('pages/search-results', ['pages' => $pages, 'searchTerm' => $searchTerm]); | 156 | return view('pages/search-results', ['pages' => $pages, 'searchTerm' => $searchTerm]); |
| ... | @@ -158,6 +163,7 @@ class PageController extends Controller | ... | @@ -158,6 +163,7 @@ class PageController extends Controller |
| 158 | */ | 163 | */ |
| 159 | public function sortPages($bookSlug) | 164 | public function sortPages($bookSlug) |
| 160 | { | 165 | { |
| 166 | + $this->checkPermission('book-update'); | ||
| 161 | $book = $this->bookRepo->getBySlug($bookSlug); | 167 | $book = $this->bookRepo->getBySlug($bookSlug); |
| 162 | return view('pages/sort', ['book' => $book, 'current' => $book]); | 168 | return view('pages/sort', ['book' => $book, 'current' => $book]); |
| 163 | } | 169 | } |
| ... | @@ -171,20 +177,21 @@ class PageController extends Controller | ... | @@ -171,20 +177,21 @@ class PageController extends Controller |
| 171 | */ | 177 | */ |
| 172 | public function savePageSort($bookSlug, Request $request) | 178 | public function savePageSort($bookSlug, Request $request) |
| 173 | { | 179 | { |
| 180 | + $this->checkPermission('book-update'); | ||
| 174 | $book = $this->bookRepo->getBySlug($bookSlug); | 181 | $book = $this->bookRepo->getBySlug($bookSlug); |
| 175 | // Return if no map sent | 182 | // Return if no map sent |
| 176 | - if(!$request->has('sort-tree')) { | 183 | + if (!$request->has('sort-tree')) { |
| 177 | return redirect($book->getUrl()); | 184 | return redirect($book->getUrl()); |
| 178 | } | 185 | } |
| 179 | 186 | ||
| 180 | // Sort pages and chapters | 187 | // Sort pages and chapters |
| 181 | $sortMap = json_decode($request->get('sort-tree')); | 188 | $sortMap = json_decode($request->get('sort-tree')); |
| 182 | - foreach($sortMap as $index => $bookChild) { | 189 | + foreach ($sortMap as $index => $bookChild) { |
| 183 | $id = $bookChild->id; | 190 | $id = $bookChild->id; |
| 184 | $isPage = $bookChild->type == 'page'; | 191 | $isPage = $bookChild->type == 'page'; |
| 185 | $model = $isPage ? $this->pageRepo->getById($id) : $this->chapterRepo->getById($id); | 192 | $model = $isPage ? $this->pageRepo->getById($id) : $this->chapterRepo->getById($id); |
| 186 | $model->priority = $index; | 193 | $model->priority = $index; |
| 187 | - if($isPage) { | 194 | + if ($isPage) { |
| 188 | $model->chapter_id = ($bookChild->parentChapter === false) ? 0 : $bookChild->parentChapter; | 195 | $model->chapter_id = ($bookChild->parentChapter === false) ? 0 : $bookChild->parentChapter; |
| 189 | } | 196 | } |
| 190 | $model->save(); | 197 | $model->save(); |
| ... | @@ -201,6 +208,7 @@ class PageController extends Controller | ... | @@ -201,6 +208,7 @@ class PageController extends Controller |
| 201 | */ | 208 | */ |
| 202 | public function showDelete($bookSlug, $pageSlug) | 209 | public function showDelete($bookSlug, $pageSlug) |
| 203 | { | 210 | { |
| 211 | + $this->checkPermission('page-delete'); | ||
| 204 | $book = $this->bookRepo->getBySlug($bookSlug); | 212 | $book = $this->bookRepo->getBySlug($bookSlug); |
| 205 | $page = $this->pageRepo->getBySlug($pageSlug, $book->id); | 213 | $page = $this->pageRepo->getBySlug($pageSlug, $book->id); |
| 206 | return view('pages/delete', ['book' => $book, 'page' => $page, 'current' => $page]); | 214 | return view('pages/delete', ['book' => $book, 'page' => $page, 'current' => $page]); |
| ... | @@ -216,6 +224,7 @@ class PageController extends Controller | ... | @@ -216,6 +224,7 @@ class PageController extends Controller |
| 216 | */ | 224 | */ |
| 217 | public function destroy($bookSlug, $pageSlug) | 225 | public function destroy($bookSlug, $pageSlug) |
| 218 | { | 226 | { |
| 227 | + $this->checkPermission('page-delete'); | ||
| 219 | $book = $this->bookRepo->getBySlug($bookSlug); | 228 | $book = $this->bookRepo->getBySlug($bookSlug); |
| 220 | $page = $this->pageRepo->getBySlug($pageSlug, $book->id); | 229 | $page = $this->pageRepo->getBySlug($pageSlug, $book->id); |
| 221 | Activity::addMessage('page_delete', $book->id, $page->name); | 230 | Activity::addMessage('page_delete', $book->id, $page->name); |
| ... | @@ -255,6 +264,7 @@ class PageController extends Controller | ... | @@ -255,6 +264,7 @@ class PageController extends Controller |
| 255 | 264 | ||
| 256 | public function restoreRevision($bookSlug, $pageSlug, $revisionId) | 265 | public function restoreRevision($bookSlug, $pageSlug, $revisionId) |
| 257 | { | 266 | { |
| 267 | + $this->checkPermission('page-update'); | ||
| 258 | $book = $this->bookRepo->getBySlug($bookSlug); | 268 | $book = $this->bookRepo->getBySlug($bookSlug); |
| 259 | $page = $this->pageRepo->getBySlug($pageSlug, $book->id); | 269 | $page = $this->pageRepo->getBySlug($pageSlug, $book->id); |
| 260 | $revision = $this->pageRepo->getRevisionById($revisionId); | 270 | $revision = $this->pageRepo->getRevisionById($revisionId); | ... | ... |
| ... | @@ -6,7 +6,6 @@ use Illuminate\Http\Request; | ... | @@ -6,7 +6,6 @@ use Illuminate\Http\Request; |
| 6 | 6 | ||
| 7 | use Illuminate\Support\Facades\Hash; | 7 | use Illuminate\Support\Facades\Hash; |
| 8 | use Oxbow\Http\Requests; | 8 | use Oxbow\Http\Requests; |
| 9 | -use Oxbow\Http\Controllers\Controller; | ||
| 10 | use Oxbow\User; | 9 | use Oxbow\User; |
| 11 | 10 | ||
| 12 | class UserController extends Controller | 11 | class UserController extends Controller |
| ... | @@ -21,9 +20,9 @@ class UserController extends Controller | ... | @@ -21,9 +20,9 @@ class UserController extends Controller |
| 21 | public function __construct(User $user) | 20 | public function __construct(User $user) |
| 22 | { | 21 | { |
| 23 | $this->user = $user; | 22 | $this->user = $user; |
| 23 | + parent::__construct(); | ||
| 24 | } | 24 | } |
| 25 | 25 | ||
| 26 | - | ||
| 27 | /** | 26 | /** |
| 28 | * Display a listing of the users. | 27 | * Display a listing of the users. |
| 29 | * | 28 | * |
| ... | @@ -32,7 +31,7 @@ class UserController extends Controller | ... | @@ -32,7 +31,7 @@ class UserController extends Controller |
| 32 | public function index() | 31 | public function index() |
| 33 | { | 32 | { |
| 34 | $users = $this->user->all(); | 33 | $users = $this->user->all(); |
| 35 | - return view('users/index', ['users'=> $users]); | 34 | + return view('users/index', ['users' => $users]); |
| 36 | } | 35 | } |
| 37 | 36 | ||
| 38 | /** | 37 | /** |
| ... | @@ -42,6 +41,7 @@ class UserController extends Controller | ... | @@ -42,6 +41,7 @@ class UserController extends Controller |
| 42 | */ | 41 | */ |
| 43 | public function create() | 42 | public function create() |
| 44 | { | 43 | { |
| 44 | + $this->checkPermission('user-create'); | ||
| 45 | return view('users/create'); | 45 | return view('users/create'); |
| 46 | } | 46 | } |
| 47 | 47 | ||
| ... | @@ -53,16 +53,20 @@ class UserController extends Controller | ... | @@ -53,16 +53,20 @@ class UserController extends Controller |
| 53 | */ | 53 | */ |
| 54 | public function store(Request $request) | 54 | public function store(Request $request) |
| 55 | { | 55 | { |
| 56 | + $this->checkPermission('user-create'); | ||
| 56 | $this->validate($request, [ | 57 | $this->validate($request, [ |
| 57 | 'name' => 'required', | 58 | 'name' => 'required', |
| 58 | 'email' => 'required|email', | 59 | 'email' => 'required|email', |
| 59 | 'password' => 'required|min:5', | 60 | 'password' => 'required|min:5', |
| 60 | - 'password-confirm' => 'required|same:password' | 61 | + 'password-confirm' => 'required|same:password', |
| 62 | + 'role' => 'required|exists:roles,id' | ||
| 61 | ]); | 63 | ]); |
| 62 | 64 | ||
| 63 | $user = $this->user->fill($request->all()); | 65 | $user = $this->user->fill($request->all()); |
| 64 | $user->password = Hash::make($request->get('password')); | 66 | $user->password = Hash::make($request->get('password')); |
| 65 | $user->save(); | 67 | $user->save(); |
| 68 | + | ||
| 69 | + $user->attachRoleId($request->get('role')); | ||
| 66 | return redirect('/users'); | 70 | return redirect('/users'); |
| 67 | } | 71 | } |
| 68 | 72 | ||
| ... | @@ -75,6 +79,9 @@ class UserController extends Controller | ... | @@ -75,6 +79,9 @@ class UserController extends Controller |
| 75 | */ | 79 | */ |
| 76 | public function edit($id) | 80 | public function edit($id) |
| 77 | { | 81 | { |
| 82 | + $this->checkPermissionOr('user-update', function () use ($id) { | ||
| 83 | + return $this->currentUser->id == $id; | ||
| 84 | + }); | ||
| 78 | $user = $this->user->findOrFail($id); | 85 | $user = $this->user->findOrFail($id); |
| 79 | return view('users/edit', ['user' => $user]); | 86 | return view('users/edit', ['user' => $user]); |
| 80 | } | 87 | } |
| ... | @@ -88,17 +95,25 @@ class UserController extends Controller | ... | @@ -88,17 +95,25 @@ class UserController extends Controller |
| 88 | */ | 95 | */ |
| 89 | public function update(Request $request, $id) | 96 | public function update(Request $request, $id) |
| 90 | { | 97 | { |
| 98 | + $this->checkPermissionOr('user-update', function () use ($id) { | ||
| 99 | + return $this->currentUser->id == $id; | ||
| 100 | + }); | ||
| 91 | $this->validate($request, [ | 101 | $this->validate($request, [ |
| 92 | 'name' => 'required', | 102 | 'name' => 'required', |
| 93 | 'email' => 'required|email', | 103 | 'email' => 'required|email', |
| 94 | 'password' => 'min:5', | 104 | 'password' => 'min:5', |
| 95 | - 'password-confirm' => 'same:password' | 105 | + 'password-confirm' => 'same:password', |
| 106 | + 'role' => 'exists:roles,id' | ||
| 96 | ]); | 107 | ]); |
| 97 | 108 | ||
| 98 | $user = $this->user->findOrFail($id); | 109 | $user = $this->user->findOrFail($id); |
| 99 | $user->fill($request->all()); | 110 | $user->fill($request->all()); |
| 100 | 111 | ||
| 101 | - if($request->has('password') && $request->get('password') != '') { | 112 | + if ($this->currentUser->can('user-update') && $request->has('role')) { |
| 113 | + $user->attachRoleId($request->get('role')); | ||
| 114 | + } | ||
| 115 | + | ||
| 116 | + if ($request->has('password') && $request->get('password') != '') { | ||
| 102 | $password = $request->get('password'); | 117 | $password = $request->get('password'); |
| 103 | $user->password = Hash::make($password); | 118 | $user->password = Hash::make($password); |
| 104 | } | 119 | } |
| ... | @@ -113,6 +128,9 @@ class UserController extends Controller | ... | @@ -113,6 +128,9 @@ class UserController extends Controller |
| 113 | */ | 128 | */ |
| 114 | public function delete($id) | 129 | public function delete($id) |
| 115 | { | 130 | { |
| 131 | + $this->checkPermissionOr('user-delete', function () use ($id) { | ||
| 132 | + return $this->currentUser->id == $id; | ||
| 133 | + }); | ||
| 116 | $user = $this->user->findOrFail($id); | 134 | $user = $this->user->findOrFail($id); |
| 117 | return view('users/delete', ['user' => $user]); | 135 | return view('users/delete', ['user' => $user]); |
| 118 | } | 136 | } |
| ... | @@ -125,6 +143,9 @@ class UserController extends Controller | ... | @@ -125,6 +143,9 @@ class UserController extends Controller |
| 125 | */ | 143 | */ |
| 126 | public function destroy($id) | 144 | public function destroy($id) |
| 127 | { | 145 | { |
| 146 | + $this->checkPermissionOr('user-delete', function () use ($id) { | ||
| 147 | + return $this->currentUser->id == $id; | ||
| 148 | + }); | ||
| 128 | $user = $this->user->findOrFail($id); | 149 | $user = $this->user->findOrFail($id); |
| 129 | $user->delete(); | 150 | $user->delete(); |
| 130 | return redirect('/users'); | 151 | return redirect('/users'); | ... | ... |
| ... | @@ -29,5 +29,6 @@ class Kernel extends HttpKernel | ... | @@ -29,5 +29,6 @@ class Kernel extends HttpKernel |
| 29 | 'auth' => \Oxbow\Http\Middleware\Authenticate::class, | 29 | 'auth' => \Oxbow\Http\Middleware\Authenticate::class, |
| 30 | 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, | 30 | 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, |
| 31 | 'guest' => \Oxbow\Http\Middleware\RedirectIfAuthenticated::class, | 31 | 'guest' => \Oxbow\Http\Middleware\RedirectIfAuthenticated::class, |
| 32 | + 'perm' => \Oxbow\Http\Middleware\PermissionMiddleware::class | ||
| 32 | ]; | 33 | ]; |
| 33 | } | 34 | } | ... | ... |
app/Http/Middleware/PermissionMiddleware.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace Oxbow\Http\Middleware; | ||
| 4 | + | ||
| 5 | +use Closure; | ||
| 6 | +use Illuminate\Support\Facades\Session; | ||
| 7 | + | ||
| 8 | +class PermissionMiddleware | ||
| 9 | +{ | ||
| 10 | + /** | ||
| 11 | + * Handle an incoming request. | ||
| 12 | + * | ||
| 13 | + * @param \Illuminate\Http\Request $request | ||
| 14 | + * @param \Closure $next | ||
| 15 | + * @param $permission | ||
| 16 | + * @return mixed | ||
| 17 | + */ | ||
| 18 | + public function handle($request, Closure $next, $permission) | ||
| 19 | + { | ||
| 20 | + | ||
| 21 | + if (!$request->user() || !$request->user()->can($permission)) { | ||
| 22 | + Session::flash('error', trans('errors.permission')); | ||
| 23 | + return redirect()->back(); | ||
| 24 | + } | ||
| 25 | + | ||
| 26 | + return $next($request); | ||
| 27 | + } | ||
| 28 | +} |
| ... | @@ -11,12 +11,14 @@ | ... | @@ -11,12 +11,14 @@ |
| 11 | | | 11 | | |
| 12 | */ | 12 | */ |
| 13 | 13 | ||
| 14 | - | 14 | +Route::get('/test', function () { |
| 15 | + return Auth::user()->can('users-edit'); | ||
| 16 | +}); | ||
| 15 | 17 | ||
| 16 | // Authentication routes... | 18 | // Authentication routes... |
| 17 | -Route::group(['middleware' => 'auth'], function() { | 19 | +Route::group(['middleware' => 'auth'], function () { |
| 18 | 20 | ||
| 19 | - Route::group(['prefix' => 'books'], function() { | 21 | + Route::group(['prefix' => 'books'], function () { |
| 20 | 22 | ||
| 21 | // Books | 23 | // Books |
| 22 | Route::get('/', 'BookController@index'); | 24 | Route::get('/', 'BookController@index'); | ... | ... |
app/Permission.php
0 → 100644
| ... | @@ -2,7 +2,9 @@ | ... | @@ -2,7 +2,9 @@ |
| 2 | 2 | ||
| 3 | namespace Oxbow\Providers; | 3 | namespace Oxbow\Providers; |
| 4 | 4 | ||
| 5 | +use Illuminate\Support\Facades\Auth; | ||
| 5 | use Illuminate\Support\ServiceProvider; | 6 | use Illuminate\Support\ServiceProvider; |
| 7 | +use Oxbow\User; | ||
| 6 | 8 | ||
| 7 | class AppServiceProvider extends ServiceProvider | 9 | class AppServiceProvider extends ServiceProvider |
| 8 | { | 10 | { | ... | ... |
app/Role.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace Oxbow; | ||
| 4 | + | ||
| 5 | +use Illuminate\Database\Eloquent\Model; | ||
| 6 | + | ||
| 7 | +class Role extends Model | ||
| 8 | +{ | ||
| 9 | + /** | ||
| 10 | + * The roles that belong to the role. | ||
| 11 | + */ | ||
| 12 | + public function users() | ||
| 13 | + { | ||
| 14 | + return $this->belongsToMany('Oxbow\User'); | ||
| 15 | + } | ||
| 16 | + | ||
| 17 | + /** | ||
| 18 | + * The permissions that belong to the role. | ||
| 19 | + */ | ||
| 20 | + public function permissions() | ||
| 21 | + { | ||
| 22 | + return $this->belongsToMany('Oxbow\Permission'); | ||
| 23 | + } | ||
| 24 | + | ||
| 25 | + /** | ||
| 26 | + * Add a permission to this role. | ||
| 27 | + * @param Permission $permission | ||
| 28 | + */ | ||
| 29 | + public function attachPermission(Permission $permission) | ||
| 30 | + { | ||
| 31 | + $this->permissions()->attach($permission->id); | ||
| 32 | + } | ||
| 33 | + | ||
| 34 | +} |
| ... | @@ -45,8 +45,58 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon | ... | @@ -45,8 +45,58 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon |
| 45 | } | 45 | } |
| 46 | 46 | ||
| 47 | /** | 47 | /** |
| 48 | + * Permissions and roles | ||
| 49 | + */ | ||
| 50 | + | ||
| 51 | + /** | ||
| 52 | + * The roles that belong to the user. | ||
| 53 | + */ | ||
| 54 | + public function roles() | ||
| 55 | + { | ||
| 56 | + return $this->belongsToMany('Oxbow\Role'); | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + public function getRoleAttribute() | ||
| 60 | + { | ||
| 61 | + return $this->roles()->first(); | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + /** | ||
| 65 | + * Check if the user has a particular permission. | ||
| 66 | + * @param $permissionName | ||
| 67 | + * @return bool | ||
| 68 | + */ | ||
| 69 | + public function can($permissionName) | ||
| 70 | + { | ||
| 71 | + $permissions = $this->role->permissions()->get(); | ||
| 72 | + $permissionSearch = $permissions->search(function ($item, $key) use ($permissionName) { | ||
| 73 | + return $item->name == $permissionName; | ||
| 74 | + }); | ||
| 75 | + return $permissionSearch !== false; | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + /** | ||
| 79 | + * Attach a role to this user. | ||
| 80 | + * @param Role $role | ||
| 81 | + */ | ||
| 82 | + public function attachRole(Role $role) | ||
| 83 | + { | ||
| 84 | + $this->attachRoleId($role->id); | ||
| 85 | + } | ||
| 86 | + | ||
| 87 | + /** | ||
| 88 | + * Attach a role id to this user. | ||
| 89 | + * @param $id | ||
| 90 | + */ | ||
| 91 | + public function attachRoleId($id) | ||
| 92 | + { | ||
| 93 | + $this->roles()->sync([$id]); | ||
| 94 | + } | ||
| 95 | + | ||
| 96 | + /** | ||
| 48 | * Returns the user's avatar, | 97 | * Returns the user's avatar, |
| 49 | * Uses Gravatar as the avatar service. | 98 | * Uses Gravatar as the avatar service. |
| 99 | + * | ||
| 50 | * @param int $size | 100 | * @param int $size |
| 51 | * @return string | 101 | * @return string |
| 52 | */ | 102 | */ | ... | ... |
| ... | @@ -20,6 +20,12 @@ class CreateUsersTable extends Migration | ... | @@ -20,6 +20,12 @@ class CreateUsersTable extends Migration |
| 20 | $table->rememberToken(); | 20 | $table->rememberToken(); |
| 21 | $table->timestamps(); | 21 | $table->timestamps(); |
| 22 | }); | 22 | }); |
| 23 | + | ||
| 24 | + \Oxbow\User::create([ | ||
| 25 | + 'name' => 'Admin', | ||
| 26 | + 'email' => 'admin@admin.com', | ||
| 27 | + 'password' => \Illuminate\Support\Facades\Hash::make('password') | ||
| 28 | + ]); | ||
| 23 | } | 29 | } |
| 24 | 30 | ||
| 25 | /** | 31 | /** | ... | ... |
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +use Illuminate\Database\Schema\Blueprint; | ||
| 4 | +use Illuminate\Database\Migrations\Migration; | ||
| 5 | + | ||
| 6 | +/** | ||
| 7 | + * Much of this code has been taken from entrust, | ||
| 8 | + * a role & permission management solution for Laravel. | ||
| 9 | + * | ||
| 10 | + * Full attribution of the database Schema shown below goes to the entrust project. | ||
| 11 | + * | ||
| 12 | + * @license MIT | ||
| 13 | + * @package Zizaco\Entrust | ||
| 14 | + * @url https://github.com/Zizaco/entrust | ||
| 15 | + */ | ||
| 16 | +class AddRolesAndPermissions extends Migration | ||
| 17 | +{ | ||
| 18 | + /** | ||
| 19 | + * Run the migrations. | ||
| 20 | + * | ||
| 21 | + * @return void | ||
| 22 | + */ | ||
| 23 | + public function up() | ||
| 24 | + { | ||
| 25 | + // Create table for storing roles | ||
| 26 | + Schema::create('roles', function (Blueprint $table) { | ||
| 27 | + $table->increments('id'); | ||
| 28 | + $table->string('name')->unique(); | ||
| 29 | + $table->string('display_name')->nullable(); | ||
| 30 | + $table->string('description')->nullable(); | ||
| 31 | + $table->timestamps(); | ||
| 32 | + }); | ||
| 33 | + | ||
| 34 | + // Create table for associating roles to users (Many-to-Many) | ||
| 35 | + Schema::create('role_user', function (Blueprint $table) { | ||
| 36 | + $table->integer('user_id')->unsigned(); | ||
| 37 | + $table->integer('role_id')->unsigned(); | ||
| 38 | + | ||
| 39 | + $table->foreign('user_id')->references('id')->on('users') | ||
| 40 | + ->onUpdate('cascade')->onDelete('cascade'); | ||
| 41 | + $table->foreign('role_id')->references('id')->on('roles') | ||
| 42 | + ->onUpdate('cascade')->onDelete('cascade'); | ||
| 43 | + | ||
| 44 | + $table->primary(['user_id', 'role_id']); | ||
| 45 | + }); | ||
| 46 | + | ||
| 47 | + // Create table for storing permissions | ||
| 48 | + Schema::create('permissions', function (Blueprint $table) { | ||
| 49 | + $table->increments('id'); | ||
| 50 | + $table->string('name')->unique(); | ||
| 51 | + $table->string('display_name')->nullable(); | ||
| 52 | + $table->string('description')->nullable(); | ||
| 53 | + $table->timestamps(); | ||
| 54 | + }); | ||
| 55 | + | ||
| 56 | + // Create table for associating permissions to roles (Many-to-Many) | ||
| 57 | + Schema::create('permission_role', function (Blueprint $table) { | ||
| 58 | + $table->integer('permission_id')->unsigned(); | ||
| 59 | + $table->integer('role_id')->unsigned(); | ||
| 60 | + | ||
| 61 | + $table->foreign('permission_id')->references('id')->on('permissions') | ||
| 62 | + ->onUpdate('cascade')->onDelete('cascade'); | ||
| 63 | + $table->foreign('role_id')->references('id')->on('roles') | ||
| 64 | + ->onUpdate('cascade')->onDelete('cascade'); | ||
| 65 | + | ||
| 66 | + $table->primary(['permission_id', 'role_id']); | ||
| 67 | + }); | ||
| 68 | + | ||
| 69 | + | ||
| 70 | + // Create default roles | ||
| 71 | + $admin = new \Oxbow\Role(); | ||
| 72 | + $admin->name = 'admin'; | ||
| 73 | + $admin->display_name = 'Admin'; | ||
| 74 | + $admin->description = 'Administrator of the whole application'; | ||
| 75 | + $admin->save(); | ||
| 76 | + | ||
| 77 | + $editor = new \Oxbow\Role(); | ||
| 78 | + $editor->name = 'editor'; | ||
| 79 | + $editor->display_name = 'Editor'; | ||
| 80 | + $editor->description = 'User can edit Books, Chapters & Pages'; | ||
| 81 | + $editor->save(); | ||
| 82 | + | ||
| 83 | + $viewer = new \Oxbow\Role(); | ||
| 84 | + $viewer->name = 'viewer'; | ||
| 85 | + $viewer->display_name = 'Viewer'; | ||
| 86 | + $viewer->description = 'User can view books & their content behind authentication'; | ||
| 87 | + $viewer->save(); | ||
| 88 | + | ||
| 89 | + // Create default CRUD permissions and allocate to admins and editors | ||
| 90 | + $entities = ['Book', 'Page', 'Chapter', 'Image']; | ||
| 91 | + $ops = ['Create', 'Update', 'Delete']; | ||
| 92 | + foreach ($entities as $entity) { | ||
| 93 | + foreach ($ops as $op) { | ||
| 94 | + $newPermission = new \Oxbow\Permission(); | ||
| 95 | + $newPermission->name = strtolower($entity) . '-' . strtolower($op); | ||
| 96 | + $newPermission->display_name = $op . ' ' . $entity . 's'; | ||
| 97 | + $newPermission->save(); | ||
| 98 | + $admin->attachPermission($newPermission); | ||
| 99 | + $editor->attachPermission($newPermission); | ||
| 100 | + } | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | + // Create admin permissions | ||
| 104 | + $entities = ['Settings', 'User']; | ||
| 105 | + $ops = ['Create', 'Update', 'Delete']; | ||
| 106 | + foreach ($entities as $entity) { | ||
| 107 | + foreach ($ops as $op) { | ||
| 108 | + $newPermission = new \Oxbow\Permission(); | ||
| 109 | + $newPermission->name = strtolower($entity) . '-' . strtolower($op); | ||
| 110 | + $newPermission->display_name = $op . ' ' . $entity; | ||
| 111 | + $newPermission->save(); | ||
| 112 | + $admin->attachPermission($newPermission); | ||
| 113 | + } | ||
| 114 | + } | ||
| 115 | + | ||
| 116 | + // Set all current users as admins | ||
| 117 | + // (At this point only the initially create user should be an admin) | ||
| 118 | + $users = \Oxbow\User::all(); | ||
| 119 | + foreach ($users as $user) { | ||
| 120 | + $user->attachRole($admin); | ||
| 121 | + } | ||
| 122 | + | ||
| 123 | + } | ||
| 124 | + | ||
| 125 | + /** | ||
| 126 | + * Reverse the migrations. | ||
| 127 | + * | ||
| 128 | + * @return void | ||
| 129 | + */ | ||
| 130 | + public function down() | ||
| 131 | + { | ||
| 132 | + Schema::drop('permission_role'); | ||
| 133 | + Schema::drop('permissions'); | ||
| 134 | + Schema::drop('role_user'); | ||
| 135 | + Schema::drop('roles'); | ||
| 136 | + } | ||
| 137 | +} |
| ... | @@ -15,11 +15,6 @@ class DatabaseSeeder extends Seeder | ... | @@ -15,11 +15,6 @@ class DatabaseSeeder extends Seeder |
| 15 | Model::unguard(); | 15 | Model::unguard(); |
| 16 | 16 | ||
| 17 | // $this->call(UserTableSeeder::class); | 17 | // $this->call(UserTableSeeder::class); |
| 18 | - \Oxbow\User::create([ | ||
| 19 | - 'name' => 'Admin', | ||
| 20 | - 'email' => 'admin@admin.com', | ||
| 21 | - 'password' => \Illuminate\Support\Facades\Hash::make('password') | ||
| 22 | - ]); | ||
| 23 | 18 | ||
| 24 | Model::reguard(); | 19 | Model::reguard(); |
| 25 | } | 20 | } | ... | ... |
| ... | @@ -60,6 +60,11 @@ | ... | @@ -60,6 +60,11 @@ |
| 60 | &.large { | 60 | &.large { |
| 61 | padding: $-xl; | 61 | padding: $-xl; |
| 62 | } | 62 | } |
| 63 | + >h1, >h2, >h3, >h4 { | ||
| 64 | + &:first-child { | ||
| 65 | + margin-top: 0.1em; | ||
| 66 | + } | ||
| 67 | + } | ||
| 63 | } | 68 | } |
| 64 | .padded-vertical, .padded-top { | 69 | .padded-vertical, .padded-top { |
| 65 | padding-top: $-m; | 70 | padding-top: $-m; |
| ... | @@ -67,6 +72,7 @@ | ... | @@ -67,6 +72,7 @@ |
| 67 | padding-top: $-xl; | 72 | padding-top: $-xl; |
| 68 | } | 73 | } |
| 69 | } | 74 | } |
| 75 | + | ||
| 70 | .padded-vertical, .padded-bottom { | 76 | .padded-vertical, .padded-bottom { |
| 71 | padding-bottom: $-m; | 77 | padding-bottom: $-m; |
| 72 | &.large { | 78 | &.large { | ... | ... |
| ... | @@ -197,7 +197,7 @@ p.secondary, p .secondary, span.secondary, .text-secondary { | ... | @@ -197,7 +197,7 @@ p.secondary, p .secondary, span.secondary, .text-secondary { |
| 197 | */ | 197 | */ |
| 198 | ul { | 198 | ul { |
| 199 | list-style: disc; | 199 | list-style: disc; |
| 200 | - margin-left: $-m; | 200 | + margin-left: $-m*1.5; |
| 201 | } | 201 | } |
| 202 | 202 | ||
| 203 | /* | 203 | /* | ... | ... |
resources/lang/en/errors.php
0 → 100644
resources/views/form/model-select.blade.php
0 → 100644
| 1 | + | ||
| 2 | +<select id="{{ $name }}" name="{{ $name }}"> | ||
| 3 | + @foreach($options as $option) | ||
| 4 | + <option value="{{$option->id}}" | ||
| 5 | + @if($errors->has($name)) class="neg" @endif | ||
| 6 | + @if(isset($model) || old($name)) @if(old($name) && old($name) === $option->id) selected @elseif(isset($model) && $model->id === $option->id) selected @endif @endif | ||
| 7 | + > | ||
| 8 | + {{ $option->$displayKey }} | ||
| 9 | + </option> | ||
| 10 | + @endforeach | ||
| 11 | +</select> | ||
| 12 | + | ||
| 13 | +@if($errors->has($name)) | ||
| 14 | + <div class="text-neg text-small">{{ $errors->first($name) }}</div> | ||
| 15 | +@endif | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| ... | @@ -14,6 +14,7 @@ | ... | @@ -14,6 +14,7 @@ |
| 14 | 14 | ||
| 15 | <div class="row"> | 15 | <div class="row"> |
| 16 | <div class="page-content"> | 16 | <div class="page-content"> |
| 17 | + | ||
| 17 | <div class="row"> | 18 | <div class="row"> |
| 18 | <div class="col-md-6"> | 19 | <div class="col-md-6"> |
| 19 | <h1>Edit User</h1> | 20 | <h1>Edit User</h1> |
| ... | @@ -33,6 +34,24 @@ | ... | @@ -33,6 +34,24 @@ |
| 33 | </div> | 34 | </div> |
| 34 | </div> | 35 | </div> |
| 35 | </div> | 36 | </div> |
| 37 | + | ||
| 38 | + <hr class="margin-top large"> | ||
| 39 | + | ||
| 40 | + <div class="row"> | ||
| 41 | + <div class="col-md-12"> | ||
| 42 | + <h3>Permissions</h3> | ||
| 43 | + <p>User Role: <strong>{{$user->role->display_name}}</strong>.</p> | ||
| 44 | + <ul class="text-muted"> | ||
| 45 | + @foreach($user->role->permissions as $permission) | ||
| 46 | + <li> | ||
| 47 | + {{ $permission->display_name }} | ||
| 48 | + </li> | ||
| 49 | + @endforeach | ||
| 50 | + </ul> | ||
| 51 | + | ||
| 52 | + </div> | ||
| 53 | + </div> | ||
| 54 | + | ||
| 36 | </div> | 55 | </div> |
| 37 | </div> | 56 | </div> |
| 38 | 57 | ... | ... |
| 1 | - | ||
| 2 | <div class="form-group"> | 1 | <div class="form-group"> |
| 3 | <label for="name">Name</label> | 2 | <label for="name">Name</label> |
| 4 | @include('form/text', ['name' => 'name']) | 3 | @include('form/text', ['name' => 'name']) |
| ... | @@ -10,11 +9,18 @@ | ... | @@ -10,11 +9,18 @@ |
| 10 | </div> | 9 | </div> |
| 11 | 10 | ||
| 12 | @if(isset($model)) | 11 | @if(isset($model)) |
| 13 | -<div class="form-group"> | 12 | + <div class="form-group"> |
| 14 | <span class="text-muted"> | 13 | <span class="text-muted"> |
| 15 | Only fill the below if you would like <br>to change your password: | 14 | Only fill the below if you would like <br>to change your password: |
| 16 | </span> | 15 | </span> |
| 17 | -</div> | 16 | + </div> |
| 17 | +@endif | ||
| 18 | + | ||
| 19 | +@if($currentUser->can('user-update')) | ||
| 20 | + <div class="form-group"> | ||
| 21 | + <label for="role">User Role</label> | ||
| 22 | + @include('form/model-select', ['name' => 'role', 'options' => \Oxbow\Role::all(), 'displayKey' => 'display_name']) | ||
| 23 | + </div> | ||
| 18 | @endif | 24 | @endif |
| 19 | 25 | ||
| 20 | <div class="form-group"> | 26 | <div class="form-group"> | ... | ... |
| ... | @@ -8,7 +8,9 @@ | ... | @@ -8,7 +8,9 @@ |
| 8 | <div class="col-md-6"></div> | 8 | <div class="col-md-6"></div> |
| 9 | <div class="col-md-6 faded"> | 9 | <div class="col-md-6 faded"> |
| 10 | <div class="action-buttons"> | 10 | <div class="action-buttons"> |
| 11 | + @if($currentUser->can('user-create')) | ||
| 11 | <a href="/users/create" class="text-pos"><i class="zmdi zmdi-account-add"></i>New User</a> | 12 | <a href="/users/create" class="text-pos"><i class="zmdi zmdi-account-add"></i>New User</a> |
| 13 | + @endif | ||
| 12 | </div> | 14 | </div> |
| 13 | </div> | 15 | </div> |
| 14 | </div> | 16 | </div> |
| ... | @@ -21,12 +23,22 @@ | ... | @@ -21,12 +23,22 @@ |
| 21 | <th></th> | 23 | <th></th> |
| 22 | <th>Name</th> | 24 | <th>Name</th> |
| 23 | <th>Email</th> | 25 | <th>Email</th> |
| 26 | + <th>User Type</th> | ||
| 24 | </tr> | 27 | </tr> |
| 25 | @foreach($users as $user) | 28 | @foreach($users as $user) |
| 26 | <tr> | 29 | <tr> |
| 27 | <td style="line-height: 0;"><img class="avatar" src="{{$user->getAvatar(40)}}" alt="{{$user->name}}"></td> | 30 | <td style="line-height: 0;"><img class="avatar" src="{{$user->getAvatar(40)}}" alt="{{$user->name}}"></td> |
| 28 | - <td><a href="/users/{{$user->id}}">{{$user->name}}</a></td> | 31 | + <td> |
| 32 | + @if($currentUser->can('user-update') || $currentUser->id == $user->id) | ||
| 33 | + <a href="/users/{{$user->id}}"> | ||
| 34 | + @endif | ||
| 35 | + {{$user->name}} | ||
| 36 | + @if($currentUser->can('user-update') || $currentUser->id == $user->id) | ||
| 37 | + </a> | ||
| 38 | + @endif | ||
| 39 | + </td> | ||
| 29 | <td>{{$user->email}}</td> | 40 | <td>{{$user->email}}</td> |
| 41 | + <td>{{ $user->role->display_name }}</td> | ||
| 30 | </tr> | 42 | </tr> |
| 31 | @endforeach | 43 | @endforeach |
| 32 | </table> | 44 | </table> | ... | ... |
-
Please register or sign in to post a comment