Laravel 6: How to override sendPasswordResetNotification function - laravel

I've been working on resetting password but using a custom notification instead of Laravel notification. This is the file vendor\laravel\framework\src\Illuminate\Auth\Passwords\CanResetPassword.php
public function sendPasswordResetNotification($token)
{
//use custom notification to change the url instead of modifying the original class
//$this->notify(new ResetPasswordNotification($token));
$this->notify(new CustomResetPassword($token));
}
That's ow I call it in a service class
$reset_password_status = Password::reset($credentials, function ($user, $password) {
$user->password = $password;
$user->save();
});
if ($reset_password_status == Password::INVALID_TOKEN) {
return $this->returnError->error("Invalid token provided");
}
But the problem is building the project online is done automatically and run composer install every time and can't just upload the change manually so I'm looking for a way to override this function in my code to reset the password instead of editing CanResetPassword.php file which exists in the vendor folder

On your Class that is using this trait you can override this function. Every function written in class have priority over trait function.

In user.php model
public function sendPasswordResetNotification($token)
{
$this->notify(new CustomResetPassword($token));
}

Related

Laravel authorization policy not working on Show page

I have a laravel app using Policies to assign roles and permissions, i cant seem to access the show page and im not sure what im doing wrong?
If i set return true it still shows a 403 error as well, so im unsure where im going wrong here. The index page is accessable but the show page is not?
UserPolicy
public function viewAny(User $user)
{
if ($user->isSuperAdmin() || $user->hasPermissionTo(44, 'web')) {
return true;
}
return false;
}
public function view(User $user, User $model)
{
if ($user->isSuperAdmin() || $user->hasPermissionTo(44, 'web')) {
return true;
}
return false;
}
UserController
public function __construct()
{
$this->authorizeResource(User::class, 'user');
}
public function index()
{
$page_title = 'Users';
$page_description = 'User Profiles';
$users = User::all();
return view('pages.users.users.index', compact('page_title', 'page_description', 'users'));
}
public function create()
{
//
}
public function store(Request $request)
{
//
}
public function show($id)
{
$user = User::findOrFail($id);
$user_roles = $user->getRoleNames()->toArray();
return view('pages.users.users.show', compact('user', 'user_roles'));
}
Base on Authorize Resource and Resource Controller documentation.
You should run php artisan make:policy UserPolicy --model=User. This allows the policy to navigate within the model.
When you use the authorizeResource() function you should implement your condition in the middleware like:
// For Index
Route::get('/users', [UserController::class, 'index'])->middleware('can:viewAny,user');
// For View
Route::get('/users/{user}', [UserController::class, 'view'])->middleware('can:view,user');
or you can also use one policy for both view and index on your controller.
I had an issue with authorizeResource function.
I stuck on failed auth policy error:
This action is unauthorized.
The problem was that I named controller resource/request param with different name than its model class name.
F. ex. my model class name is Acknowledge , but I named param as timelineAcknowledge
Laravel writes in its documentation that
The authorizeResource method accepts the model's class name as its first argument, and the name of the route / request parameter that will contain the model's ID as its second argument
So the second argument had to be request parameter name.
// Here request param name is timelineAcknowledge
public function show(Acknowledge $timelineAcknowledge)
{
return $timelineAcknowledge->toArray();
}
// So I used this naming here also
public function __construct()
{
$this->authorizeResource(Acknowledge::class, 'timelineAcknowledge');
}
Solution was to name request param to the same name as its model class name.
Fixed code example
// I changed param name to the same as its model name
public function show(Acknowledge $acknowledge)
{
return $acknowledge->toArray();
}
// Changed here also
public function __construct()
{
$this->authorizeResource(Acknowledge::class, 'acknowledge');
}
I looked over Laravel policy auth code and I saw that the code actually expects the name to be as the model class name, but I couldn't find it anywhere mentioned in Laravel docs.
Of course in most of the cases request param name is the same as model class name, but I had a different case.
Hope it might help for someone.

Laravel Fortify Customize Authentication Redirect

