the browser-facing portion of osu!
at master 6.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\Http\Controllers; 7 8use App\Exceptions\ModelNotSavedException; 9use App\Libraries\BeatmapsetDiscussion\Discussion; 10use App\Libraries\BeatmapsetDiscussion\Reply; 11use App\Libraries\BeatmapsetDiscussion\Review; 12use App\Libraries\BeatmapsetDiscussionPostsBundle; 13use App\Models\BeatmapDiscussion; 14use App\Models\BeatmapDiscussionPost; 15use App\Models\Beatmapset; 16use App\Models\BeatmapsetWatch; 17use App\Models\User; 18 19/** 20 * @group Beatmapset Discussions 21 */ 22class BeatmapDiscussionPostsController extends Controller 23{ 24 public function __construct() 25 { 26 $this->middleware('auth', ['except' => ['index', 'show']]); 27 $this->middleware('require-scopes:public', ['only' => ['index']]); 28 29 parent::__construct(); 30 } 31 32 public function destroy($id) 33 { 34 $post = BeatmapDiscussionPost::whereNull('deleted_at')->findOrFail($id); 35 priv_check('BeatmapDiscussionPostDestroy', $post)->ensureCan(); 36 37 try { 38 $post->softDeleteOrExplode(auth()->user()); 39 } catch (ModelNotSavedException $e) { 40 return error_popup($e->getMessage()); 41 } 42 43 return $post->beatmapset->defaultDiscussionJson(); 44 } 45 46 /** 47 * Get Beatmapset Discussion Posts 48 * 49 * Returns the posts of beatmapset discussions. 50 * 51 * --- 52 * 53 * ### Response Format 54 * 55 * <aside class="warning"> 56 * The response of this endpoint is likely to change soon! 57 * </aside> 58 * 59 * Field | Type | Description 60 * ------------- | ------------------------------------------------------- | ----------- 61 * beatmapsets | [Beatmapset](#beatmapset) | | 62 * cursor_string | [CursorString](#cursorstring) | | 63 * posts | [BeatmapsetDiscussionPost](#beatmapsetdiscussionpost)[] | | 64 * users | [User](#user) | | 65 * 66 * @queryParam beatmapset_discussion_id `id` of the [BeatmapsetDiscussion](#beatmapsetdiscussion). 67 * @queryParam limit Maximum number of results. 68 * @queryParam page Search result page. 69 * @queryParam sort `id_desc` for newest first; `id_asc` for oldest first. Defaults to `id_desc`. 70 * @queryParam types[] `first`, `reply`, `system` are the valid values. Defaults to `reply`. 71 * @queryParam user The `id` of the [User](#user). 72 * @queryParam with_deleted This param has no effect as api calls do not currently receive group permissions. 73 */ 74 public function index() 75 { 76 $bundle = new BeatmapsetDiscussionPostsBundle(request()->all()); 77 78 if (is_api_request()) { 79 return $bundle->toArray(); 80 } 81 82 $posts = $bundle->getPaginator(); 83 84 return ext_view('beatmap_discussion_posts.index', compact('posts')); 85 } 86 87 public function restore($id) 88 { 89 $post = BeatmapDiscussionPost::whereNotNull('deleted_at')->findOrFail($id); 90 priv_check('BeatmapDiscussionPostRestore', $post)->ensureCan(); 91 92 $post->restore(auth()->user()); 93 94 return $post->beatmapset->defaultDiscussionJson(); 95 } 96 97 public function show($id) 98 { 99 $post = BeatmapDiscussionPost::findOrFail($id); 100 $discussion = $post->beatmapDiscussion; 101 $beatmapset = $discussion->beatmapset; 102 103 if ($beatmapset === null) { 104 abort(404); 105 } 106 107 return ujs_redirect(route('beatmapsets.discussion', $beatmapset).'#/'.$discussion->getKey().'/'.$post->getKey()); 108 } 109 110 public function store() 111 { 112 /** @var User $user */ 113 $user = auth()->user(); 114 $request = request()->all(); 115 116 $discussionId = get_int($request['beatmap_discussion_id'] ?? null); 117 $beatmapsetId = get_int($request['beatmapset_id'] ?? null); 118 119 $message = presence(get_string($request['beatmap_discussion_post']['message'] ?? null)); 120 121 if ($discussionId !== null) { 122 $discussion = BeatmapDiscussion::findOrFail($discussionId); 123 $resolve = get_bool($request['beatmap_discussion']['resolved'] ?? null); 124 $posts = (new Reply($user, $discussion, $message, $resolve))->handle(); 125 126 $beatmapset = $discussion->beatmapset; 127 } elseif ($beatmapsetId !== null) { 128 $beatmapset = Beatmapset::findOrFail($beatmapsetId); 129 $discussionParams = get_params($request, 'beatmap_discussion', [ 130 'beatmap_id:int', 131 'message_type', 132 'timestamp:int', 133 ], ['null_missing' => true]); 134 135 [$discussion, $posts] = (new Discussion($user, $beatmapset, $discussionParams, $message))->handle(); 136 } else { 137 abort(404); 138 } 139 140 BeatmapsetWatch::markRead($beatmapset, $user); 141 142 return [ 143 'beatmapset' => $beatmapset->defaultDiscussionJson(), 144 'beatmap_discussion_post_ids' => array_pluck($posts, 'id'), 145 'beatmap_discussion_id' => $discussion->getKey(), 146 ]; 147 } 148 149 public function update($id) 150 { 151 $post = BeatmapDiscussionPost::findOrFail($id); 152 153 priv_check('BeatmapDiscussionPostEdit', $post)->ensureCan(); 154 155 $params = get_params(request()->all(), 'beatmap_discussion_post', ['message']); 156 $params['last_editor_id'] = auth()->user()->user_id; 157 158 if ($post->beatmapDiscussion->message_type === 'review' && $post->isFirstPost()) { 159 // handle reviews (but not replies to the reviews) 160 try { 161 $document = json_decode($params['message'], true); 162 Review::update($post->beatmapDiscussion, $document, auth()->user()); 163 } catch (\Exception $e) { 164 throw new ModelNotSavedException($e->getMessage()); 165 } 166 } else { 167 $post->fill($params)->saveOrExplode(); 168 } 169 170 return $post->beatmapset->defaultDiscussionJson(); 171 } 172}