Problems with the create policy in Laravel 5 - laravel-5

I'm implementing roles and permission for a project, and using policies, but I have a problem when I want to authorize or not the creation of new records in the patients table, very simple stuff.
I have this in my PatientPolicy
// Only the users with root or admin roles can create patients;
public function create(User $user){
return ($user->hasRole('root') || $user->hasRole('admin'));
}
// only the patient creator can edit the patient and see the edit button
public function update(User $user, Patient $patient){
return $user->id == $patient->user_id;
}
AuthServiceProvider
protected $policies = [
'App\Model' => 'App\Policies\ModelPolicy',
'App\Patient' => 'App\Policies\PatientPolicy'
];
PatientController
public function edit(Patient $patient){
if(Gate::denies('update', $patient)){
abort(403, 'No esta autorizado de estar aqui');
}
return view('patients.edit', compact('patient'));
}
public function create(){
if(Gate::denies('create')){
abort(403, 'Usted no esta autorizado para crear pacientes');
}
return view('patients.create');
}
and in my views
#can('create')
<li class="header">PROCESOS</li>
<li><i class="fa fa-book"></i> <span>Apertura de Historia Clínica</span></li>
#endcan
The problem is that the create policy is always returning false even for those users that are suppossed to be allowed to perform the action, however the edit policy works perfectly. Am I missing something?

The problem is Gate::denies and #can methods don't know which model and policy class they should look for when there is no argument to correspond, so use this code instead:
public function create(){
if(Gate::denies('create', Patient::class)) {
abort(403, 'Usted no esta autorizado para crear pacientes');
}
return view('patients.create');
}
and in your views:
#can('create', App\Patient::class)
<li class="header">PROCESOS</li>
<li><i class="fa fa-book"></i> <span>Apertura de Historia Clínica</span></li>
#endcan
You can check my full answer here:
https://stackoverflow.com/a/37261276/3477084

Related

how to change url for edit in laravel

I have an edit page, I have used resource controller for it. Everytime the page redirects from edit (../members/16/edit) it continues with the edit page url (../members/16/members). [where it should only take ../members]
How can I remove/change url for edit.
Route
Route::resource('members', MemberController::class);
edit function
public function edit(Member $members,$id)
{
$members = Member::find($id);
return view('edit', compact('members'));
}
public function update(Request $request,$id)
{
$members = Member::find($id);
$members->name = $request->name;
$members->save();
return view('committee')->with('success', 'Member Updated successfully');
}
<a class="btn btn-sm btn-icon btn-success" title="Edit NewsRoom Details"
href="'.route("members.edit",[$members->id]).'"><i class="fas fa-edit"></i></a>
You should identify what you are passing example:
...
Your update method is not redirecting anywhere, it is simply loading a different view, the correct way to do it is:
public function update(Request $request,$id)
{
$members = Member::find($id);
$members->name = $request->name;
$members->save();
//return view('committee')->with('success', 'Member Updated successfully');
return redirect()->route('members.committee')->with('success', 'Member Updated successfully');
}

Laravel Auth - If user is not logged in hide Controller regenerated Edit and Delete buttons [Yajra DataTables]

I added Laravel Auth to my Yajra Laravel Datatables but for the life of me I cannot seem to figure out the code for the controller so that if a user is not logged in then hide Controller regenerated html buttons
Here is the AjaxdataController.php:
class AjaxdataController extends Controller
{
//base page
function index()
{
return view('student.ajaxdata');
}
//view data and make dynamic EDIT and DELETE Buttons per record
function getdata(Request $request)
{
$students = Student::select('id',
'first_name',
'last_name'
);
return Datatables::of($students)
->addColumn('action', function($student){
//EDIT AND DELETE BUTTONS
return '<i class="glyphicon glyphicon-edit"></i> Edit<i class="glyphicon glyphicon-remove"></i> Delete';
})
->make(true);
}
}
Here's what I am hoping to do with the AjaxdataController.php:
class AjaxdataController extends Controller
{
//base page
function index()
{
return view('student.ajaxdata');
}
//view data and make dynamic EDIT and DELETE Buttons per record
function getdata(Request $request)
{
$students = Student::select('id',
'first_name',
'last_name'
);
return Datatables::of($students)
//if logged in then addColumn()
if (Auth::user()){
->addColumn('action', function($student){
//EDIT AND DELETE BUTTONS
return '<i class="glyphicon glyphicon-edit"></i> Edit<i class="glyphicon glyphicon-remove"></i> Delete';
})
}
->make(true);
}
}
I figured it out:
1) In the "use" section at the top of app\Http\Controllers\AjaxdataController.php, import the Auth Facades:
use Illuminate\Support\Facades\Auth;
2) Edit the addColumn() api like so:
->addColumn('action', function($contact){
if (Auth::user()) {
//IF LOGGED IN SHOW EDIT & DELETE BUTTONS
return '<div class="btn-group"><i class="glyphicon glyphicon-edit"></i> Edit <i class="glyphicon glyphicon-remove"></i> Delete
</div>';
}else{
//IF LOGGED OUT SHOW THIS
return '<p class="text-info font-weight-bold">Login to Edit or Delete</p>';
}
})

