the browser-facing portion of osu!
at master 3.2 kB view raw
1<?php 2 3// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0. 4// See the LICENCE file in the repository root for full licence text. 5 6namespace App\Libraries; 7 8use App\Models\Chat\Channel; 9use App\Models\Chat\UserChannel; 10use App\Models\User; 11use App\Transformers\Chat\ChannelTransformer; 12use Ds\Map; 13use Ds\Set; 14use Illuminate\Support\Collection; 15 16class UserChannelList 17{ 18 private Collection $channels; 19 20 public function __construct(private User $user) 21 { 22 } 23 24 public function get() 25 { 26 $this->loadChannels(); 27 $this->preloadUsers(); 28 29 $filteredChannels = $this->channels->filter(fn (Channel $channel) => $channel->isVisibleFor($this->user)); 30 31 $transformer = ChannelTransformer::forUser($this->user); 32 33 return json_collection($filteredChannels, $transformer, ChannelTransformer::LISTING_INCLUDES); 34 } 35 36 public function getChannels(): Collection 37 { 38 if (!isset($this->channels)) { 39 $this->loadChannels(); 40 } 41 42 return $this->channels; 43 } 44 45 private function loadChannels() 46 { 47 $userChannels = UserChannel::where('user_id', $this->user->getKey()) 48 ->where('hidden', false) 49 ->whereHas('channel') 50 ->with('channel') 51 ->limit($GLOBALS['cfg']['osu']['chat']['channel_limit']) 52 ->get(); 53 54 foreach ($userChannels as $userChannel) { 55 // preset userChannel for getting last_read_id. 56 $userChannel->channel->setUserChannel($userChannel); 57 } 58 59 $this->channels = $userChannels->pluck('channel'); 60 } 61 62 private function preloadUsers() 63 { 64 // Getting user list; Limited to PM channels due to large size of public channels. 65 $userIds = new Set(); 66 $pmChannels = $this->channels->filter(fn ($channel) => $channel->isPM()); 67 foreach ($pmChannels as $channel) { 68 $userIds->add(...$channel->userIds()); 69 } 70 71 $users = User::default() 72 ->whereIn('user_id', $userIds->toArray()) 73 ->with([ 74 // only fetch data related to $user, to be used by ChatPmStart/ChatChannelCanMessage privilege check 75 'friends' => fn ($query) => $query->where('zebra_id', $this->user->getKey()), 76 'blocks' => fn ($query) => $query->where('zebra_id', $this->user->getKey()), 77 ]) 78 ->get(); 79 80 // If any channel users are blocked, preload the user groups of those users for the isModerator check. 81 $blockedIds = $users->pluck('user_id')->intersect($this->user->blocks->pluck('user_id')); 82 if ($blockedIds->isNotEmpty()) { 83 // Yes, the sql will look stupid. 84 $users->load(['userGroups' => fn ($query) => $query->whereIn('user_id', $blockedIds)]); 85 } 86 87 $usersMap = new Map(); 88 foreach ($users as $user) { 89 $usersMap->put($user->getKey(), $user); 90 } 91 92 foreach ($pmChannels as $channel) { 93 $channel->setPmUsers(array_map(fn ($id) => $usersMap->get($id, null), $channel->userIds())); 94 } 95 } 96}