From 7ebab328d43a2fa44df0c52bcce475d6d96e8131 Mon Sep 17 00:00:00 2001 From: Peter Deltchev Date: Fri, 30 Dec 2016 11:22:44 -0800 Subject: [PATCH] #25: Enabled email notifications for all users. This also includes some fixes to the account merging script. --- app/Commands/MergeAccountsCommand.php | 21 +++- app/Commands/SaveAccountSettingsCommand.php | 27 +++-- app/Console/Commands/MergeAccounts.php | 21 ++++ .../Controllers/Api/Web/AccountController.php | 3 +- app/Models/User.php | 21 ++-- app/Providers/AuthServiceProvider.php | 5 - ..._12_30_193250_EnableEmailNotifications.php | 102 ++++++++++++++++++ public/templates/account/settings.html | 11 +- 8 files changed, 175 insertions(+), 36 deletions(-) create mode 100644 database/migrations/2016_12_30_193250_EnableEmailNotifications.php diff --git a/app/Commands/MergeAccountsCommand.php b/app/Commands/MergeAccountsCommand.php index 6bde0516..a1ef3e81 100644 --- a/app/Commands/MergeAccountsCommand.php +++ b/app/Commands/MergeAccountsCommand.php @@ -24,9 +24,11 @@ use Carbon\Carbon; use DB; use Poniverse\Ponyfm\Models\Album; use Poniverse\Ponyfm\Models\Comment; +use Poniverse\Ponyfm\Models\EmailSubscription; use Poniverse\Ponyfm\Models\Favourite; use Poniverse\Ponyfm\Models\Follower; use Poniverse\Ponyfm\Models\Image; +use Poniverse\Ponyfm\Models\Notification; use Poniverse\Ponyfm\Models\PinnedPlaylist; use Poniverse\Ponyfm\Models\Playlist; use Poniverse\Ponyfm\Models\ResourceLogItem; @@ -46,6 +48,10 @@ class MergeAccountsCommand extends CommandBase } /** + * Note: OAuth tokens are intentionally left untouched by the merge process. + * The Artisan script performs some sanity checks to alert the admin to the + * consequences of this. + * * @throws \Exception * @return CommandResponse */ @@ -84,8 +90,6 @@ class MergeAccountsCommand extends CommandBase $image->save(); } - DB::table('oauth2_tokens')->whereIn('user_id', $accountIds)->update(['user_id' => $this->destinationAccount->id]); - foreach (PinnedPlaylist::whereIn('user_id', $accountIds)->get() as $playlist) { $playlist->user_id = $this->destinationAccount->id; $playlist->save(); @@ -106,11 +110,24 @@ class MergeAccountsCommand extends CommandBase $item->save(); } + /** @var Track $track */ foreach (Track::whereIn('user_id', $accountIds)->get() as $track) { $track->user_id = $this->destinationAccount->id; $track->save(); } + /** @var EmailSubscription $emailSubscription */ + foreach($this->sourceAccount->emailSubscriptions()->withTrashed()->get() as $emailSubscription) { + // This keeps emails from being sent to disabled accounts. + $emailSubscription->delete(); + } + + /** @var Notification $notification */ + foreach ($this->sourceAccount->notifications()->get() as $notification) { + $notification->user_id = $this->destinationAccount->id; + $notification->save(); + } + $this->sourceAccount->disabled_at = Carbon::now(); $this->sourceAccount->save(); }); diff --git a/app/Commands/SaveAccountSettingsCommand.php b/app/Commands/SaveAccountSettingsCommand.php index e3fdd2e2..44504ac2 100644 --- a/app/Commands/SaveAccountSettingsCommand.php +++ b/app/Commands/SaveAccountSettingsCommand.php @@ -110,23 +110,20 @@ class SaveAccountSettingsCommand extends CommandBase $this->_user->save(); // Sync email subscriptions - // TODO: [#25] Remove this when email notifications are rolled out to everyone. - if (Gate::forUser($this->_user)->allows('receive-email-notifications')) { - $emailSubscriptions = $this->_user->emailSubscriptions->keyBy('activity_type'); - foreach ($this->_input['notifications'] as $notificationSetting) { + $emailSubscriptions = $this->_user->emailSubscriptions->keyBy('activity_type'); + foreach ($this->_input['notifications'] as $notificationSetting) { - if ( - $notificationSetting['receive_emails'] && - !$emailSubscriptions->offsetExists($notificationSetting['activity_type']) - ) { - $this->_user->emailSubscriptions()->create(['activity_type' => $notificationSetting['activity_type']]); + if ( + $notificationSetting['receive_emails'] && + !$emailSubscriptions->offsetExists($notificationSetting['activity_type']) + ) { + $this->_user->emailSubscriptions()->create(['activity_type' => $notificationSetting['activity_type']]); - } elseif ( - !$notificationSetting['receive_emails'] && - $emailSubscriptions->offsetExists($notificationSetting['activity_type']) - ) { - $emailSubscriptions->get($notificationSetting['activity_type'])->delete(); - } + } elseif ( + !$notificationSetting['receive_emails'] && + $emailSubscriptions->offsetExists($notificationSetting['activity_type']) + ) { + $emailSubscriptions->get($notificationSetting['activity_type'])->delete(); } } }); diff --git a/app/Console/Commands/MergeAccounts.php b/app/Console/Commands/MergeAccounts.php index f4247d7d..80f07f66 100644 --- a/app/Console/Commands/MergeAccounts.php +++ b/app/Console/Commands/MergeAccounts.php @@ -77,9 +77,30 @@ class MergeAccounts extends Command $sourceAccount = User::find($sourceAccountId); $destinationAccount = User::find($destinationAccountId); + // Sanity checks + if (null !== $sourceAccount->getAccessToken()) { + $this->warn("WARNING: The source account (ID {$sourceAccountId}) is linked to a Poniverse account! Normally, the destination account should be the one that's linked to a Poniverse account as that's the one that the artist will be logging into."); + $this->line(''); + $this->warn("If you continue with this merge, the Poniverse account linked to the source Pony.fm account will no longer be able to log into Pony.fm."); + if (!$this->confirm('Continue merging this set of source and destination accounts?')){ + $this->error('Merge aborted.'); + return 1; + } + } + + if (null === $destinationAccount->getAccessToken()) { + $this->warn("WARNING: The destination account (ID {$destinationAccountId}) is not linked to a Poniverse account!"); + $this->warn("This is normal if you're merging two archived profiles but not if you're helping an artist claim their profile."); + if (!$this->confirm('Continue merging this set of source and destination accounts?')){ + $this->error('Merge aborted.'); + return 1; + } + } + $this->info("Merging {$sourceAccount->display_name} ({$sourceAccountId}) into {$destinationAccount->display_name} ({$destinationAccountId})..."); $command = new MergeAccountsCommand($sourceAccount, $destinationAccount); $command->execute(); + return 0; } } diff --git a/app/Http/Controllers/Api/Web/AccountController.php b/app/Http/Controllers/Api/Web/AccountController.php index d0853d6b..815ecb1a 100644 --- a/app/Http/Controllers/Api/Web/AccountController.php +++ b/app/Http/Controllers/Api/Web/AccountController.php @@ -71,8 +71,7 @@ class AccountController extends ApiControllerBase 'gravatar' => $user->gravatar ? $user->gravatar : $user->email, 'avatar_url' => !$user->uses_gravatar ? $user->getAvatarUrl() : null, 'uses_gravatar' => $user->uses_gravatar == 1, - // TODO: [#25] Remove this when email notifications are rolled out to everyone. - 'can_manage_notifications' => Gate::forUser($user)->allows('receive-email-notifications'), + 'notification_email' => $user->email, 'notifications' => $user->getNotificationSettings() ], 200); } diff --git a/app/Models/User.php b/app/Models/User.php index 44e38980..1564d90a 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -174,16 +174,21 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon /** * Gets this user's OAuth access token record. * - * @return AccessToken + * @return AccessToken|null */ - public function getAccessToken():AccessToken { + public function getAccessToken() { $accessTokenRecord = DB::table('oauth2_tokens')->where('user_id', '=', $this->id)->first(); - return new AccessToken([ - 'access_token' => $accessTokenRecord->access_token, - 'refresh_token' => $accessTokenRecord->refresh_token, - 'expires' => Carbon::parse($accessTokenRecord->expires)->timestamp, - 'resource_owner_id' => $accessTokenRecord->external_user_id, - ]); + + if ($accessTokenRecord === null) { + return null; + } else { + return new AccessToken([ + 'access_token' => $accessTokenRecord->access_token, + 'refresh_token' => $accessTokenRecord->refresh_token, + 'expires' => Carbon::parse($accessTokenRecord->expires)->timestamp, + 'resource_owner_id' => $accessTokenRecord->external_user_id, + ]); + } } /** diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php index 2e17adf7..196e79e5 100644 --- a/app/Providers/AuthServiceProvider.php +++ b/app/Providers/AuthServiceProvider.php @@ -76,11 +76,6 @@ class AuthServiceProvider extends ServiceProvider return $user->hasRole('admin'); }); - // TODO: [#25] Remove this when email notifications are rolled out to everyone. - Gate::define('receive-email-notifications', function (User $user) { - return $user->hasRole('admin'); - }); - $this->registerPolicies(); } } diff --git a/database/migrations/2016_12_30_193250_EnableEmailNotifications.php b/database/migrations/2016_12_30_193250_EnableEmailNotifications.php new file mode 100644 index 00000000..37362975 --- /dev/null +++ b/database/migrations/2016_12_30_193250_EnableEmailNotifications.php @@ -0,0 +1,102 @@ +. + */ + + +use Illuminate\Support\Facades\Schema; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Database\Migrations\Migration; +use Poniverse\Ponyfm\Models\User; + +class EnableEmailNotifications extends Migration { + /** + * Run the migrations. + * + * @return void + */ + public function up() { + DB::table('email_subscriptions')->delete(); + + User::whereNull('disabled_at') + ->where('is_archived', false) + ->chunk(100, function ($users) { + /** @var User $user */ + foreach ($users as $user) { + $now = \Carbon\Carbon::now(); + $userId = $user->id; + + DB::table('email_subscriptions') + ->insert([ + [ + 'id' => \Webpatser\Uuid\Uuid::generate(4), + 'user_id' => $userId, + 'activity_type' => 2, + 'created_at' => $now, + 'updated_at' => $now, + ], + [ + 'id' => \Webpatser\Uuid\Uuid::generate(4), + 'user_id' => $userId, + 'activity_type' => 3, + 'created_at' => $now, + 'updated_at' => $now, + ], + [ + 'id' => \Webpatser\Uuid\Uuid::generate(4), + 'user_id' => $userId, + 'activity_type' => 4, + 'created_at' => $now, + 'updated_at' => $now, + ], + [ + 'id' => \Webpatser\Uuid\Uuid::generate(4), + 'user_id' => $userId, + 'activity_type' => 5, + 'created_at' => $now, + 'updated_at' => $now, + ], + [ + 'id' => \Webpatser\Uuid\Uuid::generate(4), + 'user_id' => $userId, + 'activity_type' => 6, + 'created_at' => $now, + 'updated_at' => $now, + ], + [ + 'id' => \Webpatser\Uuid\Uuid::generate(4), + 'user_id' => $userId, + 'activity_type' => 7, + 'created_at' => $now, + 'updated_at' => $now, + ] + ]); + } + + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() { + DB::table('email_subscriptions')->delete(); + } +} diff --git a/public/templates/account/settings.html b/public/templates/account/settings.html index 8a78956a..3bc18274 100644 --- a/public/templates/account/settings.html +++ b/public/templates/account/settings.html @@ -43,7 +43,7 @@
{{errors.gravatar}}
-
+

{{ ::unsubscribeMessage }}

@@ -52,15 +52,18 @@

On-site notifications are always on. That way, you can always see what you've missed whenever you log on to Pony.fm!

+

Email notifications will be sent to {{ ::settings.notification_email }}. + You can change this address in your Poniverse account settings.

+ - + - - + +
When… Email me! Give me a push notification!
Coming soon!