Assign specific roles from where the user clicks

I would like to assign roles depending on which button the user clicks:
For example:
- If you click on I want to be an Advisor, redirect to the Laravel registration form and assign the role of advisor.
- If the user clicks on I want to be a Buyer, they redirect to the Laravel registration form and assign the buyer role.
But I do not know how to do it.
I have this code in my 'RegisterController':
protected function create(array $data)
{
$user = User::create([
'name' => $data['name'],
'email' => $data['email'],
//'password' => Hash::make($data['password']), //mutador en User model
'password' => $data['password'],
'surname1' => $data['surname1'],
'surname2' => $data['surname2'],
'comunidad_id' => $data['cbx_comunidad'],
'provincia_id' => $data['cbx_provincia'],
'municipio_id' => $data['cbx_municipio'],
]);
//dd(Request::url());
// $user->assignRole('Asesor');
//quiero asignar varios roles depende de el botón que clicken
return $user;
}
For now, what I have done is to add such a parameter, in the view that calls the view 'register':
href="{{ route('register','Asesor') }}"
and in the view 'register' send it by post in a hidden:
<div class="form-group">
<?php
$pos = strpos(Request::fullUrl(), '?');
$cadena = substr (Request::fullUrl() , $pos+1, strlen(Request::fullUrl()) );
?>
<input type="hidden" name="role" id="role" value="{{ $cadena }}">
</div>
Then in the controller I do this:
if ($data['role'] == 'Asesor=')
{
$user->assignRole('Asesor');
}
return $user;
But I don't know if it's the right way to act.
I think, you could work with events like this:
In your EventServiceProvider class, create an item inside your property $listen:
'App\Events\User\Created' => ['App\Listeners\User\AssignRoles'],
After that, you going to run the command:
php artisan event:generate
Now, you need to turn on this event in your User class declaring protected property $dispatchesEvents, like this:
protected $dispatchesEvents = ['created' => 'App\Events\User\Created'];
After all call create method in your User class, the created event is going to be called and run AssignRoles logic.
In your App\Events\User\Created class you need to inject User into __construct method, like this:
public $user;
public function __construct(User $user)
{
$this->user = $user;
}
Remember to put the complete path of User class!
This is the object that is going to be filled with data coming from User::create method.
Inside your Listener AssignRoles you have the event linked with the user filled and you can get it this way:
public function handle(Created $event)
{
$event->user;
// ...
}
Inside your Listener AssignRoles you can get all Requested params in your __construct method:
private $request;
public function __construct(Illuminate\Http\Request $request)
{
$this->request = $request;
}
With requested params in your hand you can apply the logic depending on the clicked button inside handle method:
public function handle(Created $event)
{
$event->user;
// here is the best place to do all the logic about roles that is going to be attached in this user. E.g:
switch($role = $this->request->role) {
case $role == 'Asesor':
$event->user->roles()->assignRole('Asesor');
break;
case $role == 'Buyer':
$event->user->roles()->assignRole('Buyer');
break;
}
}
To send role param into Request you need to create a form with hidden element,
<input type='hidden' name='role' />
create more than one submit button to fill role hidden element
<input type='submit' value='I want to be an Advisor' onClick='setRole("Advisor")' />
<input type='submit' value='I want to be a Buyer' onClick='setRole("Buyer")' />
And, finally you need a logic to setRole js method. Good Look. ;-)
For assign Role to user.
Controller function will be like.
/* assign role */
if(is_array($request['role']))
{
foreach($request['role'] as $d)
{
$user->roles()->attach(Role::where('id',$d)->first());
}
}
return redirect()->route();

How would I go about adding a property address column to my tenancy table (friends table)

