diff --git a/app/Http/Controllers/NotificationsController.php b/app/Http/Controllers/NotificationsController.php index 9d961828..f93dba87 100644 --- a/app/Http/Controllers/NotificationsController.php +++ b/app/Http/Controllers/NotificationsController.php @@ -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); diff --git a/app/Library/Notifications/Drivers/PonyfmDriver.php b/app/Library/Notifications/Drivers/PonyfmDriver.php index af816e1b..b4d1eaad 100644 --- a/app/Library/Notifications/Drivers/PonyfmDriver.php +++ b/app/Library/Notifications/Drivers/PonyfmDriver.php @@ -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()); + } } } diff --git a/app/Library/Notifications/RecipientFinder.php b/app/Library/Notifications/RecipientFinder.php index f09a48c2..afacfbe6 100644 --- a/app/Library/Notifications/RecipientFinder.php +++ b/app/Library/Notifications/RecipientFinder.php @@ -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); + } } diff --git a/app/Mail/ContentFavourited.php b/app/Mail/ContentFavourited.php index 59e35e2c..21e07641 100644 --- a/app/Mail/ContentFavourited.php +++ b/app/Mail/ContentFavourited.php @@ -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, ]); } } diff --git a/app/Mail/NewComment.php b/app/Mail/NewComment.php index 8580e7ed..5295f4ee 100644 --- a/app/Mail/NewComment.php +++ b/app/Mail/NewComment.php @@ -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, ]); } diff --git a/app/Models/Activity.php b/app/Models/Activity.php index 8899d587..edc79039 100644 --- a/app/Models/Activity.php +++ b/app/Models/Activity.php @@ -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!'); diff --git a/app/Models/Comment.php b/app/Models/Comment.php index d16cfd65..b4665c8e 100644 --- a/app/Models/Comment.php +++ b/app/Models/Comment.php @@ -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 () { diff --git a/routes/web.php b/routes/web.php index 34358a0c..5dd1b672 100644 --- a/routes/web.php +++ b/routes/web.php @@ -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');