ÿØÿà JFIF    ÿÛ „  ( %!1"%)+...383-7(-.+  -%%--------+------------/----------------------------ÿÀ  ¶" ÿÄ     ÿÄ @    !1AQaq‘¡"±ÁÑð2’BRráS‚ñ3b¢CT²Ò #cÿÄ    ÿÄ '   1!AQ2a"‘±#ÿÚ   ? ò(/p‘—–¢·,M|¯G»R£üešT. ôŸEoCFñ‡ 4ÔkåóxR|µÁ¨ÓDà!Ç´µ˜‡p ÍQ‹§!þž^õWsŒy  åÁ§$á«%ºq˜™JyyË0y«^Ϗ -3ÃÏËÈ£Æ\P’ä„s&•‹Üs üô'àWt¹pñCp$bÚF`·7.^)¾!)ÒÙ˜–ÅÏš^h¾ø³·ìe±ŒaeÖ—Í,e=B}Jéߦ$$½—šÙÜCC¯¶è8β–Åkèwx LÉngT±æ¹£Ócœ¿Í/©Éÿ ‰ÚCÒ­mq;Tt¶–}0"zÖPcd1š­¤tˆ„ÐÓâqú[™öUCŠ2޿د­É(¸ßúçšmW,Ò ºf‹Ån™ÄLêÁ8üÁkÁ€L¥ÍuJ1œôrÂSŒÓöt!7EUíïb)AËi¬â-ÙHk8òÁiXYwÅ)O^"ÇØriÛô{»wRUKÙÏÚlÓ¬€‚’שT ] ªb—ÊîKC^×M“xùäñz¬zJ× {4[¹M'IÆeH1LCWÕ]œûº WDæà°OÅ‚¹c²ÞuA–rL`HšpCez‡V’— Ž‚Ë„–ñ­'µR0ÕÖ=À:±G»C\nÆÉ5*¢ †3šhQ4ýÒi$Õ1"Ü]¢p-q3zcQ$ªö¨¥æf›‘»´ÝÚHá„e²JÇ–iÊ:·à¬Øc5Åk»Laª*wi [0Ówk ¦a¦0Õ²ÅÅ‚T¸’³q:Æ<¹ú Ò˜Æ}2VE•Ѐp¡Ô3Úº …h³^LJºçì¥Ánó|˜ÖˆÎˆ+« ¦dø‘Mº–d\ªDðÛ„Ì×LÝ——Ð9Ç|•FèçVm™¨€™3õS–9Äå¢<̉Ìm¢±`·º˜&Z²ž Ë®D«¶»6™‰©­HÈ Àá«h­i³04æ’hxœi3ï¨(ÓL·†‹¶ËpŒ ƒÜÒ? :õdsÀ –3æÓ·Üjâ¬9—]8n¼&]I F£¼…ì–—Œ0v°LǐÅfÛ2TÖ’aµ˜N@ÖBSÏ^à´4-±°b×nÈÈœÆD=KdŒø…ÄÈK,›ÖR§fjü$^ÔÎ!„6^ s:Üun\ôkCÞò÷<—Lúl Í›G¹ÀPá¼Nc¡šÒ…ÙWͳœ±vÊáЄ×9‹P‰cEØ‘™›µŸP<×g1 º©Ø¬wiÁ^l5× I/';Ë+´Z‡ÓÄFÕp[Èð’ HÄ ó 9¬Dl4“é±Ï”V=^Hð;žLädÉa‚°Ë,#/Ž~²BÔÛ QãñQtIeórVB,ÏÂf‹4#Μc‹É3ZIÖ Œ¢¥·üxa‡Ãçè„jŠ[5 Ä!U?,3žÎ×…ðdÓ÷háŠA‰ìÄ4÷ÃÜZÃE{‰®+W\ZÍE[‰»µk»MÝ­`¢©†˜ÃV‹-f¢¡†¢a«eŠ%«Y¨©q%jâd,Ôq`) ¤¦…šˆ ¦E>0Ùb²t–Ÿ  ÷jsςҒKÈcø(é›;k(’#ôŒQ ™C> õ³M9óºÆµ¤çâ;uÀ)5>RÔ¸fÓ~Ȧ—’-$fe«"FâUˆÊwµPÏu w+"åÉó¨6s™Û9(À¨ù©hE°½†n`m~“@©›p!Vkhµ Á1šbEqqÊ@ºèl›2 –Yã%‘‚hÛ{a¶‡ÅÞM²¬çL34®Çl]®‹ŽØŒm'RÜe35æöˆ­Á­ cP9šeÁköo´L³Ì=p8]”‡B¶,šº|ɏdzXˆØk*ÇÚ{#ñ‰pã(€¶‡9ý'šÜ³½¯kƒ†Â’ëSOƒ•Å®H6+a¢µˆ‹Y¨b˜b+XˆÖ!°u!¢"µˆˆn2ˆ Å0Ä`Å Ô®c(ÓÜGº•Ä»Œ âWî%q.áÐÄ÷î%umÍ£+ÜQ,Vn¦-GphU¸¢X­&,Gt ·K¢ÅÅ·¥RÄÊÉbKn N­R2g$VµÕó Qr#–ÓZUÏð0ÎtÙÀœz ëöo“Îk¯n„T°"SÞ+³/…€½"ižãO%Í%&Δâ‘ËØ´IˆÓ°Ë‰ÞM3.™yçÁzit›`4C`k¢¼á!álÄï sÂ[×!¤l¾æo"ƒIÔ'@ªu)3›ô®“@Z à¾] üœ'‡4¸PÞkÁ-qÄH‰ÓÍBd´ÿ —¹°ÄA&ÊUC„öz‚‚RæŠtf¬>˜ÑidšEçÑL÷áý¡V±h§­c¿¥¨ƒ@g¼…Ýö^ÞËc.ž„æ“I[ ª+·zÐÒÚ,½Ð»¶€C›7jk$๖€Ž¾ÅÙpp¶ÍþéΤ ½ØÎŒq ñpæžÅ¥#Øâ49ÃÂK^MYV“,¶Éz_òæ:…;Õ«¦I3âJ£¤û5$7Èxün\â]Êe¯(Ÿ&Ž‹¶2<6Ćf× æ¢ƱqWı[(ÙÂŽç‚T7¨@ÈÉÍß‚ïÙ"&3TYlGށ†)†#5ŠA©^T2ÆÁ†)©†©†¤yGXÁ†©"†)©¼ÅV WS†#©]R–r‹q5ÕbâWþBh¯u+ªÅÄ×ü„nÑ^êkªÁj‰jeœWˆÕÕ`µDµ2Ì+Ä µDµµ5Ô{¤Þ0RF’H÷AÛ<ÊÁ§ ƈæ0Ñ£ê4 öÚµ[¬/1²€â<-¬šö²r×0o×w ´xÐÒË„ g01¬„åEM蛇Ã\6µE›‘fÙO k÷CºnÓ1`iîÒ² áÂ!ÑLÄÿ ³¬\õ*:M=Ç»c‹2[‰ØsÕLò\ŒK L^™üÄN\¶#» Ç\……ßïIœÉ$¸ÎñÍ®ÔHÇ Ûí/´>Li”„†g^$ 7NÍÑÑ2M2ªNg=k½Ð}Ÿl6‡ —JWˆ”ÞéT·+µ¦üÂFè¢Vs6ýÆ4»2+2IÝ9ô9®ÇGÙÇ1+Ä8;*Õ§ž½D*îÑWÚçá3Ma¤·ˆ¥t}š²Ü…Q+Æüµ8HíS”üxGéÁˆ¦Ël„éÈ 5 µÄƒ6äÜ(kIš¯S†fÖ&¸®×v|Äyˆ*禌Éù@7-®Ä[]ÎÖ¿ê`º…=:…žJVnݳvðÖKE¼‚ »mà ÷f®:Ë ™–4rð¡4` ܹçž~‹C=œ…¾Ïj|VDtK.ƒ"9 Ï ­–éXá³6WÒïIL-Ї Ç Exception/NotificationsException.php000064400000000334152267305340013712 0ustar00files = $files; $this->composer = $composer; } /** * Execute the console command. * * @return void */ public function handle() { $fullPath = $this->createBaseMigration(); $this->files->put($fullPath, $this->files->get(__DIR__.'/stubs/notifications.stub')); $this->info('Migration created successfully!'); $this->composer->dumpAutoloads(); } /** * Create a base migration file for the notifications. * * @return string */ protected function createBaseMigration() { $name = 'create_notifications_table'; $path = $this->laravel->databasePath().'/migrations'; return $this->laravel['migration.creator']->create($name, $path); } } Console/stubs/notifications.stub000064400000001415152270627060013066 0ustar00uuid('id')->primary(); $table->string('type'); $table->morphs('notifiable'); $table->text('data'); $table->timestamp('read_at')->nullable(); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('notifications'); } } DatabaseNotification.php000064400000005440152270627060011342 0ustar00 'array', 'read_at' => 'datetime', ]; /** * Get the notifiable entity that the notification belongs to. * * @return \Illuminate\Database\Eloquent\Relations\MorphTo */ public function notifiable() { return $this->morphTo(); } /** * Mark the notification as read. * * @return void */ public function markAsRead() { if (is_null($this->read_at)) { $this->forceFill(['read_at' => $this->freshTimestamp()])->save(); } } /** * Mark the notification as unread. * * @return void */ public function markAsUnread() { if (! is_null($this->read_at)) { $this->forceFill(['read_at' => null])->save(); } } /** * Determine if a notification has been read. * * @return bool */ public function read() { return $this->read_at !== null; } /** * Determine if a notification has not been read. * * @return bool */ public function unread() { return $this->read_at === null; } /** * Scope a query to only include read notifications. * * @param \Illuminate\Database\Eloquent\Builder $query * @return \Illuminate\Database\Eloquent\Builder */ public function scopeRead(Builder $query) { return $query->whereNotNull('read_at'); } /** * Scope a query to only include unread notifications. * * @param \Illuminate\Database\Eloquent\Builder $query * @return \Illuminate\Database\Eloquent\Builder */ public function scopeUnread(Builder $query) { return $query->whereNull('read_at'); } /** * Create a new database notification collection instance. * * @param array $models * @return \Illuminate\Notifications\DatabaseNotificationCollection */ public function newCollection(array $models = []) { return new DatabaseNotificationCollection($models); } } AnonymousNotifiable.php000064400000003153152270627060011253 0ustar00routes[$channel] = $route; return $this; } /** * Send the given notification. * * @param mixed $notification * @return void */ public function notify($notification) { app(Dispatcher::class)->send($this, $notification); } /** * Send the given notification immediately. * * @param mixed $notification * @return void */ public function notifyNow($notification) { app(Dispatcher::class)->sendNow($this, $notification); } /** * Get the notification routing information for the given driver. * * @param string $driver * @return mixed */ public function routeNotificationFor($driver) { return $this->routes[$driver] ?? null; } /** * Get the value of the notifiable's primary key. * * @return mixed */ public function getKey() { // } } NotificationSender.php000064400000016465152270627060011067 0ustar00bus = $bus; $this->events = $events; $this->locale = $locale; $this->manager = $manager; } /** * Send the given notification to the given notifiable entities. * * @param \Illuminate\Support\Collection|array|mixed $notifiables * @param mixed $notification * @return void */ public function send($notifiables, $notification) { $notifiables = $this->formatNotifiables($notifiables); if ($notification instanceof ShouldQueue) { return $this->queueNotification($notifiables, $notification); } $this->sendNow($notifiables, $notification); } /** * Send the given notification immediately. * * @param \Illuminate\Support\Collection|array|mixed $notifiables * @param mixed $notification * @param array|null $channels * @return void */ public function sendNow($notifiables, $notification, array $channels = null) { $notifiables = $this->formatNotifiables($notifiables); $original = clone $notification; foreach ($notifiables as $notifiable) { if (empty($viaChannels = $channels ?: $notification->via($notifiable))) { continue; } $this->withLocale($this->preferredLocale($notifiable, $notification), function () use ($viaChannels, $notifiable, $original) { $notificationId = Str::uuid()->toString(); foreach ((array) $viaChannels as $channel) { if (! ($notifiable instanceof AnonymousNotifiable && $channel === 'database')) { $this->sendToNotifiable($notifiable, $notificationId, clone $original, $channel); } } }); } } /** * Get the notifiable's preferred locale for the notification. * * @param mixed $notifiable * @param mixed $notification * @return string|null */ protected function preferredLocale($notifiable, $notification) { return $notification->locale ?? $this->locale ?? value(function () use ($notifiable) { if ($notifiable instanceof HasLocalePreference) { return $notifiable->preferredLocale(); } }); } /** * Send the given notification to the given notifiable via a channel. * * @param mixed $notifiable * @param string $id * @param mixed $notification * @param string $channel * @return void */ protected function sendToNotifiable($notifiable, $id, $notification, $channel) { if (! $notification->id) { $notification->id = $id; } if (! $this->shouldSendNotification($notifiable, $notification, $channel)) { return; } $response = $this->manager->driver($channel)->send($notifiable, $notification); $this->events->dispatch( new NotificationSent($notifiable, $notification, $channel, $response) ); } /** * Determines if the notification can be sent. * * @param mixed $notifiable * @param mixed $notification * @param string $channel * @return bool */ protected function shouldSendNotification($notifiable, $notification, $channel) { if (method_exists($notification, 'shouldSend') && $notification->shouldSend($notifiable, $channel) === false) { return false; } return $this->events->until( new NotificationSending($notifiable, $notification, $channel) ) !== false; } /** * Queue the given notification instances. * * @param mixed $notifiables * @param \Illuminate\Notifications\Notification $notification * @return void */ protected function queueNotification($notifiables, $notification) { $notifiables = $this->formatNotifiables($notifiables); $original = clone $notification; foreach ($notifiables as $notifiable) { $notificationId = Str::uuid()->toString(); foreach ((array) $original->via($notifiable) as $channel) { $notification = clone $original; $notification->id = $notificationId; if (! is_null($this->locale)) { $notification->locale = $this->locale; } $queue = $notification->queue; if (method_exists($notification, 'viaQueues')) { $queue = $notification->viaQueues()[$channel] ?? null; } $this->bus->dispatch( (new SendQueuedNotifications($notifiable, $notification, [$channel])) ->onConnection($notification->connection) ->onQueue($queue) ->delay(is_array($notification->delay) ? ($notification->delay[$channel] ?? null) : $notification->delay ) ->through( array_merge( method_exists($notification, 'middleware') ? $notification->middleware() : [], $notification->middleware ?? [] ) ) ); } } } /** * Format the notifiables into a Collection / array if necessary. * * @param mixed $notifiables * @return \Illuminate\Database\Eloquent\Collection|array */ protected function formatNotifiables($notifiables) { if (! $notifiables instanceof Collection && ! is_array($notifiables)) { return $notifiables instanceof Model ? new ModelCollection([$notifiables]) : [$notifiables]; } return $notifiables; } } NotificationServiceProvider.php000064400000002213152270627060012744 0ustar00loadViewsFrom(__DIR__.'/resources/views', 'notifications'); if ($this->app->runningInConsole()) { $this->publishes([ __DIR__.'/resources/views' => $this->app->resourcePath('views/vendor/notifications'), ], 'laravel-notifications'); } } /** * Register the service provider. * * @return void */ public function register() { $this->app->singleton(ChannelManager::class, function ($app) { return new ChannelManager($app); }); $this->app->alias( ChannelManager::class, DispatcherContract::class ); $this->app->alias( ChannelManager::class, FactoryContract::class ); } } composer.json000064400000002300152270627060007270 0ustar00{ "name": "illuminate/notifications", "description": "The Illuminate Notifications package.", "license": "MIT", "homepage": "https://laravel.com", "support": { "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, "authors": [ { "name": "Taylor Otwell", "email": "taylor@laravel.com" } ], "require": { "php": "^7.3|^8.0", "illuminate/broadcasting": "^8.0", "illuminate/bus": "^8.0", "illuminate/collections": "^8.0", "illuminate/container": "^8.0", "illuminate/contracts": "^8.0", "illuminate/filesystem": "^8.0", "illuminate/mail": "^8.0", "illuminate/queue": "^8.0", "illuminate/support": "^8.0" }, "autoload": { "psr-4": { "Illuminate\\Notifications\\": "" } }, "extra": { "branch-alias": { "dev-master": "8.x-dev" } }, "suggest": { "illuminate/database": "Required to use the database transport (^8.0)." }, "config": { "sort-packages": true }, "minimum-stability": "dev" } DatabaseNotificationCollection.php000064400000000741152270627060013355 0ustar00each->markAsRead(); } /** * Mark all notifications as unread. * * @return void */ public function markAsUnread() { $this->each->markAsUnread(); } } SendQueuedNotifications.php000064400000010607152270627060012064 0ustar00channels = $channels; $this->notification = $notification; $this->notifiables = $this->wrapNotifiables($notifiables); $this->tries = property_exists($notification, 'tries') ? $notification->tries : null; $this->timeout = property_exists($notification, 'timeout') ? $notification->timeout : null; $this->afterCommit = property_exists($notification, 'afterCommit') ? $notification->afterCommit : null; $this->shouldBeEncrypted = $notification instanceof ShouldBeEncrypted; } /** * Wrap the notifiable(s) in a collection. * * @param \Illuminate\Notifications\Notifiable|\Illuminate\Support\Collection $notifiables * @return \Illuminate\Support\Collection */ protected function wrapNotifiables($notifiables) { if ($notifiables instanceof Collection) { return $notifiables; } elseif ($notifiables instanceof Model) { return EloquentCollection::wrap($notifiables); } return Collection::wrap($notifiables); } /** * Send the notifications. * * @param \Illuminate\Notifications\ChannelManager $manager * @return void */ public function handle(ChannelManager $manager) { $manager->sendNow($this->notifiables, $this->notification, $this->channels); } /** * Get the display name for the queued job. * * @return string */ public function displayName() { return get_class($this->notification); } /** * Call the failed method on the notification instance. * * @param \Throwable $e * @return void */ public function failed($e) { if (method_exists($this->notification, 'failed')) { $this->notification->failed($e); } } /** * Get the number of seconds before a released notification will be available. * * @return mixed */ public function backoff() { if (! method_exists($this->notification, 'backoff') && ! isset($this->notification->backoff)) { return; } return $this->notification->backoff ?? $this->notification->backoff(); } /** * Get the expiration for the notification. * * @return mixed */ public function retryUntil() { if (! method_exists($this->notification, 'retryUntil') && ! isset($this->notification->retryUntil)) { return; } return $this->notification->retryUntil ?? $this->notification->retryUntil(); } /** * Prepare the instance for cloning. * * @return void */ public function __clone() { $this->notifiables = clone $this->notifiables; $this->notification = clone $this->notification; } } ChannelManager.php000064400000007574152270627060010144 0ustar00container->make(Bus::class), $this->container->make(Dispatcher::class), $this->locale) )->send($notifiables, $notification); } /** * Send the given notification immediately. * * @param \Illuminate\Support\Collection|array|mixed $notifiables * @param mixed $notification * @param array|null $channels * @return void */ public function sendNow($notifiables, $notification, array $channels = null) { (new NotificationSender( $this, $this->container->make(Bus::class), $this->container->make(Dispatcher::class), $this->locale) )->sendNow($notifiables, $notification, $channels); } /** * Get a channel instance. * * @param string|null $name * @return mixed */ public function channel($name = null) { return $this->driver($name); } /** * Create an instance of the database driver. * * @return \Illuminate\Notifications\Channels\DatabaseChannel */ protected function createDatabaseDriver() { return $this->container->make(Channels\DatabaseChannel::class); } /** * Create an instance of the broadcast driver. * * @return \Illuminate\Notifications\Channels\BroadcastChannel */ protected function createBroadcastDriver() { return $this->container->make(Channels\BroadcastChannel::class); } /** * Create an instance of the mail driver. * * @return \Illuminate\Notifications\Channels\MailChannel */ protected function createMailDriver() { return $this->container->make(Channels\MailChannel::class); } /** * Create a new driver instance. * * @param string $driver * @return mixed * * @throws \InvalidArgumentException */ protected function createDriver($driver) { try { return parent::createDriver($driver); } catch (InvalidArgumentException $e) { if (class_exists($driver)) { return $this->container->make($driver); } throw $e; } } /** * Get the default channel driver name. * * @return string */ public function getDefaultDriver() { return $this->defaultChannel; } /** * Get the default channel driver name. * * @return string */ public function deliversVia() { return $this->getDefaultDriver(); } /** * Set the default channel driver name. * * @param string $channel * @return void */ public function deliverVia($channel) { $this->defaultChannel = $channel; } /** * Set the locale of notifications. * * @param string $locale * @return $this */ public function locale($locale) { $this->locale = $locale; return $this; } } Action.php000064400000000737152270627060006510 0ustar00url = $url; $this->text = $text; } } Channels/MailChannel.php000064400000017031152270627060011174 0ustar00mailer = $mailer; $this->markdown = $markdown; } /** * Send the given notification. * * @param mixed $notifiable * @param \Illuminate\Notifications\Notification $notification * @return void */ public function send($notifiable, Notification $notification) { $message = $notification->toMail($notifiable); if (! $notifiable->routeNotificationFor('mail', $notification) && ! $message instanceof Mailable) { return; } if ($message instanceof Mailable) { return $message->send($this->mailer); } $this->mailer->mailer($message->mailer ?? null)->send( $this->buildView($message), array_merge($message->data(), $this->additionalMessageData($notification)), $this->messageBuilder($notifiable, $notification, $message) ); } /** * Get the mailer Closure for the message. * * @param mixed $notifiable * @param \Illuminate\Notifications\Notification $notification * @param \Illuminate\Notifications\Messages\MailMessage $message * @return \Closure */ protected function messageBuilder($notifiable, $notification, $message) { return function ($mailMessage) use ($notifiable, $notification, $message) { $this->buildMessage($mailMessage, $notifiable, $notification, $message); }; } /** * Build the notification's view. * * @param \Illuminate\Notifications\Messages\MailMessage $message * @return string|array */ protected function buildView($message) { if ($message->view) { return $message->view; } if (property_exists($message, 'theme') && ! is_null($message->theme)) { $this->markdown->theme($message->theme); } return [ 'html' => $this->markdown->render($message->markdown, $message->data()), 'text' => $this->markdown->renderText($message->markdown, $message->data()), ]; } /** * Get additional meta-data to pass along with the view data. * * @param \Illuminate\Notifications\Notification $notification * @return array */ protected function additionalMessageData($notification) { return [ '__laravel_notification_id' => $notification->id, '__laravel_notification' => get_class($notification), '__laravel_notification_queued' => in_array( ShouldQueue::class, class_implements($notification) ), ]; } /** * Build the mail message. * * @param \Illuminate\Mail\Message $mailMessage * @param mixed $notifiable * @param \Illuminate\Notifications\Notification $notification * @param \Illuminate\Notifications\Messages\MailMessage $message * @return void */ protected function buildMessage($mailMessage, $notifiable, $notification, $message) { $this->addressMessage($mailMessage, $notifiable, $notification, $message); $mailMessage->subject($message->subject ?: Str::title( Str::snake(class_basename($notification), ' ') )); $this->addAttachments($mailMessage, $message); if (! is_null($message->priority)) { $mailMessage->setPriority($message->priority); } $this->runCallbacks($mailMessage, $message); } /** * Address the mail message. * * @param \Illuminate\Mail\Message $mailMessage * @param mixed $notifiable * @param \Illuminate\Notifications\Notification $notification * @param \Illuminate\Notifications\Messages\MailMessage $message * @return void */ protected function addressMessage($mailMessage, $notifiable, $notification, $message) { $this->addSender($mailMessage, $message); $mailMessage->to($this->getRecipients($notifiable, $notification, $message)); if (! empty($message->cc)) { foreach ($message->cc as $cc) { $mailMessage->cc($cc[0], Arr::get($cc, 1)); } } if (! empty($message->bcc)) { foreach ($message->bcc as $bcc) { $mailMessage->bcc($bcc[0], Arr::get($bcc, 1)); } } } /** * Add the "from" and "reply to" addresses to the message. * * @param \Illuminate\Mail\Message $mailMessage * @param \Illuminate\Notifications\Messages\MailMessage $message * @return void */ protected function addSender($mailMessage, $message) { if (! empty($message->from)) { $mailMessage->from($message->from[0], Arr::get($message->from, 1)); } if (! empty($message->replyTo)) { foreach ($message->replyTo as $replyTo) { $mailMessage->replyTo($replyTo[0], Arr::get($replyTo, 1)); } } } /** * Get the recipients of the given message. * * @param mixed $notifiable * @param \Illuminate\Notifications\Notification $notification * @param \Illuminate\Notifications\Messages\MailMessage $message * @return mixed */ protected function getRecipients($notifiable, $notification, $message) { if (is_string($recipients = $notifiable->routeNotificationFor('mail', $notification))) { $recipients = [$recipients]; } return collect($recipients)->mapWithKeys(function ($recipient, $email) { return is_numeric($email) ? [$email => (is_string($recipient) ? $recipient : $recipient->email)] : [$email => $recipient]; })->all(); } /** * Add the attachments to the message. * * @param \Illuminate\Mail\Message $mailMessage * @param \Illuminate\Notifications\Messages\MailMessage $message * @return void */ protected function addAttachments($mailMessage, $message) { foreach ($message->attachments as $attachment) { $mailMessage->attach($attachment['file'], $attachment['options']); } foreach ($message->rawAttachments as $attachment) { $mailMessage->attachData($attachment['data'], $attachment['name'], $attachment['options']); } } /** * Run the callbacks for the message. * * @param \Illuminate\Mail\Message $mailMessage * @param \Illuminate\Notifications\Messages\MailMessage $message * @return $this */ protected function runCallbacks($mailMessage, $message) { foreach ($message->callbacks as $callback) { $callback($mailMessage->getSwiftMessage()); } return $this; } } Channels/DatabaseChannel.php000064400000003665152270627060012026 0ustar00routeNotificationFor('database', $notification)->create( $this->buildPayload($notifiable, $notification) ); } /** * Build an array payload for the DatabaseNotification Model. * * @param mixed $notifiable * @param \Illuminate\Notifications\Notification $notification * @return array */ protected function buildPayload($notifiable, Notification $notification) { return [ 'id' => $notification->id, 'type' => method_exists($notification, 'databaseType') ? $notification->databaseType($notifiable) : get_class($notification), 'data' => $this->getData($notifiable, $notification), 'read_at' => null, ]; } /** * Get the data for the notification. * * @param mixed $notifiable * @param \Illuminate\Notifications\Notification $notification * @return array * * @throws \RuntimeException */ protected function getData($notifiable, Notification $notification) { if (method_exists($notification, 'toDatabase')) { return is_array($data = $notification->toDatabase($notifiable)) ? $data : $data->data; } if (method_exists($notification, 'toArray')) { return $notification->toArray($notifiable); } throw new RuntimeException('Notification is missing toDatabase / toArray method.'); } } Channels/BroadcastChannel.php000064400000003745152270627060012223 0ustar00events = $events; } /** * Send the given notification. * * @param mixed $notifiable * @param \Illuminate\Notifications\Notification $notification * @return array|null */ public function send($notifiable, Notification $notification) { $message = $this->getData($notifiable, $notification); $event = new BroadcastNotificationCreated( $notifiable, $notification, is_array($message) ? $message : $message->data ); if ($message instanceof BroadcastMessage) { $event->onConnection($message->connection) ->onQueue($message->queue); } return $this->events->dispatch($event); } /** * Get the data for the notification. * * @param mixed $notifiable * @param \Illuminate\Notifications\Notification $notification * @return mixed * * @throws \RuntimeException */ protected function getData($notifiable, Notification $notification) { if (method_exists($notification, 'toBroadcast')) { return $notification->toBroadcast($notifiable); } if (method_exists($notification, 'toArray')) { return $notification->toArray($notifiable); } throw new RuntimeException('Notification is missing toArray method.'); } } Notifiable.php000064400000000170152270627060007336 0ustar00channel = $channel; $this->notifiable = $notifiable; $this->notification = $notification; } } Events/NotificationFailed.php000064400000002161152270627060012263 0ustar00data = $data; $this->channel = $channel; $this->notifiable = $notifiable; $this->notification = $notification; } } Events/BroadcastNotificationCreated.php000064400000005446152270627060014302 0ustar00data = $data; $this->notifiable = $notifiable; $this->notification = $notification; } /** * Get the channels the event should broadcast on. * * @return array */ public function broadcastOn() { $channels = $this->notification->broadcastOn(); if (! empty($channels)) { return $channels; } if (is_string($channels = $this->channelName())) { return [new PrivateChannel($channels)]; } return collect($channels)->map(function ($channel) { return new PrivateChannel($channel); })->all(); } /** * Get the broadcast channel name for the event. * * @return array|string */ protected function channelName() { if (method_exists($this->notifiable, 'receivesBroadcastNotificationsOn')) { return $this->notifiable->receivesBroadcastNotificationsOn($this->notification); } $class = str_replace('\\', '.', get_class($this->notifiable)); return $class.'.'.$this->notifiable->getKey(); } /** * Get the data that should be sent with the broadcasted event. * * @return array */ public function broadcastWith() { if (method_exists($this->notification, 'broadcastWith')) { return $this->notification->broadcastWith(); } return array_merge($this->data, [ 'id' => $this->notification->id, 'type' => $this->broadcastType(), ]); } /** * Get the type of the notification being broadcast. * * @return string */ public function broadcastType() { return method_exists($this->notification, 'broadcastType') ? $this->notification->broadcastType() : get_class($this->notification); } } Events/NotificationSent.php000064400000002157152270627060012015 0ustar00channel = $channel; $this->response = $response; $this->notifiable = $notifiable; $this->notification = $notification; } } RoutesNotifications.php000064400000002440152270627060011277 0ustar00send($this, $instance); } /** * Send the given notification immediately. * * @param mixed $instance * @param array|null $channels * @return void */ public function notifyNow($instance, array $channels = null) { app(Dispatcher::class)->sendNow($this, $instance, $channels); } /** * Get the notification routing information for the given driver. * * @param string $driver * @param \Illuminate\Notifications\Notification|null $notification * @return mixed */ public function routeNotificationFor($driver, $notification = null) { if (method_exists($this, $method = 'routeNotificationFor'.Str::studly($driver))) { return $this->{$method}($notification); } switch ($driver) { case 'database': return $this->notifications(); case 'mail': return $this->email; } } } LICENSE.md000064400000002063152270627060006160 0ustar00The MIT License (MIT) Copyright (c) Taylor Otwell Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Notification.php000064400000001400152270627060007705 0ustar00locale = $locale; return $this; } } HasDatabaseNotifications.php000064400000001441152270627060012156 0ustar00morphMany(DatabaseNotification::class, 'notifiable')->orderBy('created_at', 'desc'); } /** * Get the entity's read notifications. * * @return \Illuminate\Database\Query\Builder */ public function readNotifications() { return $this->notifications()->read(); } /** * Get the entity's unread notifications. * * @return \Illuminate\Database\Query\Builder */ public function unreadNotifications() { return $this->notifications()->unread(); } } resources/views/email.blade.php000064400000002205152270627060012567 0ustar00@component('mail::message') {{-- Greeting --}} @if (! empty($greeting)) # {{ $greeting }} @else @if ($level === 'error') # @lang('Whoops!') @else # @lang('Hello!') @endif @endif {{-- Intro Lines --}} @foreach ($introLines as $line) {{ $line }} @endforeach {{-- Action Button --}} @isset($actionText) @component('mail::button', ['url' => $actionUrl, 'color' => $color]) {{ $actionText }} @endcomponent @endisset {{-- Outro Lines --}} @foreach ($outroLines as $line) {{ $line }} @endforeach {{-- Salutation --}} @if (! empty($salutation)) {{ $salutation }} @else @lang('Regards'),
{{ config('app.name') }} @endif {{-- Subcopy --}} @isset($actionText) @slot('subcopy') @lang( "If you're having trouble clicking the \":actionText\" button, copy and paste the URL below\n". 'into your web browser:', [ 'actionText' => $actionText, ] ) [{{ $displayableActionUrl }}]({{ $actionUrl }}) @endslot @endisset @endcomponent Messages/SimpleMessage.php000064400000012071152270627060011572 0ustar00level = 'success'; return $this; } /** * Indicate that the notification gives information about an error. * * @return $this */ public function error() { $this->level = 'error'; return $this; } /** * Set the "level" of the notification (success, error, etc.). * * @param string $level * @return $this */ public function level($level) { $this->level = $level; return $this; } /** * Set the subject of the notification. * * @param string $subject * @return $this */ public function subject($subject) { $this->subject = $subject; return $this; } /** * Set the greeting of the notification. * * @param string $greeting * @return $this */ public function greeting($greeting) { $this->greeting = $greeting; return $this; } /** * Set the salutation of the notification. * * @param string $salutation * @return $this */ public function salutation($salutation) { $this->salutation = $salutation; return $this; } /** * Add a line of text to the notification. * * @param mixed $line * @return $this */ public function line($line) { return $this->with($line); } /** * Add lines of text to the notification. * * @param iterable $lines * @return $this */ public function lines($lines) { foreach ($lines as $line) { $this->line($line); } return $this; } /** * Add a line of text to the notification. * * @param mixed $line * @return $this */ public function with($line) { if ($line instanceof Action) { $this->action($line->text, $line->url); } elseif (! $this->actionText) { $this->introLines[] = $this->formatLine($line); } else { $this->outroLines[] = $this->formatLine($line); } return $this; } /** * Format the given line of text. * * @param \Illuminate\Contracts\Support\Htmlable|string|array $line * @return \Illuminate\Contracts\Support\Htmlable|string */ protected function formatLine($line) { if ($line instanceof Htmlable) { return $line; } if (is_array($line)) { return implode(' ', array_map('trim', $line)); } return trim(implode(' ', array_map('trim', preg_split('/\\r\\n|\\r|\\n/', $line ?? '')))); } /** * Configure the "call to action" button. * * @param string $text * @param string $url * @return $this */ public function action($text, $url) { $this->actionText = $text; $this->actionUrl = $url; return $this; } /** * Set the name of the mailer that should send the notification. * * @param string $mailer * @return $this */ public function mailer($mailer) { $this->mailer = $mailer; return $this; } /** * Get an array representation of the message. * * @return array */ public function toArray() { return [ 'level' => $this->level, 'subject' => $this->subject, 'greeting' => $this->greeting, 'salutation' => $this->salutation, 'introLines' => $this->introLines, 'outroLines' => $this->outroLines, 'actionText' => $this->actionText, 'actionUrl' => $this->actionUrl, 'displayableActionUrl' => str_replace(['mailto:', 'tel:'], '', $this->actionUrl ?? ''), ]; } } Messages/DatabaseMessage.php000064400000000625152270627060012047 0ustar00data = $data; } } Messages/BroadcastMessage.php000064400000001156152270627060012245 0ustar00data = $data; } /** * Set the message data. * * @param array $data * @return $this */ public function data($data) { $this->data = $data; return $this; } } Messages/MailMessage.php000064400000015553152270627060011233 0ustar00view = $view; $this->viewData = $data; $this->markdown = null; return $this; } /** * Set the Markdown template for the notification. * * @param string $view * @param array $data * @return $this */ public function markdown($view, array $data = []) { $this->markdown = $view; $this->viewData = $data; $this->view = null; return $this; } /** * Set the default markdown template. * * @param string $template * @return $this */ public function template($template) { $this->markdown = $template; return $this; } /** * Set the theme to use with the Markdown template. * * @param string $theme * @return $this */ public function theme($theme) { $this->theme = $theme; return $this; } /** * Set the from address for the mail message. * * @param string $address * @param string|null $name * @return $this */ public function from($address, $name = null) { $this->from = [$address, $name]; return $this; } /** * Set the "reply to" address of the message. * * @param array|string $address * @param string|null $name * @return $this */ public function replyTo($address, $name = null) { if ($this->arrayOfAddresses($address)) { $this->replyTo += $this->parseAddresses($address); } else { $this->replyTo[] = [$address, $name]; } return $this; } /** * Set the cc address for the mail message. * * @param array|string $address * @param string|null $name * @return $this */ public function cc($address, $name = null) { if ($this->arrayOfAddresses($address)) { $this->cc += $this->parseAddresses($address); } else { $this->cc[] = [$address, $name]; } return $this; } /** * Set the bcc address for the mail message. * * @param array|string $address * @param string|null $name * @return $this */ public function bcc($address, $name = null) { if ($this->arrayOfAddresses($address)) { $this->bcc += $this->parseAddresses($address); } else { $this->bcc[] = [$address, $name]; } return $this; } /** * Attach a file to the message. * * @param string $file * @param array $options * @return $this */ public function attach($file, array $options = []) { $this->attachments[] = compact('file', 'options'); return $this; } /** * Attach in-memory data as an attachment. * * @param string $data * @param string $name * @param array $options * @return $this */ public function attachData($data, $name, array $options = []) { $this->rawAttachments[] = compact('data', 'name', 'options'); return $this; } /** * Set the priority of this message. * * The value is an integer where 1 is the highest priority and 5 is the lowest. * * @param int $level * @return $this */ public function priority($level) { $this->priority = $level; return $this; } /** * Get the data array for the mail message. * * @return array */ public function data() { return array_merge($this->toArray(), $this->viewData); } /** * Parse the multi-address array into the necessary format. * * @param array $value * @return array */ protected function parseAddresses($value) { return collect($value)->map(function ($address, $name) { return [$address, is_numeric($name) ? null : $name]; })->values()->all(); } /** * Determine if the given "address" is actually an array of addresses. * * @param mixed $address * @return bool */ protected function arrayOfAddresses($address) { return is_iterable($address) || $address instanceof Arrayable; } /** * Render the mail notification message into an HTML string. * * @return string */ public function render() { if (isset($this->view)) { return Container::getInstance()->make('mailer')->render( $this->view, $this->data() ); } $markdown = Container::getInstance()->make(Markdown::class); return $markdown->theme($this->theme ?: $markdown->getTheme()) ->render($this->markdown, $this->data()); } /** * Register a callback to be called with the Swift message instance. * * @param callable $callback * @return $this */ public function withSwiftMessage($callback) { $this->callbacks[] = $callback; return $this; } }