Login log laravel 5 - laravel

I wanted to create user logs but something does not work for me.
protected $listen = [
'Illuminate\Auth\Events\Login' => [
'App\Listeners\LogSuccessfulLogin',
],
LogSuccessfulLogin.php
class LogSuccessfulLogin
{
/**
* Create the event listener.
*
* #param Request $request
* #return void
*/
public function __construct(User $user)
{
$this->user = $user;
}
/**
* Handle the event.
*
* #param Login $event
* #return void
*/
public function handle()
{
Event::listen('auth.login', function ($user, $remember) {
$user->update([
'last_login' => \Carbon\Carbon::now(),
'ip_address' => \Request::ip()
]);
});
}
}
I read many tutorials but did not help

You are telling Laravel to listing to the login event here:
protected $listen = [
'Illuminate\Auth\Events\Login' => [
'App\Listeners\LogSuccessfulLogin',
],
Listening to the event within the handle statement is incorrect. The event has already been triggered.
If you remove the Event::listen from your handle method, it should work.
/**
* Handle the event.
*
* #param Login $event
* #return void
*/
public function handle()
{
$this->user->update([
'last_login' => \Carbon\Carbon::now(),
'ip_address' => \Request::ip()
]);
}

Related

Laravel: How do I raise a 404 error instead of a 50X error when ID for resource is non-integer

I created a simple crud in Laravel, but I'm having a problem:
I am using Illuminate\Support\Facades\Route::resource method, this is my routes/web.php:
<?php
use Illuminate\Foundation\Application;
use Illuminate\Support\Facades\Route;
use Inertia\Inertia;
Route::get('/', function () {
return Inertia::render('Welcome', [
'canLogin' => Route::has('login'),
'canRegister' => Route::has('register'),
'laravelVersion' => Application::VERSION,
'phpVersion' => PHP_VERSION,
]);
});
Route::get('dashboard', [App\Http\Controllers\PageController::class, 'dashboard'])
->middleware('auth:sanctum')
->name('dashboard');
Route::resource('notes', App\Http\Controllers\NoteController::class)
->middleware('auth:sanctum');
app/Http/Controllers/NoteController.php:
<?php
namespace App\Http\Controllers;
use App\Models\Note;
use Illuminate\Http\Request;
use Inertia\Inertia;
class NoteController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index(Request $request)
{
if ($request->q) {
return Inertia::render('Notes/Index', [
'notes' => Note::where('title', 'ilike', "%$request->q%")->get(),
]);
}
return Inertia::render('Notes/Index', [
'notes' => Note::all()
]);
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create()
{
return Inertia::render('Notes/Create', [
'note' => new Note()
]);
}
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$note = Note::create($request->validate([
'title' => 'required',
'content' => 'required',
]));
return redirect()->route('notes.show', $note)->with('success', 'Nota creada');
}
/**
* Display the specified resource.
*
* #param \App\Models\Note $note
* #return \Illuminate\Http\Response
*/
public function show(Note $note)
{
return Inertia::render('Notes/Show', compact('note'));
}
/**
* Show the form for editing the specified resource.
*
* #param \App\Models\Note $note
* #return \Illuminate\Http\Response
*/
public function edit(Note $note)
{
return Inertia::render('Notes/Edit', compact('note'));
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param \App\Models\Note $note
* #return \Illuminate\Http\Response
*/
public function update(Request $request, Note $note)
{
$request->validate([
'title' => 'required',
'content' => 'required',
]);
$note->update($request->all());
return redirect()->route('notes.show', $note)->with('success', 'Nota actualizada');
}
/**
* Remove the specified resource from storage.
*
* #param \App\Models\Note $note
* #return \Illuminate\Http\Response
*/
public function destroy(Note $note)
{
$note->delete();
return redirect()->route('notes.index')->with('success', 'Nota eliminada');
}
}
When I go to /notes/a where 'a' is supposed to be the index of the note I want to see, I get a 500 error:
SQLSTATE[22P02]: Invalid text representation: 7 ERROR: invalid input syntax for type bigint: "a"
select * from "notes" where "id" = a limit 1
At this point, none of my code has yet run. How can I catch this error to raise a 404 error instead?
you can use firstOrFail() or findOrFail example code below
public function find(Request $request){
return Note::findOrFail($request->id);
}
You can use abort(404) which abort your code if no data found.
public function findNote($id)
{
$note = Note::find($id)
if($note == null)
{
abort(404);
}
}
you can use try catch block to modify the response
public function whatEverMyMethodIs( Request $request ) {
try {
return ModeL::find( $request->input('id') );
} catch (\Throwable $th) {
return response()->json(['message' => $th->getMessage()], 404 );
}
}
Since you're using the built-in resource controller, the following URIs, among others, will have been created and model binding happens. If the parameter doesn't fit the id's type it will error out.
GET /notes/{note}
GET /notes/{note}/edit
I have not found a way to modify the request validation when model binding happens. If you wish to customise the behaviour, you can do so by leaving the show and edit functions out of the route resource declaration and writing custom endpoints listed above.
routes/web.php
Route::resource('notes', NoteController::class)->except([
'show', 'edit'
]);
Route::get('/notes/{note}', [
'as' => 'notes.show',
'uses' => '\App\Http\Controllers\NoteController#show',
]);
app/Http/Controllers/NoteController.php
use Illuminate\Http\Request;
...
public function show(Request $request)
{
$noteId = $request->note;
...
}
You can perform the validation by switching Request to a custom request which inherits FormRequest.
More information can be found here:
https://laravel.com/docs/9.x/validation#form-request-validation

Laravel: Using policy on FormRequest always returns false

I'm trying to authorize whether a user is allowed to invite other users.
InvitedUserController
public function store(InvitedUserRequest $request)
{
$data = $request->all();
$data['user_id'] = auth()->user()->id;
$data['account_id'] = $request->session()->get('account_id');
InvitedUser::create($data);
}
I created a FormRequest class to handle validation:
class InvitedUser extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize(Request $request)
{
$account = Account::find($request->session()->get('account_id'));
return $this->user()->can('manageUsers', $account);
}
/**
* Validation error message
*/
public function messages() {
return [
'max' => 'You may only enter up to :max characters'
];
}
public function invalid() {
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'email' => 'required|max:255|email',
'role_id' => 'required|exists:roles,id',
];
}
}
Then my policy to handle authorization:
class InvitedUserPolicy
{
use HandlesAuthorization;
/**
* Determine whether the user can view any models.
*
* #param \App\User $user
* #return mixed
*/
public function manageUsers(User $user, Account $account)
{
dd('test');
$role = $user->roles()->wherePivot('account_id', $account->id)->first();
return $role->manage_users;
}
}
I registered the policy:
protected $policies = [
// 'App\Model' => 'App\Policies\ModelPolicy',
'App\InvitedUser' => 'App\Policies\InvitedUserPolicy'
];
For some reason, that dd() call doesn't even occur. So it's not reaching my policy and all requests are returning unauthorized.
even if i changed my policy to return true
public function manageUsers(User $user, Account $account)
{
return true;
}
I would still get unauthorized
How Can I call my policy from a FormRequest? Why is this not working?
So, while this is confusing to me, I've figured out the issue.
I needed to change my registered policies to the following:
protected $policies = [
// 'App\Model' => 'App\Policies\ModelPolicy',
'App\Account' => 'App\Policies\InvitedUserPolicy'
];
It's using the Account model instead of InvitedUser model. I think because that's what I'm passing in as a model?

