1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* @author Nicolas CARPi <[email protected]> |
5
|
|
|
* @copyright 2012 Nicolas CARPi |
6
|
|
|
* @see https://www.elabftw.net Official website |
7
|
|
|
* @license AGPL-3.0 |
8
|
|
|
* @package elabftw |
9
|
|
|
*/ |
10
|
|
|
|
11
|
|
|
declare(strict_types=1); |
12
|
|
|
|
13
|
|
|
namespace Elabftw\Models; |
14
|
|
|
|
15
|
|
|
use Elabftw\Elabftw\Tools; |
16
|
|
|
use Elabftw\Enums\Action; |
17
|
|
|
use Elabftw\Exceptions\ImproperActionException; |
18
|
|
|
use Elabftw\Interfaces\QueryParamsInterface; |
19
|
|
|
use Elabftw\Models\Notifications\CommentCreated; |
20
|
|
|
use Elabftw\Params\CommentParam; |
21
|
|
|
use Elabftw\Traits\SetIdTrait; |
22
|
|
|
use Override; |
|
|
|
|
23
|
|
|
use PDO; |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* All about the comments |
27
|
|
|
*/ |
28
|
|
|
class Comments extends AbstractRest |
29
|
|
|
{ |
30
|
202 |
|
use SetIdTrait; |
31
|
|
|
|
32
|
202 |
|
protected int $immutable = 0; |
33
|
202 |
|
|
34
|
|
|
public function __construct(public AbstractEntity $Entity, ?int $id = null) |
|
|
|
|
35
|
|
|
{ |
36
|
1 |
|
parent::__construct(); |
37
|
|
|
$this->setId($id); |
38
|
1 |
|
} |
39
|
|
|
|
40
|
|
|
#[Override] |
41
|
2 |
|
public function getApiPath(): string |
42
|
|
|
{ |
43
|
2 |
|
return sprintf('%s%d/comments/', $this->Entity->getApiPath(), $this->Entity->id ?? 0); |
44
|
|
|
} |
45
|
|
|
|
46
|
2 |
|
#[Override] |
47
|
2 |
|
public function readOne(): array |
48
|
2 |
|
{ |
49
|
2 |
|
$this->Entity->canOrExplode('read'); |
50
|
2 |
|
$sql = 'SELECT ' . $this->Entity->entityType->value . "_comments.*, |
51
|
2 |
|
CONCAT(users.firstname, ' ', users.lastname) AS fullname, |
52
|
2 |
|
users.firstname, users.lastname, users.orcid, users.email |
53
|
|
|
FROM " . $this->Entity->entityType->value . '_comments |
54
|
|
|
LEFT JOIN users ON (' . $this->Entity->entityType->value . '_comments.userid = users.userid) |
55
|
173 |
|
WHERE ' . $this->Entity->entityType->value . '_comments.id = :id AND item_id = :item_id'; |
56
|
|
|
$req = $this->Db->prepare($sql); |
57
|
173 |
|
$req->bindParam(':id', $this->id, PDO::PARAM_INT); |
58
|
|
|
$req->bindParam(':item_id', $this->Entity->id, PDO::PARAM_INT); |
59
|
|
|
$this->Db->execute($req); |
60
|
173 |
|
return $this->Db->fetch($req); |
61
|
173 |
|
} |
62
|
173 |
|
|
63
|
173 |
|
#[Override] |
64
|
173 |
|
public function readAll(?QueryParamsInterface $queryParams = null): array |
65
|
173 |
|
{ |
66
|
|
|
$this->Entity->canOrExplode('read'); |
67
|
173 |
|
$sql = 'SELECT ' . $this->Entity->entityType->value . "_comments.*, |
68
|
|
|
CONCAT(users.firstname, ' ', users.lastname) AS fullname, |
69
|
|
|
users.firstname, users.lastname, users.orcid, users.email |
70
|
1 |
|
FROM " . $this->Entity->entityType->value . '_comments |
71
|
|
|
LEFT JOIN users ON (' . $this->Entity->entityType->value . '_comments.userid = users.userid) |
72
|
1 |
|
WHERE item_id = :id ORDER BY ' . $this->Entity->entityType->value . '_comments.created_at ASC'; |
73
|
1 |
|
$req = $this->Db->prepare($sql); |
74
|
|
|
$req->bindParam(':id', $this->Entity->id, PDO::PARAM_INT); |
75
|
|
|
$this->Db->execute($req); |
76
|
2 |
|
|
77
|
|
|
return $req->fetchAll(); |
78
|
2 |
|
} |
79
|
|
|
|
80
|
|
|
#[Override] |
81
|
1 |
|
public function patch(Action $action, array $params): array |
82
|
|
|
{ |
83
|
1 |
|
$this->update(new CommentParam($params['comment'])); |
84
|
1 |
|
return $this->readOne(); |
85
|
|
|
} |
86
|
1 |
|
|
87
|
1 |
|
#[Override] |
88
|
1 |
|
public function postAction(Action $action, array $reqBody): int |
89
|
1 |
|
{ |
90
|
1 |
|
return $this->create(new CommentParam($reqBody['comment'] ?? throw new ImproperActionException('Missing comment field.'))); |
91
|
1 |
|
} |
92
|
|
|
|
93
|
1 |
|
public function update(CommentParam $params): bool |
94
|
|
|
{ |
95
|
|
|
$this->Entity->canOrExplode('read'); |
96
|
1 |
|
$this->canWriteOrExplode(); |
97
|
|
|
// note: we're using a strict WHERE clause here to prevent writing comments from someone else |
98
|
1 |
|
$sql = 'UPDATE ' . $this->Entity->entityType->value . '_comments SET |
99
|
1 |
|
comment = :content |
100
|
1 |
|
WHERE id = :id AND userid = :userid AND item_id = :item_id'; |
101
|
1 |
|
$req = $this->Db->prepare($sql); |
102
|
1 |
|
$req->bindValue(':content', $params->getContent()); |
103
|
|
|
$req->bindParam(':id', $this->id, PDO::PARAM_INT); |
104
|
1 |
|
$req->bindParam(':userid', $this->Entity->Users->userData['userid'], PDO::PARAM_INT); |
105
|
|
|
$req->bindParam(':item_id', $this->Entity->id, PDO::PARAM_INT); |
106
|
|
|
|
107
|
2 |
|
return $this->Db->execute($req); |
108
|
|
|
} |
109
|
2 |
|
|
110
|
2 |
|
#[Override] |
111
|
2 |
|
public function destroy(): bool |
112
|
2 |
|
{ |
113
|
2 |
|
$this->canWriteOrExplode(); |
114
|
2 |
|
$sql = 'DELETE FROM ' . $this->Entity->entityType->value . '_comments WHERE id = :id AND userid = :userid AND item_id = :item_id'; |
115
|
|
|
$req = $this->Db->prepare($sql); |
116
|
2 |
|
$req->bindParam(':id', $this->id, PDO::PARAM_INT); |
117
|
2 |
|
$req->bindParam(':userid', $this->Entity->Users->userData['userid'], PDO::PARAM_INT); |
118
|
2 |
|
$req->bindParam(':item_id', $this->Entity->id, PDO::PARAM_INT); |
119
|
|
|
|
120
|
|
|
return $this->Db->execute($req); |
121
|
2 |
|
} |
122
|
|
|
|
123
|
|
|
public function create(CommentParam $params): int |
124
|
|
|
{ |
125
|
|
|
$sql = 'INSERT INTO ' . $this->Entity->entityType->value . '_comments(item_id, comment, userid, immutable) |
126
|
|
|
VALUES(:item_id, :content, :userid, :immutable)'; |
127
|
|
|
$req = $this->Db->prepare($sql); |
128
|
2 |
|
$req->bindParam(':item_id', $this->Entity->id, PDO::PARAM_INT); |
129
|
|
|
$req->bindValue(':content', $params->getContent()); |
130
|
2 |
|
$req->bindParam(':userid', $this->Entity->Users->userData['userid'], PDO::PARAM_INT); |
131
|
2 |
|
$req->bindParam(':immutable', $this->immutable, PDO::PARAM_INT); |
132
|
|
|
|
133
|
|
|
$this->Db->execute($req); |
134
|
|
|
$id = $this->Db->lastInsertId(); |
135
|
|
|
$this->createNotifications(); |
136
|
|
|
|
137
|
|
|
return $id; |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
protected function canWriteOrExplode(): void |
141
|
|
|
{ |
142
|
|
|
$comment = $this->readOne(); |
143
|
|
|
if ($comment['immutable'] === 1) { |
144
|
|
|
throw new ImproperActionException(Tools::error(true)); |
145
|
|
|
} |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
/** |
149
|
|
|
* Create a notification to all participants and owner |
150
|
|
|
*/ |
151
|
|
|
protected function createNotifications(): void |
152
|
|
|
{ |
153
|
|
|
$comments = $this->readAll(); |
154
|
|
|
$userids = array_values(array_unique(array_column($comments, 'userid'))); |
155
|
|
|
// add the owner |
156
|
|
|
$userids[] = $this->Entity->entityData['userid']; |
157
|
|
|
foreach ($userids as $userid) { |
158
|
|
|
// skip commenter |
159
|
|
|
if ($userid === $this->Entity->Users->userData['userid']) { |
160
|
|
|
continue; |
161
|
|
|
} |
162
|
|
|
/** @psalm-suppress PossiblyNullArgument */ |
163
|
|
|
$Notif = new CommentCreated($this->Entity->entityType->toPage(), $this->Entity->id, $this->Entity->Users->userData['userid']); |
164
|
|
|
$Notif->create($userid); |
165
|
|
|
} |
166
|
|
|
} |
167
|
|
|
} |
168
|
|
|
|
The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g.
excluded_paths: ["lib/*"]
, you can move it to the dependency path list as follows:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths