Centralize user role verification in laravel - laravel

I'm working on an e-commerce website and i need to display certain data based on the user role. Basically the page can be viewed by three types of people: normal people who enters the page and by a client user or an admin who have their accounts but they see different buttons/data according to their role.
I'm working with jetstream authenticaton system and what i do is simply verify the user role on my views like this:
#if (Auth::user()->role->name == 'admin')
//display button only the admin can see
#else
//display button only a client user can see
#endif
My question is, can i implement something like a gate to centralize the condition?, i mean, in case i need to change it only doing it in one file and avoid to do it in all the lines where i implented it.
Any help is welcome. Thanks!

Yes. Just define gates or use a model policy. Using gates, you can do something like (using a Post model as an example):
Gate::define('edit-post', function (User $user, Post $post) {
return $user->role->name == 'admin' || $user->id == $post->user_id;
});
Gate::define('delete-post', function (User $user, Post $post) {
return $user->role->name == 'admin';
});
And use it in your .blade.php files using the #can blade directives.
#can('edit-post')
// show an edit button
#endcan
#can('delete-post')
// show a delete button
#endcan
Here we are basically creating two controls for editing and deleting a post. To edit a post (or rather see the edit button), you either have to be an admin or the user must have created the post. To delete it, you have to be an admin.
References: Laravel Documentation on Authorization

Related

How to update a field in a database via email?

