Can I use dynamic model on middleware? - laravel

I have 2 routes that requires a person to be tagged to access the discussions.
http://localhost:8000/api/fieldReports/{fieldReport}/discussions
http://localhost:8000/api/agendas/{agenda}/discussions
Currently, I have created this middleware, but instead of pointing right to a specific model, and duplicate it for each model with the exact same functionality, I want it to be more reusable.
Middleware\ForbidUntaggedUser.php
class ForbidUntaggedUser
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle(Request $request, Closure $next)
{
$user = $request->user();
$report = $request->report; // <-- I hardcoded the model, I want this to be dynamic
// The `taggedUsers` remains the same (identical) for each model that has tagging system on it.
if (!$report || !$report->taggedUsers->contains($user->id)) {
return response()->json('Your action is unauthorized.', 403);
}
return $next($request);
}
}
I've tried to use Policy but it doesn't work, so I think I need a middleware for this.
Policies\FieldReportDiscussionPolicy.php
class FieldReportDiscussionPolicy
{
use HandlesAuthorization;
/**
* Determine whether the user can view any models.
*
* #param \App\Models\User $user
* #return mixed
*/
public function viewAny(User $user, FieldReport $fieldReport)
{
return $user->can('view any fieldReportDiscussion')
&& $fieldReport->taggedUsers->contains($user->id);
}
... // and so on..
}
Controllers\FieldReportDiscussionController.php
class FieldReportDiscussionController extends Controller
{
protected $model;
/**
* Create new instance.
*
* #return void
*/
public function __construct()
{
$this->authorizeResource(
FieldReportDiscussion::class,
['fieldReportDiscussion', 'fieldReport'] // This gave me error "Array to string conversion"
);
$this->model = new FieldReportDiscussion;
}
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index(FieldReport $fieldReport)
{
$discussions = $this->model->registries($fieldReport)->paginate(100);
return response()->json($discussions);
}
}
I need the dependency injection on the controller because the route is nested with each model as the parent, like this one..
routes\api.php
Route::apiResource('fieldReports', FieldReportController::class);
Route::apiResource('fieldReports.discussions', FieldReportDiscussionController::class)->except(['update'])->parameter('discussions', 'fieldReportDiscussion');
So, what's the solution for this? Can I make it dynamic (the first request object)?

I think you're on the right track with using middleware, although you'll need some conditional checks, something along the lines like:
class ForbidUntaggedUser
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle(Request $request, Closure $next)
{
$instance = null;
if ($request->report !== null) {
$instance = $request->report;
} else if ($request->agenda !== null) {
$instance = $request->agenda;
}
if (!$instance || !$instance->taggedUsers->contains(auth()->id())) {
return response()->json('Your action is unauthorized.', 403);
}
return $next($request);
}
}

If you have named correctly your params in your controller i.e. in a resoruce controller
<?php
namespace App\Http\Controllers;
use App\Models\Agenda;
class AgendaController extends Controller
{
public function show(Agenda $agenda)
{
....
}
}
The first parameter of your request will be the named model, so you can get the model with the getModel() function, if you are not sure, you can search it with findModel() function.
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
class MyMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
* #return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle(Request $request, Closure $next)
{
$model = $this->getModel($request);
$tryGetModel = $this->findModel($request);
}
private function getModel(Request $request) : Model|null
{
$modelParameterName = $request->route()->parameterNames()[0];
return $request->$modelParameterName ?? null;
}
private function findModel(Request $request) : Model|null
{
foreach($request->route()->parameters() as $param)
{
if($param instanceof Model)
return $param;
}
return null;
}
}

Related

ReflectionException Class app\Repositories\MailMessageRepository does not exist