Listeners and Events get error: Too few arguments to function App\Events\User\Created::__construct(),

I need have two Listeners in same event, and when an user has been created in the system, Lavarel send my an email with the credentials and another to assign roles of users. It's possible have two listeners in same event? Why does the system show me this message?
When I create an user the system show me:
Too few arguments to function App\Events\User\Created::__construct(), 1 passed in C:\xampp\htdocs\bwm\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Concerns\HasEvents.php on line 205 and exactly 2 expected
This is my Event:
class UserCreated
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $user;
public $password;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct($user,$password)
{
$this->user = $user;
$this->password = $password;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
}
This is my Listener Assign Roles:
class AssignRoles
{
private $request;
/**
* Create the event listener.
*
* #return void
*/
public function __construct(Request $request)
{
$this->request = $request;
}
/**
* Handle the event.
*
* #param Created $event
* #return void
*/
public function handle(UserCreated $event)
{
$event->user;
switch($role = $this->request->role)
{
case $role == 'Asesor':
$event->user->assignRole('Asesor');
$asesoria = Asesoria::orderby('created_at', 'desc')->first();
$asesoria->user_id = $event->user->id;
$asesoria->published = true;
$asesoria->update();
break;
case $role == 'Comprador':
$event->user->assignRole('Comprador');
break;
default:
$event->user->assignRole('Writer');
}
}
}
This is my Listener Send Login Credentials:
class SendLoginCredentials
{
/**
* Create the event listener.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* #param Created $event
* #return void
*/
public function handle(UserCreated $event)
{
Mail::to($event->user)->queue(
new LoginCredentials($event->user, $event->password)
);
}
}
In my function store of my UsersController I call to dispach:
UserCreated::dispatch($user, $password);
In my EventServiceProvider I have this:
protected $listen = [
Registered::class => [
SendEmailVerificationNotification::class,
],
'App\Events\User\UserCreated' => [
'App\Listeners\User\AssignRoles',
'App\Listeners\SendLoginCredentials',
],
];
You have two parameters in your constructor of UserCreated class and you are passing only one because you are dispatching it wrong way.
you can do it several ways:
Event::dispatch(new UserCreated($user, $password))
event(new UserCreated($user, $password))
Try these. Hope it works
I had a protected $dispachesEvents in User Model:
protected $dispatchesEvents = ['created' => 'App\Events\User\Created'];
That's why I got the error:
Too few arguments to function App\Events\User\Created::__construct(), 1 passed in C:\xampp\htdocs\bwm\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Concerns\HasEvents.php on line 205 and exactly 2 expected
I deleted it, and put the call to the dispacher 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($data['password']);
event(new Created($user,$data['password']));
return $user;
}
As I had a protected $dispatchesEvents in User Model,this it executes before that my call in the RegisterController.

