the browser-facing portion of osu!
at master 6.4 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\Http\Controllers\Chat\Channels; 7 8use App\Http\Controllers\Chat\Controller as BaseController; 9use App\Libraries\Chat; 10use App\Models\Chat\Channel; 11use App\Models\Chat\Message; 12use App\Transformers\Chat\MessageTransformer; 13use App\Transformers\UserCompactTransformer; 14 15/** 16 * @group Chat 17 */ 18class MessagesController extends BaseController 19{ 20 public function __construct() 21 { 22 $this->middleware('require-scopes:chat.read', ['only' => ['index']]); 23 $this->middleware('require-scopes:chat.write', ['only' => ['store']]); 24 25 parent::__construct(); 26 } 27 28 /** 29 * Get Channel Messages 30 * 31 * This endpoint returns the chat messages for a specific channel. 32 * 33 * --- 34 * 35 * ### Response Format 36 * 37 * Returns an array of [ChatMessage](#chatmessage) 38 * 39 * @urlParam channel integer required The ID of the channel to retrieve messages for 40 * @queryParam limit integer number of messages to return (max of 50) 41 * @queryParam since integer messages after the specified message id will be returned 42 * @queryParam until integer messages up to but not including the specified message id will be returned 43 * 44 * @response [ 45 * { 46 * "message_id": 9150005004, 47 * "sender_id": 2, 48 * "channel_id": 5, 49 * "timestamp": "2018-07-06T06:33:34+00:00", 50 * "content": "i am a lazerface", 51 * "is_action": 0, 52 * "sender": { 53 * "id": 2, 54 * "username": "peppy", 55 * "profile_colour": "#3366FF", 56 * "avatar_url": "https://a.ppy.sh/2?1519081077.png", 57 * "country_code": "AU", 58 * "is_active": true, 59 * "is_bot": false, 60 * "is_online": true, 61 * "is_supporter": true 62 * } 63 * }, 64 * { 65 * "message_id": 9150005005, 66 * "sender_id": 102, 67 * "channel_id": 5, 68 * "timestamp": "2018-07-06T06:33:42+00:00", 69 * "content": "uh ok then", 70 * "is_action": 0, 71 * "sender": { 72 * "id": 102, 73 * "username": "nekodex", 74 * "profile_colour": "#333333", 75 * "avatar_url": "https://a.ppy.sh/102?1500537068", 76 * "country_code": "AU", 77 * "is_active": true, 78 * "is_bot": false, 79 * "is_online": true, 80 * "is_supporter": true 81 * } 82 * } 83 * ] 84 */ 85 public function index($channelId) 86 { 87 [ 88 'limit' => $limit, 89 'return_object' => $returnObject, 90 'since' => $since, 91 'until' => $until, 92 ] = get_params(request()->all(), null, [ 93 'limit:int', 94 'return_object:bool', 95 'since:int', 96 'until:int', 97 ], ['null_missing' => true]); 98 99 $limit = \Number::clamp($limit ?? 50, 1, 50); 100 $user = auth()->user(); 101 102 $channel = Channel::findOrFail($channelId); 103 if (!$channel->hasUser($user)) { 104 abort(404); 105 } 106 107 if ($channel->isPM()) { 108 // restricted users should be treated as if they do not exist 109 if (optional($channel->pmTargetFor($user))->isRestricted()) { 110 abort(404); 111 } 112 } 113 114 $messages = $channel 115 ->messages() 116 ->with(['channel', 'sender']) 117 ->limit($limit); 118 119 if (present($since)) { 120 $messages = $messages->where('message_id', '>', $since) 121 ->orderBy('message_id', 'asc') 122 ->get(); 123 } else { 124 if (present($until)) { 125 $messages->where('message_id', '<', $until); 126 } 127 128 $messages = $messages->orderBy('message_id', 'desc')->get()->reverse(); 129 } 130 131 $messages = Message::filterBacklogs($channel, $messages); 132 133 if (!$returnObject) { 134 return json_collection( 135 $messages, 136 new MessageTransformer(), 137 ['sender'] 138 ); 139 } 140 141 return [ 142 'messages' => json_collection($messages, new MessageTransformer()), 143 // FIXME: messages with null used should be removed from db... 144 'users' => json_collection( 145 $messages->pluck('sender')->filter()->uniqueStrict('user_id')->values(), 146 new UserCompactTransformer() 147 ), 148 ]; 149 } 150 151 /** 152 * Send Message to Channel 153 * 154 * This endpoint returns the chat messages for a specific channel. 155 * 156 * --- 157 * 158 * ### Response Format 159 * 160 * The sent [ChatMessage](#chatmessage) 161 * 162 * <aside class="notice"> 163 * When sending a message, the <code>last_read_id</code> for the <a href='#chatchannel'>ChatChannel</a> is also updated to mark the new message as read. 164 * </aside> 165 * 166 * @urlParam channel integer required The `channel_id` of the channel to send message to 167 * 168 * @bodyParam message string required message to send 169 * @bodyParam is_action boolean required whether the message is an action 170 * 171 * @response { 172 * "message_id": 9150005004, 173 * "sender_id": 2, 174 * "channel_id": 5, 175 * "timestamp": "2018-07-06T06:33:34+00:00", 176 * "content": "i am a lazerface", 177 * "is_action": 0, 178 * "sender": { 179 * "id": 2, 180 * "username": "peppy", 181 * "profile_colour": "#3366FF", 182 * "avatar_url": "https://a.ppy.sh/2?1519081077.png", 183 * "country_code": "AU", 184 * "is_active": true, 185 * "is_bot": false, 186 * "is_online": true, 187 * "is_supporter": true 188 * } 189 * } 190 */ 191 public function store($channelId) 192 { 193 $params = get_params(request()->all(), null, [ 194 'is_action:bool', 195 'message', 196 'uuid', 197 ], ['null_missing' => true]); 198 199 $message = Chat::sendMessage( 200 auth()->user(), 201 Channel::findOrFail(get_int($channelId)), 202 $params['message'], 203 $params['is_action'] ?? false, 204 $params['uuid'] 205 ); 206 207 return json_item( 208 $message, 209 new MessageTransformer(), 210 ['sender'] 211 ); 212 } 213}