When a user subscribes to news from the site, he receives a welcome letter in his mail with a question, does he really want to subscribe to news?
Also in the letter there is a button that confirms his consent to the newsletter.
How can I make it so that when I click this button from an email, the values ​​​​in my database are updated?
This is my mail form welcome.blade.php
Welcome, User
<form action="{{route('welcome', $data->hash)}} method="POST">#csrf
<button type="submit">Click me</button>
</form>
Controller
public function welcome($hash) {
\DB::table('config')->where('hash', $hash)->update(['agree' => 1]);
Route
Route::post('welcome', 'WelcomeController#welcome')->name('welcome')
Embedding forms in emails is not allowed/recommended. It is a security risk. Email clients will simply warn the recipients of potential danger and will disable the form.
You need to add a link to your application in the email content.
click me
When a user will click on the URL below route will hit.
Route::get('/add-consent/{token}', 'WelcomeController#welcome')->name('welcome');
In the action identify user based on token and perform the action.
public function welcome($token) {
// Identify user based on token and perform the action...
\DB::table('config')->where('hash', $token)->update(['agree' => 1]);
}

View Composer for sidebar in Laravel

using a view composer for the first time in Laravel. i have a sidebar that is included in every step of a submission form process a user goes through. i want the sidebar to have link that apply to the proper submission (i.e. if this is submission number 5, the links in the sidebar should all go to the edit function for submission 5.
i have the following code in my web.php:
View::composer('layouts.planbuilder', function($view){
$plansubmissions = PlanSubmission::find(3);
$view->with('plansubmissions', $plansubmissions) ;
}) ;
i am able to access the $plansubmissions variable, but of course this only applies to submission 3, which i hard coded in. is it possible to get the logic from another controller? i can't just get the user id with Auth because a user can have many submissions
View Composers also have access to the variables that were passed to the view itself, so if you are passing the submission to your view from the controller like so
return view('submissions.show', compact('submission');
Then in your composer you can assign it to $plansubmissions
$plansubmissions = $view->getData()['submission'];

Roles and permissions issues in laravel project

I am working on a laravel project. I have a side menu that is persistent across all pages. However the menu items to be shown is dependent on the role assigned to the user. I achieved that by doing this:
<?php
/**$links = Session::get('links'); **/
use Illuminate\Support\Facades\DB;
$id_hr_employee= Auth::user()->id_hr_employee;
$links = DB::select("select a.link as links from sys_menu_links as a a.id_hr_employee = $id_hr_employee)
");
?>
#if(isset($links))
#foreach($links as $link)
<li><hr class="light-grey-hr mb-10"/></li>
#include("$link->links")
#endforeach
#endif
This works quite alright. However, if someone enters a route to a menu (that he is not assigned to) on the address bar, he sees that page.
Please how do I prevent this?
i would highly recommend you using laratrust: https://laratrust.readthedocs.io/en/4.0/.
And to secure your sides: 1.option work with middelware to Block your admin views 2. Option Check for permission in the Controller files.
As a guidance you could look up this tutorial: http://itsolutionstuff.com/post/laravel-52-user-acl-roles-and-permissions-with-middleware-using-entrust-from-scratch-tutorialexample.html
greetings

Directly access a put/update method on Laravel 5.1 without going into the edit view (MethodNotAllowedHttpException in RouteCollection.php error)

I wanted to disable employees from a button on my index.blade.php page. Currently, the options of disabling employees (setting the status column in the database to false) is either to have an edit.blade.php view and update the value there, which is pretty standard for any laravel app or to have a new view for example, changestatus.blade.php, with the proper routes offcourse and update the value there. I am using the second implementation and it's working perfectly.
What i wanted to implement is to have a button on the index page which will change the status of the employee without going to a edit.blade.php or changestatus.blade.php page.
What i have tried
I have created new routes and created a button to link to the changestatus function
Routes.php
Route::put('employees/{employee}/changestatus', 'EmployeesController#changestatus')->name('employees.changestatus');
Route::resource('employees', 'EmployeesController');
EmployeeController
public function changestatus($EmployeeID)
{
$employee = Employee::find($EmployeeID);
$employee->status = true;
$employee->Save();
}
On my view i created a button with the following link
{{ URL::route('employees.changestatus', $employee->EmployeeID) }}
When i click that link, i get the MethodNotAllowedHttpException in RouteCollection.php error.
I even tried to change the Route::put to Route::Patch, but it's the same thing.
Is it even possible to achieve what I'm trying to do? If so, how?
When you click on a hyperlink, the web browser submits a GET request. Your route has been defined as being a PUT so that's why you're getting an exception.
You could either change the route to a GET by defining it like this:
Route::get('employees/{employee}/changestatus', 'EmployeesController#changestatus')->name('employees.changestatus');
Which isn't very ReSTful since a GET request should really only be used for returning a resource rather than modifying it.
Or, you could modify the button so that it submits a form like this:
<form method="post" action="{{ route('employees.changestatus', $employee->EmployeeID) }}">
{{ method_field('PUT') }}
<button type="submit">Button Text</button>
</form>
Note that you can't simply set the form method to PUT since this method isn't generally supported by web browsers. Laravel supports method spoofing which you can read all about here:
http://laravel.com/docs/5.1/routing#form-method-spoofing

Laravel 5 - getting data to a view

I think this is slightly different to the usual controller passing data to the view. I have a Project which has one DocumentOne. Within my app, the user creates a Project. This then redirects them to the show page for this project.
So with the project created, and the user on the show page for that project, I display the project ID. I then provide a select menu where the user can select a Document to display. So say I am in Project with the ID of 1, I then decide to show DocumentOne for this project. This displays a form with inputs for DocumentOne.
When the user fills in the form and submits, the data is saved to the database. The Project ID is the foreign key for DocumentOne. The following route is set up for DocumentOne
Route::resource('projects.documentOne', 'DocumentOneController');
Now I have data for DocumentOne which is linked to the Project with an ID of 1. However, if I now go back to the projects show page and then select Document One from the dropdown again, all I see is an empty form. This is obviously because the controller for this is
public function show(Project $project)
{
return view('projects.show', compact('project'));
}
So I am never passing it data for DocumentOne because theoretically it is not created when the Project is first shown. What I want to do is when the Document is selected in the Projects show page, is to have the form populated with whatever is in the database for that Document. If nothing is in the database, then the form will be empty. I have a DocumentOne Controller, but I dont know if I can link this to the Projects show page. I was thinking about doing something like this in the DocumentOne controller
public function show(DocumentOne $documentOne)
{
return view('projects.show', compact('documentOne'));
}
But not sure this will work. Hope I have not been too confusing and you understand what I am attempting, hoping someone can offer advice on how best to handle this situation.
Thanks
In my previous project, I also deal with such requirement, I thought so. Here my solution to solve such requirement.
Actual code calling from ajax.
Routes
get('setFlashData',function(Request $request){
$final_response = array();
$data_information = $request->except('_token');
$request->session()->flash('cmg_quick_create_data', $data_information);
if($request->session()->has('cmg_quick_create_data')){
$final_response['result']['success'] = true;
}
return response()->json($final_response);
});
But according to you requirement:
$data_information = $request->except('_token');
$request->session()->flash('cmg_quick_create_data', $data_information);
My basic functionality was, to share form data from Quick Create Section which is pop-up form to Full create form section, and whenever user click to "Go To Full Form" button from pop up, ajax call mentioned function which will set the flash data and than on destination side I only check weather its contain the flash data or not. and deal according to data.
#if (Session::has('cmg_quick_create_data')) {
{!! Form::model(Session::get('cmg_quick_create_data'),["class"=>"form-horizontal","data-parsley-validate"=>"data-parsley-validate",'role'=>'form','files'=>true]) !!}
#else
{!! Form::open(["class"=>"form-horizontal","data-parsley-validate"=>"data-parsley-validate",'role'=>'form','files'=>true]) !!}
#endif
I can understand this solution might be different from you requirement but hope full to figure out your solution. Look forward to hearing from you if still unclear from my side.

Resources