Laravel : Overwrite Socialite Provider to add new fields

I want to extend/overwrite my LinkedInProvider.php (in vendor\laravel\socialite\src\Two) to add new fields in the Linkedin Request.
I've create a new LinkedInProvider.php (in app\Providers) with the following code :
namespace App\Providers;
use Illuminate\Support\Arr;
use Illuminate\Http\Request;
use Laravel\Socialite\Two\AbstractProvider;
use Laravel\Socialite\Two\ProviderInterface;
use Laravel\Socialite\Two\User;
class LinkedInProvider extends AbstractProvider implements ProviderInterface
{
/**
* The scopes being requested.
*
* #var array
*/
protected $scopes = ['r_basicprofile', 'r_emailaddress'];
/**
* The separating character for the requested scopes.
*
* #var string
*/
protected $scopeSeparator = ' ';
/**
* The fields that are included in the profile.
*
* #var array
*/
protected $fields = [
'id', 'first-name', 'last-name', 'formatted-name',
'email-address', 'headline', 'location', 'industry', 'positions',
'public-profile-url', 'picture-url', 'picture-urls::(original)',
];
/**
* {#inheritdoc}
*/
protected function getAuthUrl($state)
{
return $this->buildAuthUrlFromBase('https://www.linkedin.com/oauth/v2/authorization', $state);
}
/**
* {#inheritdoc}
*/
protected function getTokenUrl()
{
return 'https://www.linkedin.com/oauth/v2/accessToken';
}
/**
* Get the POST fields for the token request.
*
* #param string $code
* #return array
*/
protected function getTokenFields($code)
{
return parent::getTokenFields($code) + ['grant_type' => 'authorization_code'];
}
/**
* {#inheritdoc}
*/
protected function getUserByToken($token)
{
$fields = implode(',', $this->fields);
$url = 'https://api.linkedin.com/v1/people/~:('.$fields.')';
$response = $this->getHttpClient()->get($url, [
'headers' => [
'x-li-format' => 'json',
'Authorization' => 'Bearer '.$token,
],
]);
return json_decode($response->getBody(), true);
}
/**
* {#inheritdoc}
*/
protected function mapUserToObject(array $user)
{
return (new User)->setRaw($user)->map([
'id' => $user['id'], 'nickname' => null, 'name' => Arr::get($user, 'formattedName'),
'email' => Arr::get($user, 'emailAddress'), 'avatar' => Arr::get($user, 'pictureUrl'),
'avatar_original' => Arr::get($user, 'pictureUrls.values.0'),
]);
}
/**
* Set the user fields to request from LinkedIn.
*
* #param array $fields
* #return $this
*/
public function fields(array $fields)
{
$this->fields = $fields;
return $this;
}
}
But now, I've got this error :
Type error: Argument 1 passed to Laravel\Socialite\Two\AbstractProvider::__construct() must be an instance of Illuminate\Http\Request, instance of Illuminate\Foundation\Application given, called in G:\laragon\www\localhost\vendor\laravel\framework\src\Illuminate\Foundation\ProviderRepository.php on line 201
I know I can install Socialite Manager, but I just want to overwrite the fields list to add new field (like position and industry)
You shouldn't have to overwrite/extend the whole class. In the Laravel\Socialite\Two\User object that is being created, there is a $user property, which contains the raw information the provider sent back.
When making the request, you can set the fields you want LinkedIn to return in your controller method:
public function redirectToProvider()
{
$fields = [
'id', 'first-name', 'last-name', 'formatted-name',
'email-address', 'headline', 'location', 'industry',
'public-profile-url', 'picture-url', 'picture-urls:(original)',
'positions', 'summary' // <-- additional fields here
];
return Socialite::driver('linkedin')->fields($fields)->redirect();
}
You can see two additional fields being requested, positions and summary, which aren't included by default.
Happy hacking!

Unable to overwrite authorized method in policy

I want to respond with a custom message when authorization fails.
I've overwritten the method in the Policy class but it does not return the custom message.
Policy:
class PostPolicy
{
use HandlesAuthorization;
/**
* Determine if user can view post
* #param User $user
* #param Post $post
* #return bool
*/
public function view(User $user, Post $post)
{
return $user
->posts()
->where('post_id', $post->id)
->exists();
}
/**
* [deny description]
* #return [type] [description]
*/
protected function deny()
{
return response()->json([
'message' => 'My custom unauthorized message'
], 401);
}
}
Implementing in PostController:
...
public function show(Post $post)
{
$this->authorize('view', $post);
...
}
The response still returns whats defined in the HandlesAuthorization trait, i.e.:
protected function deny($message = 'This action is unauthorized.')
{
throw new AuthorizationException($message);
}
You can simply add this code inside the AuthorizationException.php
/**
* Render the exception into an HTTP response.
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function render(Request $request)
{
if ($request->is('api/*')) {
$response = [
'message' => $this->message,
'status' => 403,
];
return response()->json($response, 403);
}
}

Resources