Laravel eloquent sort by latest unique entry - php

I'm currently creating a basic inbox for a private messaging system which only displays the users which the logged in user has been in contact with if messages between the user and recipient exist. (Similar to how your standard instant messenger works)
The way I am getting this list is to check the messages table to see if any messages between the two users exist. If it does then list this in the inbox but since there will be many messages between the user, I am using a Laravel collection and the unique function to only display a recipient once. The user then can click on this recipient to see the message thread.
The issue I am having with is being able to sort this list by the latest message (e.g. sort by created_at)
How am I able to order this in order of the latest entry so that the most recent messages display at the top of the list in the inbox. Here is the code I using in my controller to get the list of recipients and attempt to sort by latest message:
$messages = collect(Message::where('recipient_id', $user)->orderBy('created_at', 'desc')->get());
$messagesUnique = $messages->sortBy('created_at')->unique('sender_id');
$messagesUnique->values()->all();
Thanks

Define your relationships:
class Message extends Model
{
public function sender()
{
return $this->belongsTo(User::class, 'sender_id');
}
public function recipient()
{
return $this->belongsTo(User::class, 'recipient_id');
}
}
In the User model:
class User extends Authenticable
{
public function received()
{
return $this->hasMany(Message::class, 'recipient_id')->latest();
}
public function sent()
{
return $this->hasMany(Message::class, 'sender_id')->latest();
}
}
Then for retrieving the messages:
$user = Auth::user();
$messages = $user->received->unique('sender_id');
$sent = $user->sent->unique('recipient_id');

Related

Laravel - Error Call to undefined method App\Models\Roles::intersect()

I want to link a record of type Person to Customer, because I want to create a customer using the same record of type person, keeping both records the same but with different profiles, but I find the following problem in my code:
Error
Call to undefined method App\Models\Roles::intersect()
store() method in CustomerController.php
public function store(CustomerRequest $customerRequest)
{
$role = Roles::where('name', 'Customer')->first();
$customer = User::where('cpf', $customerRequest->cpf)->first();
if ($customer->hasRole($role)) {
return back()->with('msg_erro', "This user is already a customer profile.");
} else {
$customer->syncRoles([$role->id]);
}
}
How can I fix this problem?

Laravel User Policy Is Returning The Authenticated User's Information And Not The External User

I created a Laravel policy called "UserPolicy" which is supposed to filter out users that do not have the permission to edit, delete, and update other users. The problem is that I am trying to pass an external user's information to the policy. But instead, it just returns the authenticated users information.
My Policy:
public function edit(?User $user)
{
if(auth()->check()) {
dd($user);
$userpower = auth()->user()->roles()->min('power');
if($userpower <= $user->power) {
return true;
} else {
return false;
}
} else {
return false;
}
}
My Controller:
public function edit(User $user)
{
$this->authorize('edit', $user);
$roles = Role::all();
$user = User::where('steamid', $user->steamid)->with('roles')->first();
return view('manage.includes.users.edit')->with(compact('user', 'roles'));
}
For example, I am the user Bob. I am trying to edit the user, John. As a test, I included the dd() function to dump the $user information that is passing into the Policy. After seeing the results, instead of John's information being passed, it is Bob's. How can I make it where it is John's information and not Bob's.
Thank you for your help, if you need more information please let me know.
The first parameter is the authenticated user. The second parameter is the resource. Try defining your policy as:
/**
* Can a guest user, or an authenticated user (let's call this first user Bob)
* edit another user (let's call that second user John) ?
*/
public function edit(?User $bob, User $john)
{
//
}

MethodNotAllowedHttpException generated using return back()->withInput() in Laravel 5.4