In Laravel fortify on customization authentication process, i can not able to redirect to login page with error message which we were able to do in Auth.
Here is the customization documentation link: https://jetstream.laravel.com/1.x/features/authentication.html#customizing-the-authentication-process
if ($user && Hash::check($request->password, $user->password) && $user->status == 'active') {
return $user;
} elseif ($user->status == 'inactive') {
//redirect with some error message to login blade
} elseif ($user->status == 'blocked') {
//redirect with some error message to login blade
}
Please help me out on this.
For those coming from google search who use Laravel Jetstream (which uses Fortify):
Snapey of Laracasts answered this question and made a tutorial which uses your own LoginResponse to override the default login behavior.
I made mine like this but of course you should create your own according to your needs.
// app/Http/Responses/LoginResponse.php
namespace App\Http\Responses;
use Illuminate\Support\Facades\Auth;
use Laravel\Fortify\Contracts\LoginResponse as LoginResponseContract;
class LoginResponse implements LoginResponseContract
{
/**
* #param $request
* #return mixed
*/
public function toResponse($request)
{
// replace this with your own code
// the user can be located with Auth facade
$home = Auth::user()->is_admin ? config('fortify.dashboard') : config('fortify.home');
return $request->wantsJson()
? response()->json(['two_factor' => false])
: redirect($home);
}
}
The next step it to modify JetstreamServiceProvider to use your LoginReponse
public function boot()
{
$this->configurePermissions();
Jetstream::deleteUsersUsing(DeleteUser::class);
// register new LoginResponse
$this->app->singleton(
\Laravel\Fortify\Contracts\LoginResponse::class,
\App\Http\Responses\LoginResponse::class
);
}
Hope it saves you time.
I understand your frustration with the documentation (or lack thereof). I had a similar problem and this is how I managed to do it:
if ($user && in_array($user->status_id, [1,2,3])) {
if (Hash::check($request->password, $user->password)) {
return $user;
}
}
else {
throw ValidationException::withMessages([
Fortify::username() => "Username not found or account is inactive. Please check your username.",
]);
}
https://github.com/laravel/fortify/issues/94#issuecomment-700777994
For SPA applications that only want a custom JSON response rather than the default {two_factor: false}.
Create a custom response that implements LoginResponse contract of Fortify (in this case I'm returning the user object):
<?php
declare(strict_types=1);
namespace App\Http\Responses;
use Laravel\Fortify\Contracts\LoginResponse as LoginResponseContract;
use Symfony\Component\HttpFoundation\Response;
class LoginResponse implements LoginResponseContract
{
public function toResponse($request): Response
{
return response()->json(auth()->user());
}
}
Add this line to the boot method of FortifyServiceProvider:
$this->app->singleton(LoginResponseContract::class, LoginResponse::class);
Making sure you've imported the namespaces correctly:
use App\Http\Responses\LoginResponse;
use Laravel\Fortify\Contracts\LoginResponse as LoginResponseContract;
If you are still not getting a JSON from the server, make sure your request has the right headers. It should be an XHR request that accepts application/json.
Inspired by this article from Laravel News.
for example - custom redirect after login/logout/register. By request parameter - alias
In FortifyServiceProvider class
Add.
use Laravel\Fortify\Contracts\LoginResponse;
use Laravel\Fortify\Contracts\LogoutResponse;
use Laravel\Fortify\Contracts\RegisterResponse;
And then in register method.
$this->app->instance(LogoutResponse::class, new class implements LogoutResponse {
public function toResponse($request)
{
return redirect('/'.$request->alias);
}
});
$this->app->instance(LoginResponse::class, new class implements LoginResponse {
public function toResponse($request)
{
return redirect()->intended('/'.$request->alias.'/admin/dashboard');
}
});
$this->app->instance(RegisterResponse::class, new class implements RegisterResponse {
public function toResponse($request)
{
return redirect('/'.$request->alias.'/admin/dashboard');
}
});
goto \config\fortify.php at line 66, change home value to any path you want
'home' => '/dashboard',
Currently, Fortify doesn't have a way to customize redirects.
There is an open issue requesting this bahavior here: https://github.com/laravel/fortify/issues/77
There is a good chance this will be added soon!

Change InertiaJS-Laravel default RootView

I am using Laravel 8 and I have installed InertiaJS, but in my directory resources/views/ I have a single file called index.blade.php which I plan to use with InertiaJS.
By default, InertiaJS looks for a file inside that directory called app.blade.php. I know writing the following statement:
\Inertia\Inertia::setRootView('index');
Change the rootView and allow me to use the file I have created. It may seem like a stupid question, but as far as I see it, I can do 2 things ..
Rename file index.blade.php to app.blade.php
Write the previous sentence .. in one of the ServiceProviders that I have
I wonder the following:
InertiaJS-Laravel does not allow publishing a ServiceProvider with the command php artisan vendor:publish? (the output of this command does not show me anything to publish regarding this package)
To solve my problem I should create a ServiceProvider like: php artisan make:provider InertiaServiceProvider and then register it?
Or just add the previous statement to one of the ServiceProvider that already exist? Like in app/Http/Providers/RouteServiceProvider.php
What do you recommend that would be better?
I want to seek the largest possible organization in my project. Thank you very much in advance...
Update; after my initial answer (on 20-09-2020), Inertia introduced middleware to handle your Inertia requests.
As described in the answers below, you can use the command php artisan inertia:middleware to generate this middleware. You can set the root index with:
// Set root template via property
protected $rootView = 'app';
// OR
// Set root template via method
public function rootView(Request $request)
{
return 'app';
}
You can find more info in the docs.
Even tighter, just override the rootView method in App\Http\Middleware\HandleInertiaRequests like this...
public function rootView(Request $request)
{
if ($request->route()->getPrefix() == 'admin') {
return 'layout.admin';
}
return parent::rootView($request);
}
You can do this inside your controller on the fly.
<?php
namespace App\Http\Controllers;
use App\Models\User;
use Illuminate\Http\Request;
use Inertia\Inertia;
class NewsController extends Controller
{
public function index()
{
Inertia::setRootView('layouts.news');
$users = User::all();
return Inertia::render('News/Index', compact('users'));
}
}
Replace in the App\Http\Middleware\HandleInertiaRequests
protected $rootView = 'app';
with:
public function rootView(Request $request): string
{
if ($request->route()->getPrefix() === '/admin') {
return 'admin.app';
}
return 'app';
}
I think it would be easier to change it in App\Http\Middleware\HandleInertiaRequests.
Be sure to run php artisan inertia:middleware during inertia server-side installation.
Also include it in your web middleware group.
Then go to App\Http\Middleware\HandleInertiaRequests and change the $rootView property to the name of the blade file you want to use. Example:
protected $rootView = 'index';
Extended #Olu Udeh answer
overwrite handle method of App\Http\Middleware\HandleInertiaRequests middleware
public function handle(Request $request, Closure $next)
{
if($request->route()->getPrefix() == 'admin'){
$this->rootView = 'layouts.admin';
}
return parent::handle($request, $next);
}
In laravel 8 this work for me
App\Http\Middleware\HandleInertiaRequests
Code
public function rootView(Request $request)
{
if(request()->is('admin/*') or request()->is('admin'))
{
return 'admin';
}
return parent::rootView($request);
}

laravel nova observer trying to get property on non object

I set a database connection by the auth()->user()-dbname
This works as desired using this in the model
public function __construct() {
$this->connection = auth()->user()->dbname;
}
Now I want to observe the model on creation, update, etc.
I tried to use
protected static function boot()
{
parent::boot();
static::creating(function ($model) {
$itemIds = $model->item_ids;
... update another model based on the $itemIds
});
But Nova is not recognizing the static::creating function
So I created an Observer (I think a better choice) however when the observer is called it does not recognize the
auth()->user()->dbname property
Why doesn't the observer recognize auth?
This may be caused because there is no authenticated user. Try dumping and see what it throws you.
public function __construct() {
// Should throw an User model OR null.
dd(auth()->user());
// Alternatively, you could use the Logger
\Log::info(json_encode(auth()->user()));
$this->connection = auth()->user()->dbname;
}
If auth()->user() is null, then no user is logged in and as you might have guessed, null is a non-object.
Thanks for the suggestions but none would work for me. I gave up on Observers in Nova. I used the boot() function. This is how I setup milti tenant.
In the _constructor I added this
public function __construct() {
parent::__construct(); // needed before boot would fire
$this->connection = auth()->user()->dbname;
}
Then my boot() function became the observer
protected static function boot()
{
parent::boot();
static::creating(function($item) {
$item->event_id = Event::currentEventID();
});
}

Adding custom where clause to AuthenticatesUser Trait Laravel

We have decided to use Laravel for a project as a test run for future frameworks and are really enjoying it. There is one issue we are having though.
We use the trait Illuminate\Foundation\Auth\AuthenticatesUsers which handles user authentication. It works well. However, we have a column in the database called userstatus which could be a 0 or a 1.
How do we inject this where clause into the Illuminate\Foundation\Auth\AuthenticatesUsers trait?
I was thinking maybe something here (in my LoginController):
public function authenticated($request , $user){
//if $user->userstatus != 1 logout and redirect to start page
}
But I dont know how to logout (im looking into that now) .
your logic is right, you should redefine login and authenticated methods within LoginController.
your methods should be like below:
this method should be within your LoginController.php:
class LoginController extends Controller
{
use AuthenticatesUsers {
login as public loginParent;
}
protected function login(Request $request){
$default = '/';
$user = User::where('email', $request->get('email'))->NotActive->first();
if($user){
return redirect()->intended($default);
}
return $this->loginParent($request);
}
protected function authenticated(Request $request, $user)
{
if($user->not_active) {
$this->logout($request);
}
}
}
then we should create ScopeNotActive method within User.php Model as Local Scope:
//User.php
public function ScopeNotActive($query){
return $query->where('userStatus', '!=', 1);
}
and a Mutator to check if the user is not active:
// User.php
public function getNotActiveAttribute(){
return $this->userStatus != 1;
}

Resources