From 51642fc40d27ca844ad734fd57086717beaba75d Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Fri, 21 Feb 2020 21:00:00 -0700 Subject: [PATCH] Add modlog notifications --- app/Observers/ModLogObserver.php | 66 +++++++++++++++++++ app/Providers/AppServiceProvider.php | 3 + app/Services/ModLogService.php | 44 +++++++++++++ .../Api/NotificationTransformer.php | 25 ++++++- .../assets/js/components/NotificationCard.vue | 33 +++++++++- .../assets/js/components/PostComponent.vue | 12 +--- 6 files changed, 171 insertions(+), 12 deletions(-) create mode 100644 app/Observers/ModLogObserver.php diff --git a/app/Observers/ModLogObserver.php b/app/Observers/ModLogObserver.php new file mode 100644 index 000000000..52a2bdd0e --- /dev/null +++ b/app/Observers/ModLogObserver.php @@ -0,0 +1,66 @@ +load($modLog)->fanout(); + } + + /** + * Handle the mod log "updated" event. + * + * @param \App\ModLog $modLog + * @return void + */ + public function updated(ModLog $modLog) + { + ModLogService::boot()->load($modLog)->fanout(); + } + + /** + * Handle the mod log "deleted" event. + * + * @param \App\ModLog $modLog + * @return void + */ + public function deleted(ModLog $modLog) + { + ModLogService::boot()->load($modLog)->unfanout(); + } + + /** + * Handle the mod log "restored" event. + * + * @param \App\ModLog $modLog + * @return void + */ + public function restored(ModLog $modLog) + { + ModLogService::boot()->load($modLog)->fanout(); + } + + /** + * Handle the mod log "force deleted" event. + * + * @param \App\ModLog $modLog + * @return void + */ + public function forceDeleted(ModLog $modLog) + { + ModLogService::boot()->load($modLog)->unfanout(); + } +} diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index aa82eb674..8703f2668 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -5,6 +5,7 @@ namespace App\Providers; use App\Observers\{ AvatarObserver, NotificationObserver, + ModLogObserver, StatusHashtagObserver, UserObserver, UserFilterObserver, @@ -12,6 +13,7 @@ use App\Observers\{ use App\{ Avatar, Notification, + ModLog, StatusHashtag, User, UserFilter @@ -35,6 +37,7 @@ class AppServiceProvider extends ServiceProvider Avatar::observe(AvatarObserver::class); Notification::observe(NotificationObserver::class); + ModLog::observe(ModLogObserver::class); StatusHashtag::observe(StatusHashtagObserver::class); User::observe(UserObserver::class); UserFilter::observe(UserFilterObserver::class); diff --git a/app/Services/ModLogService.php b/app/Services/ModLogService.php index cdbf72129..e8e44465f 100644 --- a/app/Services/ModLogService.php +++ b/app/Services/ModLogService.php @@ -2,7 +2,9 @@ namespace App\Services; +use Auth; use App\ModLog; +use App\Notification; use App\User; class ModLogService { @@ -95,4 +97,46 @@ class ModLogService { return; } } + + public function load($modLog) + { + $this->log = $modLog; + return $this; + } + + public function fanout() + { + $log = $this->log; + + $msg = "{$log->user_username} commented on a modlog"; + $rendered = "{$log->user_username} commented on a modlog"; + $item_id = $log->id; + $item_type = 'App\ModLog'; + $action = 'admin.user.modlog.comment'; + + $admins = User::whereNull('status') + ->whereNotIn('id', [$log->user_id]) + ->whereIsAdmin(true) + ->pluck('profile_id') + ->toArray(); + + foreach($admins as $user) { + $n = new Notification; + $n->profile_id = $user; + $n->actor_id = $log->admin->profile_id; + $n->item_id = $item_id; + $n->item_type = $item_type; + $n->action = $action; + $n->message = $msg; + $n->rendered = $rendered; + $n->save(); + } + } + + public function unfanout() + { + Notification::whereItemType('App\ModLog') + ->whereItemId($this->log->id) + ->delete(); + } } \ No newline at end of file diff --git a/app/Transformer/Api/NotificationTransformer.php b/app/Transformer/Api/NotificationTransformer.php index c9616632d..7d0d9c5e4 100644 --- a/app/Transformer/Api/NotificationTransformer.php +++ b/app/Transformer/Api/NotificationTransformer.php @@ -13,7 +13,8 @@ class NotificationTransformer extends Fractal\TransformerAbstract protected $defaultIncludes = [ 'account', 'status', - 'relationship' + 'relationship', + 'modlog' ]; public function transform(Notification $notification) @@ -54,6 +55,7 @@ class NotificationTransformer extends Fractal\TransformerAbstract 'share' => 'share', 'like' => 'favourite', 'comment' => 'comment', + 'admin.user.modlog.comment' => 'modlog' ]; return $verbs[$verb]; } @@ -62,4 +64,25 @@ class NotificationTransformer extends Fractal\TransformerAbstract { return $this->item($notification->actor, new RelationshipTransformer()); } + + public function includeModlog(Notification $notification) + { + $n = $notification; + if($n->item_id && $n->item_type == 'App\ModLog') { + $ml = $n->item; + if(!empty($ml)) { + $res = $this->item($ml, function($ml) { + return [ + 'id' => $ml->object_uid, + 'url' => url('/i/admin/users/modlogs/' . $ml->object_uid) + ]; + }); + return $res; + } else { + return null; + } + } else { + return null; + } + } } diff --git a/resources/assets/js/components/NotificationCard.vue b/resources/assets/js/components/NotificationCard.vue index ad16298c8..1128178b6 100644 --- a/resources/assets/js/components/NotificationCard.vue +++ b/resources/assets/js/components/NotificationCard.vue @@ -4,7 +4,7 @@

- + Alerts

@@ -43,6 +43,11 @@ {{truncate(n.account.username)}} shared your post.

+
+

+ {{truncate(n.account.username)}} updated a modlog. +

+
{{timeAgo(n.created_at)}}
@@ -193,6 +198,32 @@ } }); }, interval); + }, + + refreshNotifications() { + let self = this; + axios.get('/api/pixelfed/v1/notifications') + .then(res => { + let data = res.data.filter(n => { + if(n.type == 'share' || self.notificationMaxId >= n.id) { + return false; + } + return true; + }); + if(data.length > 0) { + let ids = data.map(n => n.id); + let max = Math.max(ids); + if(max <= self.notificationMaxId) { + return; + } else { + self.notificationMaxId = max; + self.notifications = data; + let beep = new Audio('/static/beep.mp3'); + beep.volume = 0.7; + beep.play(); + } + } + }); } } } diff --git a/resources/assets/js/components/PostComponent.vue b/resources/assets/js/components/PostComponent.vue index edfe5cb53..9edc8ba86 100644 --- a/resources/assets/js/components/PostComponent.vue +++ b/resources/assets/js/components/PostComponent.vue @@ -675,9 +675,9 @@ export default { }, fetchData() { + let self = this; axios.get('/api/v2/profile/'+this.statusUsername+'/status/'+this.statusId) .then(response => { - let self = this; self.status = response.data.status; self.user = response.data.user; window._sharedData.curUser = self.user; @@ -696,15 +696,7 @@ export default { this.loaded = true; $('head title').text(this.status.account.username + ' posted a photo: ' + this.status.favourites_count + ' likes'); }).catch(error => { - if(!error.response) { - } else { - switch(error.response.status) { - case 401: - break; - default: - break; - } - } + swal('Oops!', 'An error occured, please try refreshing the page.', 'error'); }); },