#25: Implemented all basic notification types.

- blocks off the unfinished URL endpoints for email notifications
This commit is contained in:
Peter Deltchev 2016-12-23 06:31:45 -08:00
parent 78b22cdfd0
commit ff5d8220ef
8 changed files with 85 additions and 43 deletions

View file

@ -20,12 +20,17 @@
namespace Poniverse\Ponyfm\Http\Controllers;
use App;
use DB;
use Poniverse\Ponyfm\Models\Email;
use Poniverse\Ponyfm\Models\EmailSubscription;
// TODO: #25 - finish these endpoints and secure them properly
class NotificationsController extends Controller {
public function getEmailClick($emailKey) {
App::abort(403, "This isn't implemented yet!");
$emailKey = decrypt($emailKey);
/** @var Email $email */
$email = Email::findOrFail($emailKey);
@ -40,6 +45,8 @@ class NotificationsController extends Controller {
}
public function getEmailUnsubscribe($subscriptionKey) {
App::abort(403, "This isn't implemented yet!");
$subscriptionId = decrypt($subscriptionKey);
$subscription = EmailSubscription::findOrFail($subscriptionId);

View file

@ -25,11 +25,6 @@ use Log;
use Mail;
use Poniverse\Ponyfm\Contracts\Favouritable;
use Poniverse\Ponyfm\Mail\BaseNotification;
use Poniverse\Ponyfm\Mail\ContentFavourited;
use Poniverse\Ponyfm\Mail\NewComment;
use Poniverse\Ponyfm\Mail\NewFollower;
use Poniverse\Ponyfm\Mail\NewPlaylist;
use Poniverse\Ponyfm\Mail\NewTrack;
use Poniverse\Ponyfm\Models\Activity;
use Poniverse\Ponyfm\Models\Comment;
use Poniverse\Ponyfm\Models\Email;
@ -66,7 +61,9 @@ class PonyfmDriver extends AbstractDriver
*/
private function sendEmails(Activity $activity, $recipients) {
foreach ($recipients as $recipient) {
/** @var Notification $notification */
$notification = $activity->notifications->where('user_id', $recipient->id)->first();
/** @var Email $email */
$email = $notification->email()->create([]);
Log::debug("Attempting to send an email about notification {$notification->id} to {$recipient->email}.");
@ -88,8 +85,10 @@ class PonyfmDriver extends AbstractDriver
]);
$recipientsQuery = $this->getRecipients(__FUNCTION__, func_get_args());
$this->insertNotifications($activity, $recipientsQuery->get());
$this->sendEmails($activity, $recipientsQuery->withEmailSubscriptionFor(Activity::TYPE_PUBLISHED_TRACK)->get());
if (NULL !== $recipientsQuery) {
$this->insertNotifications($activity, $recipientsQuery->get());
$this->sendEmails($activity, $recipientsQuery->withEmailSubscriptionFor(Activity::TYPE_PUBLISHED_TRACK)->get());
}
}
/**
@ -106,10 +105,15 @@ class PonyfmDriver extends AbstractDriver
]);
$recipientsQuery = $this->getRecipients(__FUNCTION__, func_get_args());
$this->insertNotifications($activity, $recipientsQuery->get());
$this->sendEmails($activity, $recipientsQuery->withEmailSubscriptionFor(Activity::TYPE_PUBLISHED_PLAYLIST)->get());
if (NULL !== $recipientsQuery) {
$this->insertNotifications($activity, $recipientsQuery->get());
$this->sendEmails($activity, $recipientsQuery->withEmailSubscriptionFor(Activity::TYPE_PUBLISHED_PLAYLIST)->get());
}
}
/**
* @inheritdoc
*/
public function newFollower(User $userBeingFollowed, User $follower)
{
$activity = Activity::create([
@ -121,8 +125,10 @@ class PonyfmDriver extends AbstractDriver
]);
$recipientsQuery = $this->getRecipients(__FUNCTION__, func_get_args());
$this->insertNotifications($activity, $recipientsQuery->get());
$this->sendEmails($activity, $recipientsQuery->withEmailSubscriptionFor(Activity::TYPE_NEW_FOLLOWER)->get());
if (NULL !== $recipientsQuery) {
$this->insertNotifications($activity, $recipientsQuery->get());
$this->sendEmails($activity, $recipientsQuery->withEmailSubscriptionFor(Activity::TYPE_NEW_FOLLOWER)->get());
}
}
/**
@ -139,8 +145,10 @@ class PonyfmDriver extends AbstractDriver
]);
$recipientsQuery = $this->getRecipients(__FUNCTION__, func_get_args());
$this->insertNotifications($activity, $recipientsQuery->get());
$this->sendEmails($activity, $recipientsQuery->withEmailSubscriptionFor(Activity::TYPE_NEW_COMMENT)->get());
if (NULL !== $recipientsQuery) {
$this->insertNotifications($activity, $recipientsQuery->get());
$this->sendEmails($activity, $recipientsQuery->withEmailSubscriptionFor(Activity::TYPE_NEW_COMMENT)->get());
}
}
/**
@ -157,7 +165,9 @@ class PonyfmDriver extends AbstractDriver
]);
$recipientsQuery = $this->getRecipients(__FUNCTION__, func_get_args());
$this->insertNotifications($activity, $recipientsQuery->get());
$this->sendEmails($activity, $recipientsQuery->withEmailSubscriptionFor(Activity::TYPE_CONTENT_FAVOURITED)->get());
if (NULL !== $recipientsQuery) {
$this->insertNotifications($activity, $recipientsQuery->get());
$this->sendEmails($activity, $recipientsQuery->withEmailSubscriptionFor(Activity::TYPE_CONTENT_FAVOURITED)->get());
}
}
}

View file

@ -20,11 +20,11 @@
namespace Poniverse\Ponyfm\Library\Notifications;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Poniverse\Ponyfm\Contracts\Favouritable;
use Poniverse\Ponyfm\Contracts\NotificationHandler;
use Poniverse\Ponyfm\Jobs\SendNotifications;
use Poniverse\Ponyfm\Library\Notifications\Drivers\EmailDriver;
use Poniverse\Ponyfm\Library\Notifications\Drivers\NativeDriver;
use Poniverse\Ponyfm\Library\Notifications\Drivers\PonyfmDriver;
use Poniverse\Ponyfm\Models\Activity;
@ -39,7 +39,8 @@ use Poniverse\Ponyfm\Models\User;
* @package Poniverse\Ponyfm\Library\Notifications
*
* This class returns a list of users who are to receive a particular notification.
* It is instantiated on a per-driver basis.
* It is instantiated on a per-driver basis. Its methods return Eloquent query
* objects for the PonyfmDriver.
*/
class RecipientFinder implements NotificationHandler
{
@ -67,11 +68,6 @@ class RecipientFinder implements NotificationHandler
case PonyfmDriver::class:
return $track->user->followers();
case EmailDriver::class:
return $track->user->followers()->whereHas('emailSubscriptions', function($query) {
$query->where('activity_type', Activity::TYPE_PUBLISHED_TRACK);
})->get();
case NativeDriver::class:
$followerIds = [];
$subIds = [];
@ -99,7 +95,8 @@ class RecipientFinder implements NotificationHandler
{
switch ($this->notificationDriver) {
case PonyfmDriver::class:
return $playlist->user->followers;
return $playlist->user->followers();
case NativeDriver::class:
$followerIds = [];
$subIds = [];
@ -127,8 +124,8 @@ class RecipientFinder implements NotificationHandler
{
switch ($this->notificationDriver) {
case PonyfmDriver::class:
case EmailDriver::class:
return [$userBeingFollowed];
return $this->queryForUser($userBeingFollowed);
case NativeDriver::class:
return Subscription::where('user_id', '=', $userBeingFollowed->id)->get();
default:
@ -145,8 +142,8 @@ class RecipientFinder implements NotificationHandler
case PonyfmDriver::class:
return
$comment->user->id === $comment->resource->user->id
? []
: [$comment->resource->user];
? NULL
: $this->queryForUser($comment->resource->user);
case NativeDriver::class:
return Subscription::where('user_id', '=', $comment->resource->user->id)->get();
default:
@ -163,12 +160,23 @@ class RecipientFinder implements NotificationHandler
case PonyfmDriver::class:
return
$favouriter->id === $entityBeingFavourited->user->id
? []
: [$entityBeingFavourited->user];
? NULL
: $this->queryForUser($entityBeingFavourited->user);
case NativeDriver::class:
return Subscription::where('user_id', '=', $entityBeingFavourited->user->id)->get();
default:
return $this->fail();
}
}
/**
* Helper function that returns an Eloquent query instance that will return
* a specific user when executed.
*
* @param User $user
* @return \Eloquent|Builder
*/
private function queryForUser(User $user):Builder {
return User::where('id', '=', $user->id);
}
}

View file

@ -32,9 +32,9 @@ class ContentFavourited extends BaseNotification
return $this->renderEmail(
'content-favourited',
$this->activityRecord->text, [
'creatorName' => $creatorName,
'resourceType' => $this->activityRecord->getResourceType(),
'resourceTitle' => $this->activityRecord->resource->resource->title,
'creatorName' => $creatorName,
'resourceType' => $this->activityRecord->getResourceTypeString(),
'resourceTitle' => $this->activityRecord->resource->title,
]);
}
}

View file

@ -33,7 +33,7 @@ class NewComment extends BaseNotification
// Profile comments get a different template and subject line from
// other types of comments.
if ($this->activityRecord->getResourceType() === User::class) {
if ($this->activityRecord->getResourceTypeString() === User::class) {
return $this->renderEmail(
'new-comment-profile',
$this->activityRecord->text, [
@ -43,9 +43,9 @@ class NewComment extends BaseNotification
return $this->renderEmail(
'new-comment-content',
$this->activityRecord->text, [
'creatorName' => $creatorName,
'resourceType' => $this->activityRecord->getResourceType(),
'resourceTitle' => $this->activityRecord->resource->resource->title,
'creatorName' => $creatorName,
'resourceType' => $this->activityRecord->getResourceTypeString(),
'resourceTitle' => $this->activityRecord->resource->resource->title,
]);
}

View file

@ -217,11 +217,11 @@ class Activity extends Model
* @return string
* @throws \Exception
*/
public function getResourceType():string
public function getResourceTypeString():string
{
switch($this->activity_type) {
case static::TYPE_NEW_COMMENT:
if ($this->resource_type === User::class) {
if ($this->isProfileComment()) {
return $this->resource->getResourceType();
} else {
return $this->resource->resource->getResourceType();
@ -232,6 +232,14 @@ class Activity extends Model
throw new \Exception("Unknown activity type {$this->activity_type} - cannot determine resource type.");
}
/**
* @return bool
*/
public function isProfileComment():bool {
return static::TYPE_NEW_COMMENT === $this->activity_type &&
User::class === $this->resource->getResourceClass();
}
/**
* The string this method generates is used for email subject lines as well
* as on-site notifications.
@ -256,17 +264,16 @@ class Activity extends Model
return "{$this->initiatingUser->display_name} is now following you!";
case static::TYPE_NEW_COMMENT:
// Is this a profile comment?
if ($this->resource_type === User::class) {
if ($this->isProfileComment()) {
return "{$this->initiatingUser->display_name} left a comment on your profile!";
// Must be a content comment.
// If it's not a profile comment, it must be a content comment.
} else {
return "{$this->initiatingUser->display_name} left a comment on your {$this->getResourceType()}, {$this->resource->resource->title}!";
return "{$this->initiatingUser->display_name} left a comment on your {$this->getResourceTypeString()}, \"{$this->resource->resource->title}\"!";
}
case static::TYPE_CONTENT_FAVOURITED:
return "{$this->initiatingUser->display_name} favourited your {$this->getResourceType()}, {$this->resource->title}!";
return "{$this->initiatingUser->display_name} favourited your {$this->getResourceTypeString()}, \"{$this->resource->title}\"!";
default:
throw new \Exception('This activity\'s activity type is unknown!');

View file

@ -144,6 +144,15 @@ class Comment extends Model
}
}
/**
* Returns the class name of the object that this is a comment on.
*
* @return string
*/
public function getResourceClass():string {
return get_class($this->resource);
}
public function delete()
{
DB::transaction(function () {

View file

@ -77,6 +77,7 @@ Route::get('p{id}/dl.{extension}', 'PlaylistsController@getDownload');
Route::get('notifications', 'AccountController@getNotifications');
Route::get('notifications/email/unsubscribe/{subscriptionKey}', 'NotificationsController@getEmailUnsubscribe')->name('email:unsubscribe');
Route::get('notifications/email/click/{emailKey}', 'NotificationsController@getEmailClick')->name('email:click');