i'm having trouble accessing a repository, I can't call functions. I'm trying to integrate a softdelete button on my MailMessages datatable but I can't use the repository, I recived the following message:
ReflectionException Class app\Repositories\MailMessageRepository does
not exist
My MailMessageController
<?php
namespace App\Http\Controllers;
use App\DataTables\MailMessageDataTable;
use App\Http\Requests\MailMessageRequest;
use app\Repositories\MailMessageRepository;
use App\MailMessage;
use Illuminate\Http\Request;
use DataTables;
use PulkitJalan\Google\Facades\Google;
class MailMessageController extends Controller
{
protected $mailMessageRepository;
/**
* UserController constructor.
* #param $mailmessageRepository
*/
public function __construct(mailmessageRepository $mailmessageRepository)
{
parent::__construct();
$this->MailMessageRepository = $mailmessageRepository;
}
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index(MailMessageDataTable $MailMessageDataTable)
{
return $MailMessageDataTable->render('mailmessage.index');
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create()
{
// $MailMessage = $this->MailMessageRepository;
return view('mailmessage.create');
}
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(MailMessageRequest $request)
{
$MailMessage = $this->MailMessageRepository->saveMailMessage($request);
return redirect()->route('MailMessage.show', ["id" => $MailMessage->id])
->with(["message" => __('messages.create.success')]);
}
/**
* Display the specified resource.
*
* #param \App\MailMessage $mailMessage
* #return \Illuminate\Http\Response
*/
public function show($id)
{
$MailMessage = MailMessage::find($id);
return view('MailMessage.show', ['MailMessage' => $MailMessage]);
}
/**
* Show the form for editing the specified resource.
*
* #param \App\MailMessage $mailMessage
* #return \Illuminate\Http\Response
*/
public function edit($id)
{
$MailMessage = MailMessage::find($id);
return view('MailMessage.edit', ['MailMessage' => $MailMessage]);
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param \App\MailMessage $mailMessage
* #return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
$MailMessage = MailMessage::find($id);
$MailMessage->type = $request->type;
$MailMessage->description = $request->description;
$MailMessage->from_value = $request->from_value;
$MailMessage->to_value = $request->to_value;
$MailMessage->update();
return redirect('MailMessage/' .$MailMessage->id)->with(["message" => __('messages.edit.success')]);
}
/**
* Remove the specified resource from storage.
*
* #param \App\MailMessage $mailMessage
* #return \Illuminate\Http\Response
*/
public function destroy($id)
{
$MailMessage = $this->MailMessageRepository->getMessagebyId($id, true);
if ($MailMessage->trashed()) {
$MailMessage->restore();
}else{
$MailMessage->delete();
}
return redirect()->route('MailMessage.index')
->with(["message" => __('messages.update.success')]);
}
public function digest_report(MailMessage $mailMessage)
{
}
}
my MailMessageRepository
<?php
namespace App\Repositories;
use App\User;
use App\MailMessage;
use App\Enums\MailMessageType;
use Illuminate\Support\Facades\Auth;
class MailMessageRepository
{
public function getMessage($id, $trashed = false)
{
if($trashed){
return MailMessage::withTrashed();
}
return MailMessage;
}
public function getMessageById($id, $trashed = false)
{
if ($trashed) {
return MailMessage::withTrashed()->with('roles')
->where('id', '=', $id)->first();
}
return MailMessage->where('id', '=', $id)->first();
}
public function deleteMailMessage($id)
{
$MailMessage = MailMessage::find($id);
$MailMessage->delete();
}
public function saveMailMessage($request)
{
$MailMessage = new Message($request->all());
$MailMessage->save();
return $MailMessage;
}
public function setOAuthAccessToken($accessToken)
{
}
public function updateMailMessage($request, $id) {
}
}
Maybe something wrong, you declare mailMessageRepository variable so you need to use $this->mailMessageRepository
public function __construct(mailmessageRepository $mailmessageRepository)
{
parent::__construct();
$this->MailMessageRepository = $mailmessageRepository;
}
try this
public function __construct(MailMessageRepository $mailmessageRepository)
{
parent::__construct();
$this->mailMessageRepository = $mailmessageRepository;
}
and try replace all $this->MailMessageRepository to $this->mailMessageRepository in your code

Laravel 6 - How to restrict route by user field value?

Atm, I use a steamauth API to grab a users steamid and pass it into user->steamid, but I want to restrict it to, if the field named steamid in users is not null(has already a steamid) they cant enter the route and will get a redirect back. I have tried for several hours now, but i cant seem to get it to working. This is my AuthController atm:
use Invisnik\LaravelSteamAuth\SteamAuth;
use App\User;
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Request;
class AuthController extends Controller
{
/**
* The SteamAuth instance.
*
* #var SteamAuth
*/
protected $steam;
/**
* The redirect URL.
*
* #var string
*/
protected $redirectURL = '/';
/**
* AuthController constructor.
*
* #param SteamAuth $steam
*/
public function __construct(SteamAuth $steam)
{
$this->steam = $steam;
$this->middleware('auth');
}
/**
* Redirect the user to the authentication page
*
* #return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function redirectToSteam()
{
return $this->steam->redirect();
}
/**
* Get user info and log in
*
* #return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function handle()
{
if ($this->steam->validate()) {
$info = $this->steam->getSteamId();
if (!is_null($info)) {
Auth::user()->update(['steamid' => $info]);
return redirect($this->redirectURL); // redirect to site
}
}
return $this->redirectToSteam();
}
Added this custom middleware and it works:
public function handle($request, \Closure $next)
{
/*$user = User::where('steamid', $request)->first();
if (!is_null($user)) {
return redirect('/profile');
}*/
if ($request->user()->steamid !== null){
return redirect('/profile')->with('denied', 'Du kan kun tilføje én steamprofil');
}
return $next($request);
}

Laravel, Show(), Edit (), update functions not working

In the code below methods show, edit update are not working.
<?php
namespace App\Http\Controllers\admins;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\contact;
use Image;
use Auth;
use Storage;
use File;
class ContactController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
$contact = Contact::orderby('created_at', 'desc')->paginate(5);
//$agent=Agent::orderby('id','desc')->paginate(5);
return view('admin.messages.index', ['contacts' => $contact]);
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create()
{
return back()->with('success', 'Message can only be created by Users end.');
}
/** * Display the specified resource.
*
* #param \App\contact $contact
* #return \Illuminate\Http\Response
*/
public function show(contact $contact)
{
dd(['contact' => $contact]);
//return back()->with('success','Message Contents Are Already Shown');
}
/**
* Show the form for editing the specified resource.
*
* #param \App\contact $contact
* #return \Illuminate\Http\Response
*/
public function edit(contact $contact)
{
return view('admin.messages.edit', compact('contact'));
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param \App\contact $contact
* #return \Illuminate\Http\Response
*/
public function update(Request $request, contact $contact)
{
dd($request);
}
/**
* Remove the specified resource from storage.
*
* #param \App\contact $contact
* #return \Illuminate\Http\Response
*/
public function destroy(contact $contact)
{
return back()->with('success', 'Message history can not be Deleted. ');
}
}
Assuming you are using a slug in a route like contacts/{ slug }
public function show(contact $contact)
{
dd(['contact' => $contact]);
//return back()->with('success','Message Contents Are Already Shown');
}
Receives an id not a contact... you are initializing/declaring in the function parameter as contact thats why it somehow gets casted to a contact... but it's an id you should do something like:
public function show($id)
{
$contact = Contact::findOrFail($id);
dd(['contact' => $contact]);
//return back()->with('success','Message Contents Are Already Shown');
}

Object of class Illuminate\Routing\Redirector could not be converted to string

On my laravel project when, I'm trying to authorize, shows me error exception
"Object of class Illuminate\Routing\Redirector could not be converted to string"
It indicates me to my Middleware Class
use Closure;
use Illuminate\Support\Facades\Auth;
class RedirectIfAuthenticated
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #param string|null $guard
* #return mixed
*/
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->check()) {
return redirect('/dashboard');
}
return $next($request); //This row could not be converted to string
}
}
and to this file
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Storage;
class VerifyAppInstalled
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if (config('database.transfer_mode') == "1") {
if (password_verify($request->server('SERVER_NAME'), getOption('app_key', true))
&& password_verify(strrev($request->server('SERVER_NAME')), getOption('app_code', true))) {
return redirect('/transfer/restore');
}
return redirect('/transfer/ready');
}
if (config('database.installed') == '%installed%') {
return redirect('/install');
}
if (Storage::exists('images/update')) {
return redirect('/update-progress');
}
\App::setLocale(request()->session()->get('locale', getOption('language')));
return $next($request);
}
}
Please help me what is wrong here?
enter image description here

