I'm trying to send a notification with a mention of a user in a general channel. This is what I have:
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\SlackMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
class WeeklyTasksResponsible extends Notification
{
use Queueable;
protected $employee;
/**
* Create a new notification instance.
*
* #return void
*/
public function __construct(\App\Employee $employee)
{
$this->employee = $employee;
}
/**
* Get the notification's delivery channels.
*
* #param mixed $notifiable
* #return array
*/
public function via($notifiable)
{
return ['slack'];
}
/**
* Get the Slack representation of the notification.
*
* #param mixed $notifiable
* #return SlackMessage
*/
public function toSlack($notifiable)
{
return (new SlackMessage)
->content('Reponsible for this week is: ' . $this->employee->slack_name);
}
}
This will sent a weekly notification in the general slack channel of our company. The message is "Responsible for this week is: nameofuser". The problem is the user doesn't see a notification of this.
I've also tried do this:
public function toSlack($notifiable)
{
return (new SlackMessage)
->content('Reponsible for this week is: #' . $this->employee->slack_name);
}
But it isn't the same as mentioning someone myself in the channel.
How can I do this?
As mentioned by #HCK you can enable matching of usernames for #username mentions in chat.postMessages by setting the optional parameter link_names to true.
However, creating mentions with usernames is deprecated and should no longer be used.
The recommended approach is to create mentions with the user ID, which will work by default.
Example:
<#U12345678>
See the post A lingering farewell to the username from Slack for details about username deprecation.
I just found the following in the Laravel 6.18.0 source code:
/**
* Find and link channel names and usernames.
*
* #return $this
*/
public function linkNames()
{
$this->linkNames = 1;
return $this;
}
vendor/laravel/slack-notification-channel/src/Messages/SlackMessage.php
So you can use it like this:
public function toSlack($notifiable)
{
return (new SlackMessage)
->linkNames()
...
}
As #erik-kalkoken pointed out, use the Slack user ID, enclosed by <> and with the # sign. You can find it in your profile in the Slack App:
Actually, I tried that way and it's works pretty well.
$content .= "New order!\r\n #person";
return (new SlackMessage)
->content($content)->linkNames();
You would need to add the # before name of person or team and in order for slack to recognize them as mentions not just text, you would need to chain the content with linkNames
Related
So I am setting up a exception handler that send a Slack notification every time an exception happens in the application, I have also setup this when a Complaint(Model) is created and that work fine. But in my Exception/Handle.php I have this setup.
Notification::route('slack', env('LOG_SLACK_WEBHOOK_URL'))->notify(new ExceptionCreated($exception));
The webhook does exist and it does work. And while dd() every possible step I know that it hits the ExceptionCreated in Notifications. So there I have this code.
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Notification;
use Illuminate\Notifications\Messages\SlackMessage;
use Carbon\Carbon;
use Throwable;
use Auth;
use Illuminate\Support\Facades\Request;
class ExceptionCreated extends Notification
{
use Queueable;
/**
* #var Throwable
*/
public $exception;
/**
* Create a new notification instance.
*
* #param \Throwable $exception
* #return void
*/
public function __construct(Throwable $exception)
{
$this->exception = $exception;
}
/**
* Get the notification's delivery channels.
*
* #param mixed $notifiable
* #return array
*/
public function via($notifiable)
{
return ['slack'];
}
/**
* Get the slack representation of the notification.
*
* #param mixed $notifiable
* #return \Illuminate\Notifications\Messages\SlackMessage
*/
public function toSlack($notifiable)
{
dd($this->exception);
//and a lot of code here but that doesn't matter
}
Now when I dump inside the constructor I can see the exception is being passed correctly, but it never fires the toSlack function and I have no idea why, I have cleared cache, dump autoload and nothing seems to be working, as I said I have this exact code for my Complaints and that works fine. So any suggestions are much appreciated.
I have a weird issue in my website. I have several Notifications such as Email Verification and Password Reset that are sending properly. However, I made my own notification that sends an url with a UUID to the user and unfortunately, it doesn't send.
I tried every way: 'Notification::route', notify the user directly, nothing works. Actually, notifying the user directly would be bad since I need to send it to an email address not attached to any model.
Anyway, here's the code for the notification. Keep in mind the other notifications work, so I doubt it is the issue.
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
class NewEmail extends Notification
{
use Queueable;
/**
* Create a new notification instance.
*
* #return void
*/
public function __construct($uuid)
{
$this->uuid = $uuid;
}
/**
* 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(__('messages.newEmailAsked'))
->action(__('messages.newEmailConfirm'), config('app.frontend_url') . '/verify-new-email?code=' . $this->uuid)
->line(__('messages.newEmailIgnore'));
}
/**
* Get the array representation of the notification.
*
* #param mixed $notifiable
* #return array
*/
public function toArray($notifiable)
{
return [
//
];
}
}
public function addNewEmail($email) {
if(User::where('email', $email)->count() === 0) {
$uuid = Str::uuid();
NewEmail::create(['email' => $email, 'unique_code' => $uuid, 'user_id' => $this->id]);
Notification::route('mail', $email)->notify(new \App\Notifications\NewEmail($uuid));
} else {
return 'Email already exists.';
}
}
I really don't get why this notification isn't sent while the other are...
Weirdly enough, the problem fixed itself when I did the actual path the user would take instead of using Tinker.
Just had to $user->addNewEmail($newEmailHere) and it worked properly...
You have not defined the $uuid variable in your Queueable class
I'm working on a laravel backpack project. I have created an Event CRUD and each event has its own admin and SMTP details. Admin can sent invites to users for that event. I have already set sendgrid SMTP in my '.env' file and created a notification to send invites. Its working fine and sends invites notification to the users for that particular event through sendgrid SMTP. But I want notification to be sent out with that particualr event's SMTP.
I have searched a lot but couldn't find a feasible solution for that. Would really appreciate if anyone can point me into right direction.
Below is my Invites Notification class code:
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
class EventUserInvitation extends Notification
{
// use Queueable;
/**
* Create a new notification instance.
*
* #return void
*/
public function __construct($event_user)
{
$this->event_user = $event_user;
}
/**
* 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)
->subject('You are invited to ' .$this->event_user->get_event->name. ' at SpaceTo app')
->line('You have received this email to join the meeting created by ' . (($this->event_user->get_event->user) ? $this->event_user->get_event->user->name : $this->event_user->get_event->event_admin[0]->name) . '. Please click on the link below to proceed. ')
->line('If your browser doesn’t support automatic redirection please copy and paste the link to your browser address field.')
->action('Open SpaceTo App', url('/') . '/app')
->line('This email is an automated email please do not reply. ')
->line('In case if you have any questions please contact our support team support#spaceto.com')
->line('Have a great day.')
->line('Spaceto team. ');
}
/**
* Get the array representation of the notification.
*
* #param mixed $notifiable
* #return array
*/
public function toArray($notifiable)
{
return [
//
];
}
}
I'm building an API with Laravel and want to send push notification using the Laravel Notifications system. I've a model for matches (which is basically a post), another user can like this match. When the match is liked, the creator of the post will get a push notification. It's just like Instagram, Facebook, etc.
Often the push notification wasn't send to the user. I installed Laravel Horizon to see if there where errors. Sometimes the notification was send and sometimes it wasn't. With the exact same data:
The notification fails sometimes with the exact same data (same user, same match).
The error is as followed:
Illuminate\Database\Eloquent\ModelNotFoundException: No query results
for model [App\Models\Match] 118 in
/home/forge/owowgolf.com/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php:312
I'm sure the match and the user exists in the database, I've verified that before sending the notification. Does anybody know what's going wrong? Everything I could find online is that people didn't save their model before sending the notification into the queue. But the line where the code send's the notification into the queue wouldn't even be reached if the model didn't exists. Because of Implicit Binding in the route/controller.
Controller method:
/**
* Like a match.
*
* #param \App\Models\Match $match
* #return \Illuminate\Http\JsonResponse
*/
public function show(Match $match)
{
$match->like();
$players = $match->players()->where('user_id', '!=', currentUser()->id)->get();
foreach ($players as $user) {
$user->notify(new NewLikeOnPost($match, currentUser()));
}
return ok();
}
Notification:
<?php
namespace App\Notifications;
use App\Models\Match;
use App\Models\User;
use Illuminate\Bus\Queueable;
use NotificationChannels\Apn\ApnChannel;
use NotificationChannels\Apn\ApnMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
class NewLikeOnPost extends Notification implements ShouldQueue
{
use Queueable;
/**
* The match instance.
*
* #var \App\Models\Match
*/
private $match;
/**
* The user instance.
*
* #var \App\Models\User
*/
private $user;
/**
* Create a new notification instance.
*
* #param \App\Models\Match $match
* #param \App\Models\User $user
*/
public function __construct(Match $match, User $user)
{
$this->user = $user;
$this->match = $match;
$this->onQueue('high');
}
/**
* Get the notification's delivery channels.
*
* #param \App\Models\User $notifiable
* #return array
*/
public function via($notifiable)
{
if ($notifiable->wantsPushNotification($this)) {
return ['database', ApnChannel::class];
}
return ['database'];
}
/**
* Get the mail representation of the notification.
*
* #param \App\Models\User $notifiable
* #return \NotificationChannels\Apn\ApnMessage
*/
public function toApn($notifiable)
{
return ApnMessage::create()
->badge($notifiable->unreadNotifications()->count())
->sound('success')
->body($this->user->username . ' flagged your match.');
}
/**
* Get the array representation of the notification.
*
* #param mixed $notifiable
* #return array
*/
public function toArray($notifiable)
{
return [
'user_id' => $this->user->id,
'body' => "<flag>Flagged</flag> your match.",
'link' => route('matches.show', $this->match),
'match_id' => $this->match->id,
];
}
/**
* Get the match attribute.
*
* #return \App\Models\Match
*/
public function getMatch()
{
return $this->match;
}
}
This is not a complete solution, but it will lower your chances of running into this error in the future.
Instead of passing in the whole Match model into the job, only pass the id of the model. You can then fetch that model in the constructor.
/**
* Like a match.
*
* #param \App\Models\Match $match
* #return \Illuminate\Http\JsonResponse
*/
public function show(Match $match)
{
$match->like();
$players = $match->players()->where('user_id', '!=', currentUser()->id)->get();
foreach ($players as $user) {
$user->notify(new NewLikeOnPost($match->id, currentUser()->id));
}
return ok();
}
Notification:
class NewLikeOnPost extends Notification implements ShouldQueue
{
use Queueable;
private const QUEUE_NAME = 'high';
/**
* The match instance.
*
* #var \App\Models\Match
*/
private $match;
/**
* The user instance.
*
* #var \App\Models\User
*/
private $user;
/**
* Create a new notification instance.
*
* #param int $match
* #param int $user
*/
public function __construct(int $matchId, int $userId)
{
$this->user = User::query()->where('id', $userId)->firstOrFail();
$this->match = Match::query()->where('id', $matchId)->firstOrFail();
$this->onQueue(self::QUEUE_NAME);
}
// Rest of the class is still the same...
}
You can use the SerializesModels trait, but it doesn't work well when you add a delay to a queued job. This is because it will try to reload the model on __wakeup() and sometimes it cannot find the class.
Hopefully this helps :)
Its probably because $user is not an object of User model, its an object of Match model. You need to do a User::findorfail or User::firstOrFail then notify the user.
public function show(Match $match)
{
$match->like();
$players = $match->players()->where('user_id', '!=', currentUser()->id)->get();
foreach ($players as $user) {
$someUser = User::findOrFail($user->user_id);
$someUser->notify(new NewLikeOnPost($match, currentUser()));
}
return ok();
}
Unless the notify trait is used in Match model. Or you could use eager loading which will cost way less queries!
Check your .env to be sure that u really use REDIS
BROADCAST_DRIVER=redis
CACHE_DRIVER=redis
SESSION_DRIVER=redis
SESSION_LIFETIME=120
QUEUE_DRIVER=redis
then clear cache ( php artisan cache:clear , php artisan view:clear ), that should clear the issue
EDIT
I had similar problems but now I use Docker only and before I had to check for cached configfiles, wrong file/folderpermissions and so on (REDIS for broadcast only, others were standard). I started using redis only - that`s a lot easier, faster and more debugfriendly for me ! And together with Docker really helpful to not use messed up nginx/apache/php/redis/ ...
I am trying to use the laravel-notifications-channel/onesignal and I am having some problems with users in my laravel app set up to receive notifications. The documentation on the github page does not really cover how a user authenticates them self to receive a notification.
Even reading over the OneSignal docs for sending users to OneSignal is not working for me.
How do I set it up where when a user is using our web app they are notified to receive notifications and then I can send notifications to them using laravel notifications?
Here is my AssignedToTask Notification file:
<?php
namespace App\Notifications;
use App\Task;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use NotificationChannels\OneSignal\OneSignalChannel;
use NotificationChannels\OneSignal\OneSignalMessage;
use NotificationChannels\OneSignal\OneSignalWebButton;
class AssignedToTask extends Notification
{
use Queueable;
protected $task;
/**
* Create a new notification instance.
*
* #return void
*/
public function __construct(Task $task)
{
//
$this->task = $task;
}
/**
* Get the notification's delivery channels.
*
* #param mixed $notifiable
* #return array
*/
public function via($notifiable)
{
return ['mail', OneSignalChannel::class];
}
public function toOneSignal($notifiable)
{
return OneSignalMessage::create()
->subject("Your {$notifiable->service} account was approved!")
->body("Click here to see details.")
->url('http://onesignal.com')
->webButton(
OneSignalWebButton::create('link-1')
->text('Click here')
->icon('https://upload.wikimedia.org/wikipedia/commons/4/4f/Laravel_logo.png')
->url('http://laravel.com')
);
}
/**
* Get the mail representation of the notification.
*
* #param mixed $notifiable
* #return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage)
->subject('You have been assigned a new task')
->line('You have a new task: ' . $this->task->title)
->action('View Task', url('tasks/' . $this->task->id));
}
/**
* Get the array representation of the notification.
*
* #param mixed $notifiable
* #return array
*/
public function toArray($notifiable)
{
return [
//
];
}
}
In my user model:
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Zizaco\Entrust\Traits\EntrustUserTrait;
use HipsterJazzbo\Landlord\BelongsToTenants;
use Cmgmyr\Messenger\Traits\Messagable;
class User extends Authenticatable
{
use Notifiable;
use EntrustUserTrait;
use BelongsToTenants;
use Messagable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'email', 'password', 'company_id'
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token', 'company_id'
];
....
public function routeNotificationForOneSignal()
{
return 'ONE_SIGNAL_PLAYER_ID';
}
public function routeNotificationForMail()
{
return $this->email_address;
}
}
How do I set and get the ONE_SIGNAL_PLAYER_ID in user model so a user accepts notifications and I can send them notifications?
EDIT - 2
Since you don't know what's happening is, Let me try to explain how you can work with OneSignal.
This is a push messaging system just like any other push notification system. (FCM (google), PubNub).
How it Works
First goto OneSignal.Com Create your account, and then create an app for you. Once you create an app it will give you SDK for Mobile, where your consumers are.
Now whenever your consumers install and start your app, they will notify your web server with their own unique id and user information.
The information you received about the user is unique player_id which you will store in your database against that user.
Now when you want to send a notification to any mobile app just call the API Post Notification method with player_id and OneSignal will send a push notification to that mobile app.
EDIT - 1
I think now i understand your confusion about Notifications with OneSignalChannel
Flow
You already have the players_ids stored in your app database against every user.
Now when you want to push a notification to a player, you just take that users player_id from db and push a notification to OneSignal.
Well you took this meaning literally. Which was causing issue
public function routeNotificationForOneSignal()
{
return 'ONE_SIGNAL_PLAYER_ID';
}
From the error message this function should have return a unique id (UUID).
Change the return value to actual player id at OneSignalChannel
That's all my friend.