diff --git a/app/Http/Controllers/Api/ApiV1Dot1Controller.php b/app/Http/Controllers/Api/ApiV1Dot1Controller.php index 82929fe68..3741390e2 100644 --- a/app/Http/Controllers/Api/ApiV1Dot1Controller.php +++ b/app/Http/Controllers/Api/ApiV1Dot1Controller.php @@ -29,6 +29,7 @@ use App\Services\NetworkTimelineService; use App\Services\NotificationAppGatewayService; use App\Services\ProfileStatusService; use App\Services\PublicTimelineService; +use App\Services\PushNotificationService; use App\Services\StatusService; use App\Services\UserStorageService; use App\Status; @@ -1020,14 +1021,20 @@ class ApiV1Dot1Controller extends Controller return $this->json($account, 200, $rateLimiting ? $limits : []); } - public function getExpoPushNotifications(Request $request) + public function getPushState(Request $request) { + abort_unless($request->hasHeader('X-PIXELFED-APP'), 404, 'Not found'); abort_if(! $request->user() || ! $request->user()->token(), 403); abort_unless($request->user()->tokenCan('push'), 403); - abort_unless(config('services.expo.access_token') && strlen(config('services.expo.access_token')) > 10, 404, 'Push notifications are not supported on this server.'); + abort_unless(NotificationAppGatewayService::enabled(), 404, 'Push notifications are not supported on this server.'); $user = $request->user(); + abort_if($user->status, 422, 'Cannot access this resource at this time'); $res = [ - 'expo_token' => (bool) $user->expo_token, + 'version' => PushNotificationService::PUSH_GATEWAY_VERSION, + 'username' => (string) $user->username, + 'profile_id' => (string) $user->profile_id, + 'notify_enabled' => (bool) $user->notify_enabled, + 'has_token' => (bool) $user->expo_token, 'notify_like' => (bool) $user->notify_like, 'notify_follow' => (bool) $user->notify_follow, 'notify_mention' => (bool) $user->notify_mention, @@ -1037,45 +1044,147 @@ class ApiV1Dot1Controller extends Controller return $this->json($res); } - public function disableExpoPushNotifications(Request $request) + public function disablePush(Request $request) { + abort_unless($request->hasHeader('X-PIXELFED-APP'), 404, 'Not found'); abort_if(! $request->user() || ! $request->user()->token(), 403); abort_unless($request->user()->tokenCan('push'), 403); - abort_unless(config('services.expo.access_token') && strlen(config('services.expo.access_token')) > 10, 404, 'Push notifications are not supported on this server.'); + abort_unless(NotificationAppGatewayService::enabled(), 404, 'Push notifications are not supported on this server.'); + abort_if($request->user()->status, 422, 'Cannot access this resource at this time'); + $request->user()->update([ + 'notify_enabled' => false, 'expo_token' => null, + 'notify_like' => false, + 'notify_follow' => false, + 'notify_mention' => false, + 'notify_comment' => false, ]); - return $this->json(['expo_token' => null]); + PushNotificationService::removeMemberFromAll($request->user()->profile_id); + + $user = $request->user(); + + return $this->json([ + 'version' => PushNotificationService::PUSH_GATEWAY_VERSION, + 'username' => (string) $user->username, + 'profile_id' => (string) $user->profile_id, + 'notify_enabled' => (bool) $user->notify_enabled, + 'has_token' => (bool) $user->expo_token, + 'notify_like' => (bool) $user->notify_like, + 'notify_follow' => (bool) $user->notify_follow, + 'notify_mention' => (bool) $user->notify_mention, + 'notify_comment' => (bool) $user->notify_comment, + ]); } - public function updateExpoPushNotifications(Request $request) + public function comparePush(Request $request) { + abort_unless($request->hasHeader('X-PIXELFED-APP'), 404, 'Not found'); abort_if(! $request->user() || ! $request->user()->token(), 403); abort_unless($request->user()->tokenCan('push'), 403); - abort_unless(config('services.expo.access_token') && strlen(config('services.expo.access_token')) > 10, 404, 'Push notifications are not supported on this server.'); + abort_unless(NotificationAppGatewayService::enabled(), 404, 'Push notifications are not supported on this server.'); + abort_if($request->user()->status, 422, 'Cannot access this resource at this time'); + $this->validate($request, [ 'expo_token' => ['required', ExpoPushToken::rule()], + ]); + + $user = $request->user(); + + if (empty($user->expo_token)) { + return $this->json([ + 'version' => PushNotificationService::PUSH_GATEWAY_VERSION, + 'username' => (string) $user->username, + 'profile_id' => (string) $user->profile_id, + 'notify_enabled' => (bool) $user->notify_enabled, + 'match' => false, + 'has_existing' => false, + ]); + } + + $token = $request->input('expo_token'); + $knownToken = $user->expo_token; + $match = hash_equals($knownToken, $token); + + return $this->json([ + 'version' => PushNotificationService::PUSH_GATEWAY_VERSION, + 'username' => (string) $user->username, + 'profile_id' => (string) $user->profile_id, + 'notify_enabled' => (bool) $user->notify_enabled, + 'match' => $match, + 'has_existing' => true, + ]); + } + + public function updatePush(Request $request) + { + abort_unless($request->hasHeader('X-PIXELFED-APP'), 404, 'Not found'); + abort_if(! $request->user() || ! $request->user()->token(), 403); + abort_unless($request->user()->tokenCan('push'), 403); + abort_unless(NotificationAppGatewayService::enabled(), 404, 'Push notifications are not supported on this server.'); + abort_if($request->user()->status, 422, 'Cannot access this resource at this time'); + + $this->validate($request, [ + 'notify_enabled' => 'required', + 'token' => ['required', ExpoPushToken::rule()], 'notify_like' => 'sometimes', 'notify_follow' => 'sometimes', 'notify_mention' => 'sometimes', 'notify_comment' => 'sometimes', ]); - $user = $request->user()->update([ - 'expo_token' => $request->input('expo_token'), - 'notify_like' => $request->has('notify_like') && $request->boolean('notify_like'), - 'notify_follow' => $request->has('notify_follow') && $request->boolean('notify_follow'), - 'notify_mention' => $request->has('notify_mention') && $request->boolean('notify_mention'), - 'notify_comment' => $request->has('notify_comment') && $request->boolean('notify_comment'), + $pid = $request->user()->profile_id; + abort_if(! $pid, 422, 'An error occured'); + $expoToken = $request->input('token'); + + $existing = User::where('profile_id', '!=', $pid)->whereExpoToken($expoToken)->count(); + abort_if($existing, 400, 'Push token is already used by another account'); + + $request->user()->update([ + 'notify_enabled' => $request->boolean('notify_enabled'), + 'expo_token' => $expoToken, ]); + if ($request->filled('notify_like')) { + $request->user()->update(['notify_like' => (bool) $request->boolean('notify_like')]); + $request->boolean('notify_like') == true ? + PushNotificationService::set('like', $pid) : + PushNotificationService::removeMember('like', $pid); + } + if ($request->filled('notify_follow')) { + $request->user()->update(['notify_follow' => (bool) $request->boolean('notify_follow')]); + $request->boolean('notify_follow') == true ? + PushNotificationService::set('follow', $pid) : + PushNotificationService::removeMember('follow', $pid); + } + if ($request->filled('notify_mention')) { + $request->user()->update(['notify_mention' => (bool) $request->boolean('notify_mention')]); + $request->boolean('notify_mention') == true ? + PushNotificationService::set('mention', $pid) : + PushNotificationService::removeMember('mention', $pid); + } + if ($request->filled('notify_comment')) { + $request->user()->update(['notify_comment' => (bool) $request->boolean('notify_comment')]); + $request->boolean('notify_comment') == true ? + PushNotificationService::set('comment', $pid) : + PushNotificationService::removeMember('comment', $pid); + } + + if ($request->boolean('notify_enabled') == false) { + PushNotificationService::removeMemberFromAll($request->user()->profile_id); + } + + $user = $request->user(); + $res = [ - 'expo_token' => (bool) $request->user()->expo_token, - 'notify_like' => (bool) $request->user()->notify_like, - 'notify_follow' => (bool) $request->user()->notify_follow, - 'notify_mention' => (bool) $request->user()->notify_mention, - 'notify_comment' => (bool) $request->user()->notify_comment, + 'version' => PushNotificationService::PUSH_GATEWAY_VERSION, + 'notify_enabled' => (bool) $user->notify_enabled, + 'has_token' => (bool) $user->expo_token, + 'notify_like' => (bool) $user->notify_like, + 'notify_follow' => (bool) $user->notify_follow, + 'notify_mention' => (bool) $user->notify_mention, + 'notify_comment' => (bool) $user->notify_comment, ]; return $this->json($res);