Issues (186)

includes/Pages/PageEditComment.php (2 issues)

Severity
1
<?php
2
/******************************************************************************
3
 * Wikipedia Account Creation Assistance tool                                 *
4
 * ACC Development Team. Please see team.json for a list of contributors.     *
5
 *                                                                            *
6
 * This is free and unencumbered software released into the public domain.    *
7
 * Please see LICENSE.md for the full licencing statement.                    *
8
 ******************************************************************************/
9
10
namespace Waca\Pages;
11
12
use Exception;
13
use Waca\DataObjects\Comment;
14
use Waca\DataObjects\Request;
15
use Waca\DataObjects\User;
16
use Waca\Exceptions\AccessDeniedException;
17
use Waca\Exceptions\ApplicationLogicException;
18
use Waca\Helpers\Logger;
19
use Waca\SessionAlert;
20
use Waca\Tasks\InternalPageBase;
21
use Waca\WebRequest;
22
23
class PageEditComment extends InternalPageBase
24
{
25
    /**
26
     * Main function for this page, when no specific actions are called.
27
     * @throws ApplicationLogicException
28
     * @throws Exception
29
     */
30
    protected function main()
31
    {
32
        $commentId = WebRequest::getInt('id');
33
        if ($commentId === null) {
34
            throw new ApplicationLogicException('Comment ID not specified');
35
        }
36
37
        $database = $this->getDatabase();
38
39
        /** @var Comment|false $comment */
40
        $comment = Comment::getById($commentId, $database);
41
        if ($comment === false) {
0 ignored issues
show
The condition $comment === false is always false.
Loading history...
42
            throw new ApplicationLogicException('Comment not found');
43
        }
44
45
        $currentUser = User::getCurrent($database);
46
47
        $this->checkCommentAccess($comment, $currentUser);
48
49
        /** @var Request|false $request */
50
        $request = Request::getById($comment->getRequest(), $database);
51
52
        if ($request === false) {
0 ignored issues
show
The condition $request === false is always false.
Loading history...
53
            throw new ApplicationLogicException('Request was not found.');
54
        }
55
56
        $canUnflag = $this->barrierTest('unflag', $currentUser, PageFlagComment::class);
57
58
        if (WebRequest::wasPosted()) {
59
            $this->validateCSRFToken();
60
            $newComment = WebRequest::postString('newcomment');
61
            $visibility = WebRequest::postString('visibility');
62
            $doUnflag = WebRequest::postBoolean('unflag');
63
64
            if ($newComment === null || $newComment === '') {
65
                throw new ApplicationLogicException('Comment cannot be empty!');
66
            }
67
68
            $commentDataUnchanged = $newComment === $comment->getComment()
69
                && ($comment->getVisibility() === 'requester' || $comment->getVisibility() === $visibility);
70
            $flagStatusUnchanged = (!$canUnflag || $comment->getFlagged() && !$doUnflag);
71
72
            if ($commentDataUnchanged && $flagStatusUnchanged) {
73
                // No change was made; redirect back.
74
                $this->redirectBack($comment->getRequest());
75
76
                return;
77
            }
78
79
            // optimistically lock from the load of the edit comment form
80
            $updateVersion = WebRequest::postInt('updateversion');
81
82
            // comment data has changed, update the object
83
            if (!$commentDataUnchanged) {
84
                $this->updateCommentData($comment, $visibility, $newComment);
85
            }
86
87
            if ($doUnflag && $canUnflag) {
88
                $comment->setFlagged(false);
89
            }
90
91
            $comment->setUpdateVersion($updateVersion);
92
            $comment->save();
93
94
            if (!$commentDataUnchanged) {
95
                Logger::editComment($database, $comment, $request);
96
                $this->getNotificationHelper()->commentEdited($comment, $request);
97
            }
98
99
            if ($doUnflag && $canUnflag) {
100
                Logger::unflaggedComment($database, $comment, $request->getDomain());
101
            }
102
103
            SessionAlert::success('Comment has been saved successfully');
104
            $this->redirectBack($comment->getRequest());
105
        }
106
        else {
107
            $this->assignCSRFToken();
108
            $this->assign('comment', $comment);
109
            $this->assign('request', $request);
110
            $this->assign('user', User::getById($comment->getUser(), $database));
111
            $this->assign('canUnflag', $canUnflag);
112
            $this->setTemplate('edit-comment.tpl');
113
        }
114
    }
115
116
    /**
117
     * @throws AccessDeniedException
118
     */
119
    private function checkCommentAccess(Comment $comment, User $currentUser): void
120
    {
121
        if ($comment->getUser() !== $currentUser->getId() && !$this->barrierTest('editOthers', $currentUser)) {
122
            throw new AccessDeniedException($this->getSecurityManager(), $this->getDomainAccessManager());
123
        }
124
125
        $restrictedVisibility = $comment->getFlagged()
126
            || $comment->getVisibility() === 'admin'
127
            || $comment->getVisibility() === 'checkuser';
128
129
        if ($restrictedVisibility && !$this->barrierTest('alwaysSeePrivateData', $currentUser, 'RequestData')) {
130
            // Restricted visibility comments can only be seen if the user has a request reserved.
131
            /** @var Request $request */
132
            $request = Request::getById($comment->getRequest(), $comment->getDatabase());
133
134
            if ($request->getReserved() !== $currentUser->getId()) {
135
                throw new AccessDeniedException($this->getSecurityManager(), $this->getDomainAccessManager());
136
            }
137
        }
138
139
        if ($comment->getVisibility() === 'admin'
140
            && !$this->barrierTest('seeRestrictedComments', $currentUser, 'RequestData')
141
            && $comment->getUser() !== $currentUser->getId()) {
142
            throw new AccessDeniedException($this->getSecurityManager(), $this->getDomainAccessManager());
143
        }
144
145
        if ($comment->getVisibility() === 'checkuser'
146
            && !$this->barrierTest('seeCheckuserComments', $currentUser, 'RequestData')
147
            && $comment->getUser() !== $currentUser->getId()) {
148
            throw new AccessDeniedException($this->getSecurityManager(), $this->getDomainAccessManager());
149
        }
150
    }
151
152
    /**
153
     * @throws ApplicationLogicException
154
     */
155
    private function updateCommentData(Comment $comment, ?string $visibility, string $newComment): void
156
    {
157
        if ($comment->getVisibility() !== 'requester') {
158
            if ($visibility !== 'user' && $visibility !== 'admin' && $visibility !== 'checkuser') {
159
                throw new ApplicationLogicException('Comment visibility is not valid');
160
            }
161
162
            $comment->setVisibility($visibility);
163
        }
164
165
        $comment->setComment($newComment);
166
        $comment->touchEdited();
167
    }
168
169
    private function redirectBack(int $requestId): void
170
    {
171
        $source = WebRequest::getString('from');
172
173
        if ($source == 'flagged') {
174
            $this->redirect('flaggedComments');
175
        }
176
        else {
177
            $this->redirect('viewRequest', null, array('id' => $requestId));
178
        }
179
    }
180
}
181