the browser-facing portion of osu!
at master 11 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 Tests\Libraries; 7 8use App\Events\NewPrivateNotificationEvent; 9use App\Exceptions\AuthorizationException; 10use App\Exceptions\VerificationRequiredException; 11use App\Jobs\Notifications\ChannelAnnouncement; 12use App\Libraries\Chat; 13use App\Mail\UserNotificationDigest; 14use App\Models\Chat\Channel; 15use App\Models\Chat\Message; 16use App\Models\OAuth\Client; 17use App\Models\User; 18use Event; 19use Exception; 20use Mail; 21use Queue; 22use Tests\TestCase; 23 24class ChatTest extends TestCase 25{ 26 /** 27 * @dataProvider createAnnouncementApiDataProvider 28 */ 29 public function testCreateAnnouncementApi(?string $group, bool $isApiRequest, bool $isAllowed) 30 { 31 $sender = User::factory()->withGroup($group)->create()->markSessionVerified(); 32 $users = User::factory()->count(2)->create(); 33 34 if ($isApiRequest) { 35 $client = Client::factory()->create(['user_id' => $sender]); 36 $token = $this->createToken($sender, ['chat.write'], $client); 37 $sender->withAccessToken($token); 38 } 39 40 if (!$isAllowed) { 41 $this->expectException(AuthorizationException::class); 42 } 43 44 $channel = $this->createAnnouncement($sender, $users->pluck('user_id')->toArray()); 45 46 if ($isAllowed) { 47 $this->assertTrue($channel->fresh()->exists()); 48 } 49 } 50 51 public function testCreateAnnouncementIncludesSender() 52 { 53 $sender = User::factory()->withGroup('announce')->create()->markSessionVerified(); 54 $user = User::factory()->create(); 55 56 $channel = $this->createAnnouncement($sender, [$user->getKey()]); 57 58 $this->assertTrue($channel->fresh()->users()->contains('user_id', $sender->getKey())); 59 } 60 61 public function testCreateAnnouncementSendsNotification() 62 { 63 Queue::fake(); 64 Event::fake(); 65 Mail::fake(); 66 67 $sender = User::factory()->withGroup('announce')->create()->markSessionVerified(); 68 $user = User::factory()->create(); 69 70 $this->createAnnouncement($sender, [$user->getKey()]); 71 72 Queue::assertPushed(ChannelAnnouncement::class); 73 $this->runFakeQueue(); 74 75 Event::assertDispatched(NewPrivateNotificationEvent::class); 76 77 $this->artisan('notifications:send-mail'); 78 $this->runFakeQueue(); 79 80 Mail::assertSent(UserNotificationDigest::class); 81 } 82 83 /** 84 * @dataProvider minPlaysDataProvider 85 */ 86 public function testMinPlaysSendMessage(?string $groupIdentifier, bool $hasMinPlays, bool $successful) 87 { 88 config_set('osu.user.min_plays_allow_verified_bypass', false); 89 config_set('osu.user.min_plays_for_posting', 2); 90 91 $playCount = $hasMinPlays ? null : 1; 92 93 $sender = User::factory()->withGroup($groupIdentifier)->withPlays($playCount)->create()->markSessionVerified(); 94 $channel = Channel::factory()->type('public')->create(); 95 $channel->addUser($sender); 96 97 $countChange = $successful ? 1 : 0; 98 99 $this->expectCountChange(fn () => Message::count(), $countChange); 100 101 if (!$successful) { 102 $this->expectException(AuthorizationException::class); 103 } 104 105 Chat::sendMessage($sender, $channel, 'test', false); 106 } 107 108 /** 109 * @dataProvider minPlaysDataProvider 110 */ 111 public function testMinPlaysSendPM(?string $groupIdentifier, bool $hasMinPlays, bool $successful) 112 { 113 config_set('osu.user.min_plays_allow_verified_bypass', false); 114 config_set('osu.user.min_plays_for_posting', 2); 115 116 $playCount = $hasMinPlays ? null : 1; 117 118 $sender = User::factory()->withGroup($groupIdentifier)->withPlays($playCount)->create()->markSessionVerified(); 119 $target = User::factory()->create(['pm_friends_only' => false]); 120 121 $countChange = $successful ? 1 : 0; 122 123 $this->expectCountChange(fn () => Channel::count(), $countChange); 124 $this->expectCountChange(fn () => Message::count(), $countChange); 125 126 if (!$successful) { 127 $this->expectException(AuthorizationException::class); 128 } 129 130 Chat::sendPrivateMessage($sender, $target, 'test message', false); 131 132 if ($successful) { 133 $this->assertInstanceOf(Channel::class, Channel::findPM($sender, $target)); 134 } 135 } 136 137 /** 138 * @dataProvider verifiedDataProvider 139 */ 140 public function testSendMessage(bool $verified, ?string $expectedException) 141 { 142 $sender = User::factory()->create(); 143 $channel = Channel::factory()->type('public')->create(); 144 $channel->addUser($sender); 145 146 if ($verified) { 147 $sender->markSessionVerified(); 148 } 149 150 if ($expectedException === null) { 151 $this->expectNotToPerformAssertions(); 152 } else { 153 $this->expectException($expectedException); 154 } 155 156 Chat::sendMessage($sender, $channel, 'test', false); 157 } 158 159 public function testSendPM() 160 { 161 $sender = User::factory()->create(); 162 $sender->markSessionVerified(); 163 $target = User::factory()->create(['pm_friends_only' => false]); 164 165 $this->expectCountChange(fn () => Channel::count(), 1); 166 $this->expectCountChange(fn () => Message::count(), 1); 167 168 Chat::sendPrivateMessage($sender, $target, 'test message', false); 169 170 $this->assertInstanceOf(Channel::class, Channel::findPM($sender, $target)); 171 } 172 173 /** 174 * @dataProvider sendPmFriendsOnlyGroupsDataProvider 175 */ 176 public function testSendPMFriendsOnly(?string $groupIdentifier, bool $successful) 177 { 178 $sender = User::factory()->withGroup($groupIdentifier)->create(); 179 $sender->markSessionVerified(); 180 $target = User::factory()->create(['pm_friends_only' => true]); 181 182 $countChange = $successful ? 1 : 0; 183 $this->expectCountChange(fn () => Channel::count(), $countChange); 184 $this->expectCountChange(fn () => Message::count(), $countChange); 185 186 try { 187 Chat::sendPrivateMessage($sender, $target, 'test message', false); 188 } catch (Exception $e) { 189 $savedException = $e; 190 } 191 192 $channel = Channel::findPM($sender, $target); 193 194 if ($successful) { 195 $this->assertNotNull($channel); 196 } else { 197 $this->assertNull($channel); 198 $this->assertSame( 199 osu_trans('authorization.chat.friends_only'), 200 $savedException->getMessage() 201 ); 202 } 203 } 204 205 /** 206 * @dataProvider sendPmSenderFriendsOnlyGroupsDataProvider 207 */ 208 public function testSendPmSenderFriendsOnly(?string $groupIdentifier) 209 { 210 $sender = User::factory()->withGroup($groupIdentifier)->create(['pm_friends_only' => true]); 211 $sender->markSessionVerified(); 212 $target = User::factory()->create(['pm_friends_only' => false]); 213 214 $this->expectCountChange(fn () => Channel::count(), 0); 215 $this->expectCountChange(fn () => Message::count(), 0); 216 217 try { 218 Chat::sendPrivateMessage($sender, $target, 'test message', false); 219 } catch (Exception $e) { 220 $savedException = $e; 221 } 222 223 $this->assertNull(Channel::findPM($sender, $target)); 224 $this->assertSame( 225 osu_trans('authorization.chat.receive_friends_only'), 226 $savedException->getMessage() 227 ); 228 } 229 230 public function testSendPMTooLongNotCreatingNewChannel() 231 { 232 $sender = User::factory()->create(); 233 $sender->markSessionVerified(); 234 $target = User::factory()->create(['pm_friends_only' => false]); 235 236 $this->expectCountChange(fn () => Channel::count(), 0); 237 $this->expectCountChange(fn () => Message::count(), 0); 238 239 $longMessage = str_repeat('a', $GLOBALS['cfg']['osu']['chat']['message_length_limit'] + 1); 240 241 try { 242 Chat::sendPrivateMessage($sender, $target, $longMessage, false); 243 } catch (Exception $e) { 244 $savedException = $e; 245 } 246 247 $this->assertNull(Channel::findPM($sender, $target)); 248 $this->assertSame( 249 osu_trans('api.error.chat.too_long'), 250 $savedException->getMessage() 251 ); 252 } 253 254 public function testSendPMSecondTime() 255 { 256 $sender = User::factory()->create(); 257 $sender->markSessionVerified(); 258 $target = User::factory()->create(['pm_friends_only' => false]); 259 260 Chat::sendPrivateMessage($sender, $target, 'test message', false); 261 262 $this->expectCountChange(fn () => Channel::count(), 0); 263 $this->expectCountChange(fn () => Message::count(), 1); 264 265 Chat::sendPrivateMessage($sender, $target, 'test message again', false); 266 } 267 268 public static function createAnnouncementApiDataProvider() 269 { 270 return [ 271 [null, false, false], 272 [null, true, false], 273 ['admin', false, true], 274 ['admin', true, false], 275 ['announce', false, true], 276 ['announce', true, true], // announce group retains its group permission with OAuth. 277 ['bng', false, false], 278 ['bng', true, false], 279 ['bot', false, false], 280 ['bot', true, false], 281 ['gmt', false, true], 282 ['gmt', true, false], 283 ['nat', false, true], 284 ['nat', true, false], 285 ]; 286 } 287 288 public static function minPlaysDataProvider() 289 { 290 return [ 291 'bot group with minplays' => ['bot', true, true], 292 'bot group without minplays' => ['bot', false, true], 293 'default group with minplays' => [null, true, true], 294 'default group without minplays' => [null, false, false], 295 ]; 296 } 297 298 public static function sendPmFriendsOnlyGroupsDataProvider() 299 { 300 return [ 301 ['admin', true], 302 ['bng', false], 303 ['bot', true], 304 ['gmt', true], 305 ['nat', true], 306 [null, false], 307 ]; 308 } 309 310 public static function sendPmSenderFriendsOnlyGroupsDataProvider() 311 { 312 return [ 313 // admin skip because OsuAuthorize skips the check when admin. 314 ['bng'], 315 ['bot'], 316 ['gmt'], 317 ['nat'], 318 [null], 319 ]; 320 } 321 322 public static function verifiedDataProvider() 323 { 324 return [ 325 [false, VerificationRequiredException::class], 326 [true, null], 327 ]; 328 } 329 330 private function createAnnouncement(User $sender, array $targetIds): Channel 331 { 332 return Chat::createAnnouncement($sender, [ 333 'channel' => [ 334 'description' => 'best', 335 'name' => 'announcements', 336 ], 337 'message' => 'test', 338 'target_ids' => $targetIds, 339 ]); 340 } 341}