I've searched the forums and have seen many similar issues but none that seem to address my concern. I believe this is different because:
Form validation is not being used at this point
The form method does not seem to be related (just 1 post action)
The routes are not wrapped in web middleware
Here's what the application is supposed to be doing:
A user (with or without Authentication) views a public page with form (display_event)
The user selects a specific ticket for ordering and is directed to a 2nd form (register_step1)
The user then fills out demographic info for as many tickets as are being ordered
The processing step, if the email address used is of a valid user (in DB) should return to the form in step 2 & 3, populate the fields and flash a message. Otherwise it would perform the save() actions required. (register_step2)
The relevant routes from web.php are here:
Route::get('/events/{event}', 'EventController#show')->name('display_event');
Route::post('/register/{event}', 'RegistrationController#showRegForm')->name('register_step1');
Route::post('/register/{event}/create', 'RegistrationController#store')->name('register_step2');
The relevant portions of the RegistrationController.php are here:
public function showRegForm (Request $request, $id) {
// Registering for an event from /event/{id}
$ticket = Ticket::find(request()->input('ticketID'));
$quantity = request()->input('quantity');
$discount_code = request()->input('discount_code');
$event = Event::find($ticket->eventID);
return view('v1.public_pages.register', compact('ticket', 'event', 'quantity', 'discount_code'));
}
And:
public function store (Request $request) {
$event = Event::find(request()->input('eventID'));
if(Auth::check()) {
$this->currentPerson = Person::find(auth()->user()->id);
}
// set up a bunch of easy-reference variables from request()->input()
$email = Email::where('emailADDR', $checkEmail)->first();
if(!Auth::check() && $email === null) {
// Not logged in and email is not in database; must create
$person = new Person;
// add person demographics from form
} elseif(!Auth::check() && $email !== null) {
// Not logged in and email is in the database;
// Should force a login -- return to form with input saved.
flash("You have an account that we've created for you.
Please attempt to login and we'll send you a password to your email address.", 'warning');
return back()->withInput();
} elseif(Auth::check() && ($email->personID == $this->currentPerson->personID)) {
// the email entered belongs to the person logged in; ergo in DB
$person = $this->currentPerson;
// add person demographics from form
} elseif(Auth::check() && ($email->personID != $this->currentPerson->personID)) {
// someone logged in is registering for someone else in the DB
$person = Person::find($email->personID);
// add person demographics from form
} else {
// someone logged in is registering for someone else NOT in the DB
$person = new Person;
// add person demographics from form
}
// do more stuff...
$reg = new Registration; (set up a registration record)
}
I took the advice indicated in #apokryfos's comment and changed the form parsing-then-display script from a POST to a get.
redirect()->back() is, apparently, always a method=get and that was the cause of the MethodNotAllowedHttpException. In my ~2 weeks using Laravel, I hadn't yet come across that fact.

Laravel 5 forgotten password email template condition

I am using the Laravel 5 built in user stuff with Entrust for user roles and permissions. I have two roles set up which are administrators and users. Basically what I want to do is have two different forgotten password email templates - one for users and one for administrators. So when a user enters their email address to get the reset link emailed to them I need to check what sort of user they are first and then send them the right template. I don't want to have to do any sort of hacky stuff in the standard email template their must be a way to do this in the controller or something surely? Anyone know how I would do it?
You can probably prompt them to enter their email and when they submit you can grab it in the controller:
public function forgot()
{
$email = Input::get('email');
$user = User::where('email', $email)->first();
if($user->type == 'admin') {
// logic to email admin with admin template
} else {
// logic to email user with user template
}
// redirect to success page letting user know the email was sent
return View::make('someview');
}
Or better yet, just pass the user type to an email service that handles the emailing:
public function forgot()
{
$email = Input::get('email');
$user = User::where('email', $email)->first();
$emailService->sendForgotForType($user->type);
// redirect to success page letting user know the email was sent
return View::make('someview');
}
If you are using Laravel 5's built in User Management:
To override the default template used you would need to manually set the $emailView in the PasswordBroker.php by writing a new class that extends PasswordBroker.
For example, comment out 'Illuminate\Auth\Passwords\PasswordResetServiceProvider' in config/app.php
Then create an extension class:
use Illuminate\Contracts\Auth\PasswordBroker;
use Illuminate\Contracts\Auth\CanResetPassword;
class MyPasswordBroker extends PasswordBroker {
// override
public function emailResetLink(CanResetPasswordContract $user, $token, Closure $callback = null)
{
// Override Logic to email reset link function perhaps using the example above?
}
}
Then you would need to bind your new MyPasswordBroker class to AppServiceProvider at app/Providers/AppServiceProvider.php in the register method (below found online):
$this->app->bind('App\Model\PasswordBroker', function($app) {
$key = $app['config']['app.key'];
$userToken = new \App\Model\NewUserToken;
$tokens = new \App\Repository\NewTokenRepository($key,$userToken);
$user = new \App\Model\NewUser;
$view = $app['config']['auth.password.email'];
return new \App\Model\PasswordBroker($tokens, $users, $app['mailer'], $view);
});
Definitely moderately advanced stuff, if you can handle it - great. Otherwise I would possibly look into using an authentication package with built in features you need.

Best way for account activation

I'm trying to create an account register page with CakePHP 2.0 where user needs to activate it's new account by clicking on a link in the email he's received after insert username, email and password.
My question is how can I set an activation code inside the user record.
I thought to create a table field named activation_code and then to store an hashed version of the username to be sure the user can activate itself by clicking the email link with the activation key.
All the procedure is done but I don't know how can I set the activation_code inside the $data['User'] object and It's not clear for me if this is a good usage of the MVC framework or I should make it in a different way.
During the user registration action I've done this but I get an error when I try to create 'activation_code' dynamically:
// from the UserController class
public function register () {
if (!empty($this->data)) {
if ($this->data['User']['password'] == $this->data['User']['confirm_password']) {
// here is where I get the error
$this->data['User']['activation_key'] = AuthComponent::password($this->data['User']['email']);
$this->User->create();
if ($this->User->save($this->data)) {
// private method
$this->registrationEmail ($this->data['User']['email'], $this->data['User']['username']);
$this->redirect(array('controller'=>'users', 'action'=>'registration', 'success'));
}
}
}
}
Obviously the activation_key is an empty field inside my database.
So how can I create a filed dynamically from the controller?
$this->data['User']['activation_key']
should be:
$this->request->data['User']['activation_key']
(You should change all references to $this->data to the new cakephp2.0 $this->request->data)
I've solved the problem with the method Model::set(), so:
public function register () {
if (!empty($this->data)) {
if ($this->data['User']['password'] == $this->data['User']['confirm_password']) {
$this->User->create();
// I've used set method
$this->User->set('activation_key', AuthComponent::password($this->data['User']['email']));
if ($this->User->save($this->data)) {
$this->registrationEmail ($this->data['User']['email'], $this->data['User']['username']);
$this->redirect(array('controller'=>'users', 'action'=>'registration', 'success'));
}
}
}
}

Categories