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\Forum;
7
8use App\Exceptions\ModelNotSavedException;
9use App\Models\Forum\Post;
10use Auth;
11use DB;
12use Request;
13
14/**
15 * @group Forum
16 */
17class PostsController extends Controller
18{
19 public function __construct()
20 {
21 $this->middleware('auth', ['only' => [
22 'destroy',
23 'raw',
24 ]]);
25
26 $this->middleware('require-scopes:forum.write', ['only' => ['update']]);
27
28 parent::__construct();
29 }
30
31 public function destroy($id)
32 {
33 $post = Post::withTrashed()->findOrFail($id);
34
35 priv_check('ForumPostDelete', $post)->ensureCan();
36
37 DB::transaction(function () use ($post) {
38 if ((auth()->user()->user_id ?? null) !== $post->poster_id) {
39 $this->logModerate(
40 'LOG_DELETE_POST',
41 [$post->topic->topic_title],
42 $post
43 );
44 }
45
46 $post->deleteOrExplode();
47 });
48
49 return ext_view('forum.topics.delete', compact('post'), 'js');
50 }
51
52 public function restore($id)
53 {
54 $post = Post::withTrashed()->findOrFail($id);
55
56 priv_check('ForumModerate', $post->forum)->ensureCan();
57
58 DB::transaction(function () use ($post) {
59 $this->logModerate(
60 'LOG_RESTORE_POST',
61 [$post->topic->topic_title],
62 $post
63 );
64
65 if (!$post->restore()) {
66 throw new ModelNotSavedException($post->validationErrors()->toSentence());
67 }
68 });
69
70 return ext_view('forum.topics.restore', compact('post'), 'js');
71 }
72
73 public function edit($id)
74 {
75 $post = Post::withTrashed()->findOrFail($id);
76
77 priv_check('ForumPostEdit', $post)->ensureCan();
78
79 return ext_view('forum.posts.edit', compact('post'));
80 }
81
82 /**
83 * Edit Post
84 *
85 * Edit specified forum post.
86 *
87 * ---
88 *
89 * ### Response Format
90 *
91 * [ForumPost](#forum-post) with `body` included.
92 *
93 * @urlParam post integer required Id of the post. Example: 1
94 *
95 * @bodyParam body string required New post content in BBCode format. Example: hello
96 */
97 public function update($id)
98 {
99 $post = Post::withTrashed()->findOrFail($id);
100
101 priv_check('ForumPostEdit', $post)->ensureCan();
102
103 try {
104 DB::transaction(function () use ($post) {
105 $userId = Auth::user() === null ? null : Auth::user()->getKey();
106
107 if ($userId !== $post->poster_id) {
108 $this->logModerate(
109 'LOG_POST_EDITED',
110 [
111 $post->topic->topic_title,
112 $post->user->username,
113 ],
114 $post
115 );
116 }
117
118 $post
119 ->fill([
120 'post_text' => get_string(request('body')),
121 'post_edit_user' => $userId,
122 ])
123 ->saveOrExplode();
124 });
125 } catch (ModelNotSavedException $e) {
126 return error_popup($e->getMessage());
127 }
128
129 $post->refresh();
130
131 if (is_api_request()) {
132 return json_item($post, 'Forum\Post', ['body']);
133 }
134
135 return ext_view('forum.topics._posts', [
136 'posts' => collect([$post]),
137 'firstPostPosition' => $post->topic->postPosition($post->post_id),
138 'topic' => $post->topic,
139 ]);
140 }
141
142 public function raw($id)
143 {
144 $post = Post::withTrashed()->findOrFail($id);
145
146 if ($post->forum === null || $post->topic === null) {
147 abort(404);
148 }
149
150 if ($post->trashed() || $post->topic->trashed()) {
151 priv_check('ForumModerate', $post->forum)->ensureCan();
152 }
153
154 priv_check('ForumView', $post->forum)->ensureCan();
155
156 $text = $post->bodyRaw;
157
158 if (Request::input('quote') === '1') {
159 $text = sprintf("[quote=\"%s\"]\n%s\n[/quote]\n", $post->userNormalized()->username, $text);
160 }
161
162 return response($text)->header('Content-Type', 'text/plain');
163 }
164
165 public function show($id)
166 {
167 $post = Post::withTrashed()->findOrFail($id);
168
169 if ($post->trashed()) {
170 priv_check('ForumModerate', $post->forum)->ensureCan();
171 }
172
173 if ($post->forum === null || $post->topic === null) {
174 abort(404);
175 }
176
177 priv_check('ForumView', $post->forum)->ensureCan();
178
179 return ujs_redirect(post_url($post->topic_id, $post->post_id));
180 }
181}