laravel redirect to url after login

I have trouble with redirecting to an url after login.
The situation is that someone visits a blog post, and needs to login before adding a comment. So the user clicks on the login link and logs in on "auth/login", and is always redirected to "/home".
I want the user to be redirected to the blogpost when an url is set like "auth/login?redirect=url/to/blogpost"
I have the following Middleware:
app\Http\Middleware\RedirectIfAuthenticated
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Contracts\Auth\Guard;
class RedirectIfAuthenticated
{
/**
* The Guard implementation.
*
* #var Guard
*/
protected $auth;
/**
* Create a new filter instance.
*
* #param Guard $auth
* #return void
*/
public function __construct(Guard $auth)
{
$this->auth = $auth;
}
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if ($this->auth->check()) {
return redirect('/home');
}
return $next($request);
}
}
app\Http\Middleware\Authenticate
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Contracts\Auth\Guard;
class Authenticate
{
/**
* The Guard implementation.
*
* #var Guard
*/
protected $auth;
/**
* Create a new filter instance.
*
* #param Guard $auth
* #return void
*/
public function __construct(Guard $auth)
{
$this->auth = $auth;
}
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if ($this->auth->guest()) {
if ($request->ajax()) {
return response('Unauthorized.', 401);
} else {
return redirect()->guest('auth/login');
}
}
return $next($request);
}
}
Why don't you use the intended method on redirector? Read about this in docs
The intended method on the redirector will redirect the user to the URL they were attempting to access before being caught by the authentication filter. A fallback URI may be given to this method in case the intended destination is not available.
I've decided to copy and paste the getLogin function of the trait AuthenticatesUsers into my AuthController. I overwrite the function AND keep the trait as is.
I've just added
\Session::put('url.intended',\URL::previous());
If you're using standard authentication from Laravel 5, find a app/Http/Controllers/Auth/AuthController.php file and change $redirectPath to this:
protected $redirectPath = '/url/to/blogpost';

Resources