I have Super-Admin and Admin roles. In Admin view I've added button to request verification email. The problem I'm having is that when Admin clicks the button to receive verification email, the email is from Admin, not Super-Admin.
How to make this to be sent to Admin from Super-Admin, instead of from Admin?
Route:
Route::post('/dashboard/SendEmailVerification', 'AdminDashboardController#SendEmailVerification')->name('dashboard.SendEmailVerification');
In AdminDashboardController:
use App\Notifications\EmailVerification;
use App\User;
.............
public function SendEmailVerification(Request $request){
$user = User::where('email_verification_code', $request->code)
->withoutGlobalScope('active')
->first();
$user->notify(new EmailVerification($user));
return Reply::success('Email sent!');
}
And the notification email:
namespace App\Notifications;
use App\Traits\SmtpSettings;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use App\User;
class EmailVerification extends Notification implements ShouldQueue
{
use Queueable, SmtpSettings;
protected $user;
/**
* Create a new notification instance.
*
* #return void
*/
public function __construct(User $user)
{
$this->user = $user;
$this->setMailConfigs();
}
/**
* Get the notification's delivery channels.
*t('mail::layout')
* #param mixed $notifiable
* #return array
*/
public function via($notifiable)
{
$via = ['mail'];
return $via;
}
/**
* Get the mail representation of the notification.
*
* #param mixed $notifiable
* #return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage)
->subject('Confirm your email')
->greeting(__('Hello!'))
->line(__('email.emailVerify.text'))
->action('Confirm', getDomainSpecificUrl(route('front.get-email-verification', $this->user->email_verification_code), $this->user->company));
#->line(__('email.thankyouNote'));
}
/**
* Get the array representation of the notification.
*
* #param mixed $notifiable
* #return array
*/
public function toArray($notifiable)
{
return $notifiable->toArray();
}
}
You're getting wrong sender address because you never defined who's the sender in your Notification configuration. There are two ways to do this:
First: The first one is a really simple, but non-dynamic solution. In your .env configuration config, add these lines:
MAIL_FROM_NAME="My Name"
MAIL_FROM_ADDRESS=support#example.com
When you configure this, add this in yout config/mail.php configuration:
'from' => [
'address' => env('MAIL_FROM_ADDRESS', 'default value if not found in .env'),
'name' => env('MAIL_FROM_NAME', 'default value if not found in .env'),
],
Note: Don't forget to clear your cache, and restart queue when you do this:
Second: This is a more dynamic solution, since you can load the sender email address from your database. In your SendEmailVerification method, you can query up the super-admin user, and pass to the EmailVerification class:
public function SendEmailVerification(Request $request){
$user = User::where('email_verification_code', $request->code)
->withoutGlobalScope('active')
->first();
$superAdminUser = User::where('role', 'super-admin')->first();
$user->notify(new EmailVerification($user, $superAdminUser));
return Reply::success('Email sent!');
}
Then, change your EmailVerification class:
public $user;
public $superUser;
public function __construct(User $user, User $superUser)
{
$this->user = $user;
$this->superUser = $superUser;
$this->setMailConfigs();
}
And in your toMail() method, add another from() method:
public function toMail($notifiable)
{
return (new MailMessage)
->subject('Confirm your email')
->from($superAdminUser->email, $superAdminUser->first_name)
->greeting(__('Hello!'))
->line(__('email.emailVerify.text'))
->action('Confirm', getDomainSpecificUrl(route('front.get-email-verification', $this->user->email_verification_code), $this->user->company));
#->line(__('email.thankyouNote'));
}
Note: Also clear your cache and restart your queue.
Hope that this can resolve your issue. Let me know if you have any problems with these solutions.
You can read more about notifications on official documentation.
Related
I'm in the process of implementing fortify into my app. I'm really confused about customising the default emails that are produced when you hit the password-reset / verifty-email routes?
I could edit them in vendor but that going to cause me an issue every time I update.
There must be a hook to provide an alternative email template.
Unfortnatly I cant find any documentation that explains how its done.
Do I need to add:
public function sendEmailVerificationNotification()
{
}
To my user model? If so how to I generate the return verificaiton URL as its not being held in the database?
Any help would be great.
Thanks!
Here is the solution in Laravel 8.
1.) Create a Notification by command
php artisan make:notification ResetPasswordNotification
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Auth\Notifications\ResetPassword;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Lang;
class ResetPasswordNotification extends ResetPassword
{
use Queueable;
/**
* Create a new notification instance.
*
* #return void
*/
public $token;
public function __construct($token)
{
$this->token = $token;
}
/**
* Get the notification's delivery channels.
*
* #param mixed $notifiable
* #return array
*/
public function via($notifiable)
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*
* #param mixed $notifiable
* #return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
if (static::$toMailCallback) {
return call_user_func(static::$toMailCallback, $notifiable, $this->token);
}
$url = url(config('app.url') . route('password.reset', [
'token' => $this->token,
'email' => $notifiable->getEmailForPasswordReset(),
], false));
return (new MailMessage)
->view(
'emails.reset_password', ['name'=>$notifiable->name,'url' => $url]
)
->subject(Lang::get('Reset Password'));
}
/**
* Get the array representation of the notification.
*
* #param mixed $notifiable
* #return array
*/
public function toArray($notifiable)
{
return [
//
];
}
}
2.) In the app/Models/User.php Model. Add below method.
public function sendPasswordResetNotification($token)
{
$this->notify(new ResetPasswordNotification($token));
}
3.) Now create an email template in views/emails/reset_password.blade.php
Hi {{ $name }}, Please reset your password here. Click on the below link to reset the password.
RESET
You can customize the password reset email by adding the following in FortifyServiceProvider
ResetPassword::toMailUsing(function($user, string $token) {
return (new MailMessage)
->subject('Reset Password')
->view('emails.password_reset', [
'user' => $user,
'url' => sprintf('%s/users/password_reset/%s', config('app.url'), $token)
]);
});
Create a file named resources/views/emails/password_reset.blade.php, in this file you can use $user and $url
You can enter the directory when you use fortify vendor\laravel\framework\src\Illuminate\ Notifications\resources\views\email.blade.php and overwrite the content and style of the email.
Notifications are by default in the directory vendor\laravel\framework\src\Illuminate\Auth\Notifications\VerifyEmail.php
You can change the email text lines there. Similarly reset password in ResetPassword.php
I use database notifications, in notification code I have method toDatabase:
public function toDatabase($notifiable)
{
$user = \App\SomeUsers::where('id', $notifiable->id)->first();
return [
'message' => $message,
];
}
it returns data array which is being sent to database channel mentioned in via method of current notification:
public function via($notifiable)
{
return ['database'];
}
Everything is as usual, BUT... The problem is I need id of notification in database here in current notification file so that I could broadcast message (from current notification file) to frontend which contains id of notificaion in db (so I could somehow identify it to mark as read). How to get it?
P.S. Moreover, database notification may be queueable, so... it seems that I can't get id...
P.P.S Another words I need broadcast message which contains ["id" => "id of just added corresponding database notification"].
<?php
namespace App\Notifications;
use App\Channels\SocketChannel;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Redis;
class MyCustomNotification extends Notification implements ShouldQueue
{
use Queueable;
/**
* Create a new notification instance.
*
* #return void
*/
public function __construct($param)
{
$this->param = $param;
}
/**
* Get the notification's delivery channels.
*
* #param mixed $notifiable
* #return array
*/
public function via($notifiable)
{
$channels = ['database'];
return $channels;
}
/**
* Get the mail representation of the notification.
*
* #param mixed $notifiable
* #return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
}
/**
* Get the array representation of the notification.
*
* #param mixed $notifiable
* #return array
*/
public function toDatabase($notifiable)
{
info("This is the current notification ID, it's generated right here before inserting to database");
info($this->id);
return [
'id' => **$this->id**,
'message' => 'Notification message',
];
}
}
$this->id solves the problem.
https://laracasts.com/discuss/channels/laravel/get-database-notification-id-in-push-notification
P.S. I want to draw attention to one fact. When I posted this question, I knew about $this->id, but I couldn't make it work. The reason was: when I dive deeper to my target code from the top level I made changes to code, but they didn't apply. The reason is queues. You need to restart laravel worker to apply settings as Laravel caches logic or you need temporarily delete those: implements ShouldQueue and use Queueable.
In order to retrieve the actual ID of the notifications table in Laravel, you need to cast the ID column to string. First, you need to create a new model called, Notification.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Notification extends Model
{
/**
* Cast variables to specified data types
*
* #var array
*/
protected $casts = [
'data' => 'array',
'id' => 'string'
];
}
This way, if you retrieve the model, it will give you the actual ID of the table.
{
"id": "212829d6-5579-449f-a8e5-e86f0a08e0f9",
"type": "App\\Notifications\\CronFailureNotification",
....
}
The accepted answer did not provide a solution for me in Laravel 8. To properly get the id of the notification, listen for the NotificationSent event and retrieve the id there. Example code:
EventServiceProvider.php
protected $listen = [
NotificationSent::class => [
DispatchBroadcastNotification::class
]
];
DispatchBroadcastNotification.php
<?php
namespace App\Listeners;
use App\Notifications\BroadcastNotification;
use Illuminate\Notifications\Events\NotificationSent;
class DispatchBroadcastNotification
{
/**
* Create the event listener.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* #param NotificationSent $event
* #return void
*/
public function handle(NotificationSent $event)
{
$event->notifiable->notify(
new BroadcastNotification($event->notification->id)
);
}
}
BroadcastNotification.php
<?php
namespace App\Notifications;
use App\Models\Tenant\User;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Notifications\Messages\BroadcastMessage;
use Illuminate\Notifications\Notification;
class BroadcastNotification extends Notification implements ShouldBroadcast
{
public $notificationId;
public function __construct($notificationId)
{
$this->notificationId = $notificationId;
}
/**
* Get the notification's delivery channels.
*
* #param mixed $notifiable
* #return array
*/
public function via(User $notifiable): array
{
return ['broadcast'];
}
public function toBroadcast(User $notifiable)
{
return new BroadcastMessage([
'notificationId' => $this->notificationId
]);
}
}
I am trying to set up a contact form on my site whereby when someone clicks send, then a job is run and in that job, a notification is sent to all admin users. I keep getting this error in my failed jobs table though:
Illuminate\Database\Eloquent\ModelNotFoundException: No query results for model [App\Contact]. in /var/www/html/leonsegal/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php:412
I have been all over my code and I can't see what I have done wrong. Would anyone be able to help please?
Here is my controller:
<?php
namespace App\Http\Controllers;
use App\Contact;
use App\Jobs\SendContactJob;
class ContactController extends Controller
{
/**
* #return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function create()
{
return view('contact');
}
public function store()
{
request()->validate([
'name' => 'required|max:255',
'email' => 'required|email|unique:contacts|max:255',
'message' => 'required|max:2000',
]);
$contact = Contact::create(
request()->only([
'name',
'email',
'message',
])
);
SendContactJob::dispatch($contact);
return back()->with('success', 'Thank you, I will be in touch as soon as I can');
}
}
my job:
<?php
namespace App\Jobs;
use App\Contact;
use App\Notifications\SendContactNotification;
use App\User;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Support\Facades\Notification;
class SendContactJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $contact;
/**
* Create a new job instance.
*
* #param Contact $contact
*/
public function __construct(Contact $contact)
{
$this->contact = $contact;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
$users = User::all()
->where('admin', 1)
->where('approved', 1);
Notification::send($users, new SendContactNotification($this->contact));
}
}
my notification:
<?php
namespace App\Notifications;
use App\Contact;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
class SendContactNotification extends Notification implements ShouldQueue
{
use Queueable;
protected $contact;
/**
* Create a new notification instance.
*
* #param $contact
*/
public function __construct(Contact $contact)
{
$this->contact = $contact;
}
/**
* Get the notification's delivery channels.
*
* #param mixed $notifiable
* #return array
*/
public function via($notifiable)
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*
* #param mixed $notifiable
* #return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage)
->line($this->contact->name)
->line($this->contact->email)
->line($this->contact->message);
}
/**
* Get the array representation of the notification.
*
* #param mixed $notifiable
* #return array
*/
public function toArray($notifiable)
{
return [
//
];
}
}
The weird thing is that when I run a die dump in the handle method of the job, it never fires, but the artisan queue worker says it was processed correctly but the subsequent notification is where it is failing. I am not sure why that handle method in the job wouldn't be firing.
I have set my .env file to database queue driver.
I thought it might be that I didn't import the contact model, but you can see I have.
Any help would be appreciated.
Could be that because both the job and the notification are queued, the contact could be getting 'lost in transit' so to speak. try making the job non queueable, and only queue the notification (or the other way around). Or scrap the job altogether and just send the notification from the controller.
Did you check on your model path? Coz for newer laravel the path should be
use App\Models\Contact;
I am new in Laravel and I am trying to send Slack Notification each time an order is placed. For testing, I used my Incoming Webhook. Now when I am changing the webhook to clients slack webhook. Its still sending the notification to old webhook.
Can you help me sort this out?
This is my Listener
public function handle(OrderConfirmed $event)
{
$admin=User::find(73);
$user=User::find($event->order->user_id);
$order=Order::find($event->order->id);
Notification::send(User::find(73),(new \App\Notifications\PaymentProcessedNot($user,$order)));
}
This is my PaymentProcessedNot class
class PaymentProcessedNot extends Notification implements ShouldQueue
{
use Queueable;
public $user;
public $order;
/**
* Create a new notification instance.
*
* #return void
*/
public function __construct(\App\User $user,\App\Order $order)
{
$this->user=$user;
$this->order=$order;
}
/**
* Get the notification's delivery channels.
*
* #param mixed $notifiable
* #return array
*/
public function via($notifiable)
{
return ['slack'];
}
public function toSlack($notifiable){
return (new SlackMessage)
->success()
->content('A new Payment was just processed.')
->attachment(function ($attachment){
$attachment->title('Order : '. $this->order->order_id)
->fields([
'Amount' => ' ₹'. number_format($this->order->amount,2),
'From' => $this->user->name,
'Payment Mode' => strtoupper($this->order->payment_mode)
]);
});
}
}
This is my User.php
public function routeNotificationForSlack()
{
return 'new_slack_incoming_webhook';
}
If your using .env you should clear the cache!
Just checking this is actually the url right?
return 'new_slack_incoming_webhook';
I'm experimenting with laravel and I came across this article.
I followed it exactly but for some reason when sending the mail in the Notification class, he can't find the $user variable I declared in the constructor. When printing it in the constructor it works so the user object is passed correctly, but when I want to access it in the toMail method, it's inexisting for some reason. Anyone know why & how to fix this?
<?php
namespace App\Notifications;
use App\User;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
class UserRegisteredSuccessfully extends Notification
{
use Queueable;
/**
* #var User
*/
protected $user;
/**
* Create a new notification instance.
*
* #param User $user
*/
public function __construct(User $user)
{
$this->$user = $user;
// printing here works
}
/**
* Get the notification's delivery channels.
*
* #param mixed $notifiable
* #return array
*/
public function via($notifiable)
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*
* #param mixed $notifiable
* #return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
// ERROR HERE (Undefined variable: user)
$user = $this->$user;
return (new MailMessage)
->subject('Succesfully created new account')
->greeting(sprintf('Hello %s', $user->username))
->line('You have successfully registered to our system. Please activate your account.')
->action('Click here', route('activate.user', $user->activation_code))
->line('Thank you for using our application!');
}
/**
* Get the array representation of the notification.
*
* #param mixed $notifiable
* #return array
*/
public function toArray($notifiable)
{
return [
//
];
}
}
Register Method:
/**
* Register new user
*
* #param Request $request
* #return User
*/
protected function register(Request $request)
{
$validatedData = $request->validate([
'username' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:6|confirmed',
]);
try {
$validatedData['password'] = Hash::make(array_get($validatedData, 'password'));
$validatedData['activation_code'] = str_random(30).time();
$user = app(User::class)->create($validatedData);
} catch(\Exception $ex) {
logger()->error($ex);
return redirect()->back()->with('message', 'Unable to create new user.');
}
$user->notify(new UserRegisteredSuccessfully($user));
return redirect()->back()->with('message', 'Successfully created a new account. Please check your email and activate your account.');
}
Thanks in Advance!
You made 2 typos:
In your constructor:
$this->$user = $user;
Should be:
$this->user = $user;
And in the toMail() method:
$user = $this->$user;
Should be:
$user = $this->user;
The reason it is not working, is because you are currently using the value of $user as the variable name, and you are not assigning the value of the User object to $this->user.