Ok.
I'm building a property app. I have a friends system implemented in the app. I'm using this to allow a landlord to add a tenant and this works as a connection. My question is how would I associated one of the landlords properties with the request when it is send.
At the moment, when a request is sent, the following is posted to the database. User_id (Landlord), Tenancy_id (Tenant), Accepted (false). I would like to post a property address with this also, but I'm stuck on how to do that.
I have a form, where I have the landlords name, and tenants name, but also a list of the landlords property. I have no idea how to send this to the database. As it's not a normal store method. I will post the code.
The add method in the ACCOUNT CONTROLLER
public function getAdd($id){
$user = User::where('id', $id)->first();
//If the user can be found
if(!$user){
return redirect('/')->with(['status', 'Profile Not Found']);
}
if(Auth::user()->id === $user->id){
return redirect()->route('home');
}
//If current sign in user has request pending with the users
//If the uer has a request pending with auth user
if (Auth::user()->hasTenancyRequestsPending($user) ||
$user->hasTenancyRequestsPending(Auth::user())){
return redirect('/account/{{$user->id}}')->with('status', "Friend request already pending");
}
//Check if tenancy already exists
if(Auth::user()->isInTenancyWith($user)){
return redirect('/account/{{$user->id}}')->with('status', "Already i a tenancy");
}
//After passing all checks. Add other account
//Landord is adding the tenant
Auth::user()->addTenancy($user);
return redirect('/account/{{$user->id}}')->with('status', "Request Sent");
}
The create FORM
The properties variable is loaded from a controller which holds all properties owned by a landlord.
<form action="/account/{{$user->id}}/add" method="POST">
{{ csrf_field() }}
<select class="form-control" id="property_address" name="property_address">
<!--Gets all counties from DB -->
#foreach ($properties as $property)
<option value={{$property->id}}>{{$property->address . ', ' . $property->town . ', ' . $property->county}}</option>
#endforeach
</select>
<label for="landlord-name">Landlord Name</label>
<select class="form-control" name="landlord-name">
<option value="{{Auth::user()->name}}">{{Auth::user()->name}}</option>
</select>
<label for="tenand-name">Tenant Name</label>
<select class="form-control" name="tenant-name">
<option value="{{$user->name}}">{{$user->name}}</option>
</select>
<button class="mt-2 btn btn-primary" type="submit">Create Tenancy</button>
</form> <!-- ./form -->
THE User model which has the methods to add friends
//Tenancies of this uers. User model, tenancy table.
public function tenanciesOfMine(){
return $this->belongsToMany('App\User', 'tenancies', 'user_id', 'tenancy_id');
}
//Users who have this user as a friend
//Inverse of user tenncies -> Both users have tenancy if one exists. One user can't be in a tenancy with someone who is not in tenacy with them.
//Like friends on FB. You can't be friends with someone, without them being friends with you also.
public function tenancyOf(){
return $this->belongsToMany('App\User', 'tenancies', 'tenancy_id', 'user_id');
}
//If a tenancy is accepted, create the tenancy ie friendship.
public function tenancies(){
//Getting friends of this user. Where accepted is true
return $this->tenanciesOfMine()->wherePivot('accepted', true)->get()->
//merge the inverse. Tennancy created with both users
merge($this->tenancyOf()->wherePivot('accepted', true)->get());
}
//Request hasn't yet been accepted. Display list of pending requests
public function tenacyRequests(){
return $this->tenanciesOfMine()->wherePivot('accepted', false)->get();
}
//Inverse of Tenancy Requests
public function tenancyRequestsPending(){
return $this->tenancyOf()->where('accepted', false)->get();
}
//If a user has a request pending from another user
public function hasTenancyRequestsPending(User $user){
return (bool) $this->tenancyRequestsPending()->where('id', $user->id)->count();
}
public function hasTenancyRequestsReceived(User $user){
return (bool) $this->tenacyRequests()->where('id', $user->id)->count();
}
//Add tenancy
public function addTenancy(User $user){
$this->tenancyOf()->attach($user->id);
}
//Add tenancy
public function acceptTenancyRequest(User $user){
$this->tenacyRequests()->where('id', $user->id)->first()->pivot->update([
'accepted' => true,
]);
}
Here are the migrations for Tenancies (Which holds the landlord and Tenant) relationship.
Schema::create('tenancies', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id');
$table->integer('tenancy_id');
$table->string('property_address');
$table->boolean('accepted')->default('0');
});
And for property
Schema::create('property_adverts', function (Blueprint $table) {
$table->increments('id');
$table->string("photo");
$table->string('address');
});

Account balance system with Stripe

For the past two days I've been trying to understand how Stripe works.. What I'm trying to build is a simple system that lets the user to add funds to his account on the site.
I followed a tutorial I found on the internet that uses Laravel Cashier but as I've read on the laravel documentation if I need to perform single charges I should use directly Stripe. The thing is, there are not many tutorials on how this should be done with laravel..
Here's what I have so far:
VIEW:
<form class="app-form" style="margin-bottom: 0px;" action="/add-funds" method="POST">
{{ csrf_field() }}
<select id="funds-options" style="width: 20%; margin-bottom: 20px;" name="add-funds-select">
<option value="30">$30</option>
<option value="50">$50</option>
<option value="100">$100</option>
<option value="200">$200</option>
<option value="300">$300</option>
<option value="500">$500</option>
</select>
<p style="margin-bottom: 0px;">
<script src="https://checkout.stripe.com/checkout.js"></script>
<button id="customButton">Purchase</button>
<script>
var handler = StripeCheckout.configure({
key: '{{ getenv('STRIPE_KEY') }}',
image: 'https://stripe.com/img/documentation/checkout/marketplace.png',
locale: 'auto',
token: function(token) {
// You can access the token ID with `token.id`.
// Get the token ID to your server-side code for use.
}
});
document.getElementById('customButton').addEventListener('click', function(e) {
// Open Checkout with further options:
var userAmount = $("#funds-options").val();
handler.open({
name: 'Demo Site',
description: '2 widgets',
amount: userAmount*100
});
e.preventDefault();
});
// Close Checkout on page navigation:
window.addEventListener('popstate', function() {
handler.close();
});
</script>
</p>
</form>
I have this select tag where the user can select the amount he wants to add to his account. Now, this opens the widget from Stripe but as soon as I hit pay, I'm getting that info: "You did not set a valid publishable key".
I tried this using the publishable key directly and I'm able to pass this but as soon as it gets into the controller it throws pretty much the same error, something like API key was not set.
I set the keys in the env file and I also reference them in the services.php..
ENV:
STRIPE_KEY=pk_test_....
STRIPE_SECRET=sk_test_...
SERVICES:
'stripe' => [
'model' => App\User::class,
'key' => env('STRIPE_KEY'),
'secret' => env('STRIPE_SECRET'),
],
Anyway, even if I pass this "error" I'm still not sure if I'm doing this right.
Controller:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Auth;
class WalletController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
return view('user.wallet.index');
}
public function postPayWithStripe(Request $request)
{
return $this->chargeCustomer($request->input('add-funds-select'), $request->input('stripeToken'));
}
public function chargeCustomer($amount, $token)
{
\Stripe\Stripe::setApiKey(getenv('STRIPE_SECRET'));
if (!$this->isStripeCustomer())
{
$customer = $this->createStripeCustomer($token);
}
else
{
$customer = \Stripe\Customer::retrieve(Auth::user()->stripe_id);
}
return $this->createStripeCharge($amount, $customer);
}
public function createStripeCharge($amount, $customer)
{
try {
$charge = \Stripe\Charge::create(array(
"amount" => $amount,
"currency" => "brl",
"customer" => $customer->id,
"description" => "Add funds to your account"
));
} catch(\Stripe\Error\Card $e) {
return redirect()
->route('index')
->with('error', 'Your credit card was been declined. Please try again or contact us.');
}
return $this->postStoreAmount($amount);
}
public function createStripeCustomer($token)
{
\Stripe\Stripe::setApiKey(getenv('STRIPE_SECRET'));
$customer = \Stripe\Customer::create(array(
"description" => Auth::user()->email,
"source" => $token
));
Auth::user()->stripe_id = $customer->id;
Auth::user()->save();
return $customer;
}
/**
* Check if the Stripe customer exists.
*
* #return boolean
*/
public function isStripeCustomer()
{
return Auth::user() && \App\User::where('id', Auth::user()->id)->whereNotNull('stripe_id')->first();
}
public function postStoreAmount($amount)
{
$userBalance = Auth::user()->balance;
$userBalance = $userBalance + $amount;
Auth::user()->save();
session()->flash('message', 'You just added funds to your account.');
return redirect()->route('index');
}
}
I have a field in the users table that holds the user balance.
As I mentioned, I followed a tutorial I found on the internet.. I'm not sure how this should work. Any suggestions?
You will follow this tutorial. I am integrated it in my cart functionality previous week. Its very easy to integrate ...have Fun :)
http://justlaravel.com/integrate-stripe-payment-gateway-laravel/
For anyone else looking for how to retrieve account balance with laravel cashier, I found it like this:
$user = App\User::first();
echo $user->asStripeCustomer()->account_balance;
This returns the account balance in cents.

Resources