1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace SilverStripe\Comments\Tests; |
4
|
|
|
|
5
|
|
|
use HTMLPurifier_Config; |
6
|
|
|
use HTMLPurifier; |
7
|
|
|
use ReflectionClass; |
8
|
|
|
use SilverStripe\Comments\Extensions\CommentsExtension; |
9
|
|
|
use SilverStripe\Comments\Model\Comment; |
10
|
|
|
use SilverStripe\Comments\Tests\Stubs\CommentableItem; |
11
|
|
|
use SilverStripe\Comments\Tests\Stubs\CommentableItemDisabled; |
12
|
|
|
use SilverStripe\Comments\Tests\Stubs\CommentableItemEnabled; |
13
|
|
|
use SilverStripe\Control\Controller; |
14
|
|
|
use SilverStripe\Control\Director; |
15
|
|
|
use SilverStripe\Core\Config\Config; |
16
|
|
|
use SilverStripe\Core\Email\Email; |
17
|
|
|
use SilverStripe\Dev\FunctionalTest; |
18
|
|
|
use SilverStripe\Dev\TestOnly; |
19
|
|
|
use SilverStripe\i18n\i18n; |
20
|
|
|
use SilverStripe\ORM\DataObject; |
21
|
|
|
use SilverStripe\Security\Member; |
22
|
|
|
use SilverStripe\Security\Security; |
23
|
|
|
use SilverStripe\Security\Permission; |
24
|
|
|
|
25
|
|
|
class CommentsTest extends FunctionalTest |
26
|
|
|
{ |
27
|
|
|
protected static $fixture_file = 'CommentsTest.yml'; |
28
|
|
|
|
29
|
|
|
protected static $extra_dataobjects = array( |
30
|
|
|
CommentableItem::class, |
31
|
|
|
CommentableItemEnabled::class, |
32
|
|
|
CommentableItemDisabled::class |
33
|
|
|
); |
34
|
|
|
|
35
|
|
|
public function setUp() |
36
|
|
|
{ |
37
|
|
|
parent::setUp(); |
38
|
|
|
|
39
|
|
|
// Set good default values |
40
|
|
|
Config::modify()->merge(CommentsExtension::class, 'comments', array( |
41
|
|
|
'enabled' => true, |
42
|
|
|
'comment_permalink_prefix' => 'comment-' |
43
|
|
|
)); |
44
|
|
|
} |
45
|
|
|
|
46
|
|
|
public function testCommentsList() |
47
|
|
|
{ |
48
|
|
|
// comments don't require moderation so unmoderated comments can be |
49
|
|
|
// shown but not spam posts |
50
|
|
|
Config::modify()->merge(CommentableItem::class, 'comments', array( |
51
|
|
|
'require_moderation_nonmembers' => false, |
52
|
|
|
'require_moderation' => false, |
53
|
|
|
'require_moderation_cms' => false, |
54
|
|
|
)); |
55
|
|
|
|
56
|
|
|
$item = $this->objFromFixture(CommentableItem::class, 'spammed'); |
57
|
|
|
|
58
|
|
|
$this->assertDOSEquals(array( |
59
|
|
|
array('Name' => 'Comment 1'), |
60
|
|
|
array('Name' => 'Comment 3') |
61
|
|
|
), $item->Comments(), 'Only 2 non spam posts should be shown'); |
|
|
|
|
62
|
|
|
|
63
|
|
|
// when moderated, only moderated, non spam posts should be shown. |
64
|
|
|
Config::modify()->merge(CommentableItem::class, 'comments', array('require_moderation_nonmembers' => true)); |
65
|
|
|
|
66
|
|
|
// Check that require_moderation overrides this option |
67
|
|
|
Config::modify()->merge(CommentableItem::class, 'comments', array('require_moderation' => true)); |
68
|
|
|
|
69
|
|
|
$this->assertDOSEquals(array( |
70
|
|
|
array('Name' => 'Comment 3') |
71
|
|
|
), $item->Comments(), 'Only 1 non spam, moderated post should be shown'); |
|
|
|
|
72
|
|
|
$this->assertEquals(1, $item->Comments()->Count()); |
73
|
|
|
|
74
|
|
|
// require_moderation_nonmembers still filters out unmoderated comments |
75
|
|
|
Config::modify()->merge(CommentableItem::class, 'comments', array('require_moderation' => false)); |
76
|
|
|
$this->assertEquals(1, $item->Comments()->Count()); |
77
|
|
|
|
78
|
|
|
Config::modify()->merge(CommentableItem::class, 'comments', array('require_moderation_nonmembers' => false)); |
79
|
|
|
$this->assertEquals(2, $item->Comments()->Count()); |
80
|
|
|
|
81
|
|
|
// With unmoderated comments set to display in frontend |
82
|
|
|
Config::modify()->merge(CommentableItem::class, 'comments', array( |
83
|
|
|
'require_moderation' => true, |
84
|
|
|
'frontend_moderation' => true |
85
|
|
|
)); |
86
|
|
|
$this->assertEquals(1, $item->Comments()->Count()); |
87
|
|
|
|
88
|
|
|
$this->logInWithPermission('ADMIN'); |
89
|
|
|
$this->assertEquals(2, $item->Comments()->Count()); |
90
|
|
|
|
91
|
|
|
// With spam comments set to display in frontend |
92
|
|
|
Config::modify()->merge(CommentableItem::class, 'comments', array( |
93
|
|
|
'require_moderation' => true, |
94
|
|
|
'frontend_moderation' => false, |
95
|
|
|
'frontend_spam' => true, |
96
|
|
|
)); |
97
|
|
|
if ($member = Member::currentUser()) { |
|
|
|
|
98
|
|
|
$member->logOut(); |
|
|
|
|
99
|
|
|
} |
100
|
|
|
$this->assertEquals(1, $item->Comments()->Count()); |
101
|
|
|
|
102
|
|
|
$this->logInWithPermission('ADMIN'); |
103
|
|
|
$this->assertEquals(2, $item->Comments()->Count()); |
104
|
|
|
|
105
|
|
|
|
106
|
|
|
// With spam and unmoderated comments set to display in frontend |
107
|
|
|
Config::modify()->merge(CommentableItem::class, 'comments', array( |
108
|
|
|
'require_moderation' => true, |
109
|
|
|
'frontend_moderation' => true, |
110
|
|
|
'frontend_spam' => true, |
111
|
|
|
)); |
112
|
|
|
if ($member = Member::currentUser()) { |
|
|
|
|
113
|
|
|
$member->logOut(); |
|
|
|
|
114
|
|
|
} |
115
|
|
|
$this->assertEquals(1, $item->Comments()->Count()); |
116
|
|
|
|
117
|
|
|
$this->logInWithPermission('ADMIN'); |
118
|
|
|
$this->assertEquals(4, $item->Comments()->Count()); |
119
|
|
|
} |
120
|
|
|
|
121
|
|
|
/** |
122
|
|
|
* Test moderation options configured via the CMS |
123
|
|
|
*/ |
124
|
|
|
public function testCommentCMSModerationList() |
125
|
|
|
{ |
126
|
|
|
Config::modify()->merge(CommentableItem::class, 'comments', array( |
127
|
|
|
'require_moderation' => true, |
128
|
|
|
'require_moderation_cms' => true, |
129
|
|
|
)); |
130
|
|
|
|
131
|
|
|
$item = $this->objFromFixture(CommentableItem::class, 'spammed'); |
132
|
|
|
|
133
|
|
|
$this->assertEquals('None', $item->getModerationRequired()); |
134
|
|
|
|
135
|
|
|
$this->assertDOSEquals(array( |
136
|
|
|
array('Name' => 'Comment 1'), |
137
|
|
|
array('Name' => 'Comment 3') |
138
|
|
|
), $item->Comments(), 'Only 2 non spam posts should be shown'); |
|
|
|
|
139
|
|
|
|
140
|
|
|
// when moderated, only moderated, non spam posts should be shown. |
141
|
|
|
$item->ModerationRequired = 'NonMembersOnly'; |
142
|
|
|
$item->write(); |
143
|
|
|
|
144
|
|
|
$this->assertEquals('NonMembersOnly', $item->getModerationRequired()); |
145
|
|
|
|
146
|
|
|
// Check that require_moderation overrides this option |
147
|
|
|
$item->ModerationRequired = 'Required'; |
148
|
|
|
$item->write(); |
149
|
|
|
$this->assertEquals('Required', $item->getModerationRequired()); |
150
|
|
|
|
151
|
|
|
$this->assertDOSEquals(array( |
152
|
|
|
array('Name' => 'Comment 3') |
153
|
|
|
), $item->Comments(), 'Only 1 non spam, moderated post should be shown'); |
|
|
|
|
154
|
|
|
$this->assertEquals(1, $item->Comments()->Count()); |
155
|
|
|
|
156
|
|
|
// require_moderation_nonmembers still filters out unmoderated comments |
157
|
|
|
$item->ModerationRequired = 'NonMembersOnly'; |
158
|
|
|
$item->write(); |
159
|
|
|
$this->assertEquals(1, $item->Comments()->Count()); |
160
|
|
|
|
161
|
|
|
$item->ModerationRequired = 'None'; |
162
|
|
|
$item->write(); |
163
|
|
|
$this->assertEquals(2, $item->Comments()->Count()); |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
public function testCanPostComment() |
167
|
|
|
{ |
168
|
|
|
Config::modify()->merge(CommentableItem::class, 'comments', array( |
169
|
|
|
'require_login' => false, |
170
|
|
|
'require_login_cms' => false, |
171
|
|
|
'required_permission' => false, |
172
|
|
|
)); |
173
|
|
|
$item = $this->objFromFixture(CommentableItem::class, 'first'); |
174
|
|
|
$item2 = $this->objFromFixture(CommentableItem::class, 'second'); |
175
|
|
|
|
176
|
|
|
// Test restriction free commenting |
177
|
|
|
if ($member = Member::currentUser()) { |
|
|
|
|
178
|
|
|
$member->logOut(); |
|
|
|
|
179
|
|
|
} |
180
|
|
|
$this->assertFalse($item->CommentsRequireLogin); |
181
|
|
|
$this->assertTrue($item->canPostComment()); |
182
|
|
|
|
183
|
|
|
// Test permission required to post |
184
|
|
|
Config::modify()->merge(CommentableItem::class, 'comments', array( |
185
|
|
|
'require_login' => true, |
186
|
|
|
'required_permission' => 'POSTING_PERMISSION', |
187
|
|
|
)); |
188
|
|
|
$this->assertTrue($item->CommentsRequireLogin); |
189
|
|
|
$this->assertFalse($item->canPostComment()); |
190
|
|
|
$this->logInWithPermission('WRONG_ONE'); |
191
|
|
|
$this->assertFalse($item->canPostComment()); |
192
|
|
|
$this->logInWithPermission('POSTING_PERMISSION'); |
193
|
|
|
$this->assertTrue($item->canPostComment()); |
194
|
|
|
$this->logInWithPermission('ADMIN'); |
195
|
|
|
$this->assertTrue($item->canPostComment()); |
196
|
|
|
|
197
|
|
|
// Test require login to post, but not any permissions |
198
|
|
|
Config::modify()->merge(CommentableItem::class, 'comments', array( |
199
|
|
|
'required_permission' => false, |
200
|
|
|
)); |
201
|
|
|
$this->assertTrue($item->CommentsRequireLogin); |
202
|
|
|
if ($member = Member::currentUser()) { |
|
|
|
|
203
|
|
|
$member->logOut(); |
|
|
|
|
204
|
|
|
} |
205
|
|
|
$this->assertFalse($item->canPostComment()); |
206
|
|
|
$this->logInWithPermission('ANY_PERMISSION'); |
207
|
|
|
$this->assertTrue($item->canPostComment()); |
208
|
|
|
|
209
|
|
|
// Test options set via CMS |
210
|
|
|
Config::modify()->merge(CommentableItem::class, 'comments', array( |
211
|
|
|
'require_login' => true, |
212
|
|
|
'require_login_cms' => true, |
213
|
|
|
)); |
214
|
|
|
$this->assertFalse($item->CommentsRequireLogin); |
215
|
|
|
$this->assertTrue($item2->CommentsRequireLogin); |
216
|
|
|
if ($member = Member::currentUser()) { |
|
|
|
|
217
|
|
|
$member->logOut(); |
|
|
|
|
218
|
|
|
} |
219
|
|
|
$this->assertTrue($item->canPostComment()); |
220
|
|
|
$this->assertFalse($item2->canPostComment()); |
221
|
|
|
|
222
|
|
|
// Login grants permission to post |
223
|
|
|
$this->logInWithPermission('ANY_PERMISSION'); |
224
|
|
|
$this->assertTrue($item->canPostComment()); |
225
|
|
|
$this->assertTrue($item2->canPostComment()); |
226
|
|
|
} |
227
|
|
|
public function testDeleteComment() |
228
|
|
|
{ |
229
|
|
|
// Test anonymous user |
230
|
|
|
if ($member = Member::currentUser()) { |
|
|
|
|
231
|
|
|
$member->logOut(); |
|
|
|
|
232
|
|
|
} |
233
|
|
|
$comment = $this->objFromFixture(Comment::class, 'firstComA'); |
234
|
|
|
$commentID = $comment->ID; |
235
|
|
|
$this->assertNull($comment->DeleteLink(), 'No permission to see delete link'); |
236
|
|
|
$delete = $this->get('comments/delete/' . $comment->ID . '?ajax=1'); |
237
|
|
|
$this->assertEquals(403, $delete->getStatusCode()); |
238
|
|
|
$check = DataObject::get_by_id(Comment::class, $commentID); |
239
|
|
|
$this->assertTrue($check && $check->exists()); |
240
|
|
|
|
241
|
|
|
// Test non-authenticated user |
242
|
|
|
$this->logInAs('visitor'); |
243
|
|
|
$this->assertNull($comment->DeleteLink(), 'No permission to see delete link'); |
244
|
|
|
|
245
|
|
|
// Test authenticated user |
246
|
|
|
$this->logInAs('commentadmin'); |
247
|
|
|
$comment = $this->objFromFixture(Comment::class, 'firstComA'); |
248
|
|
|
$commentID = $comment->ID; |
249
|
|
|
$adminComment1Link = $comment->DeleteLink(); |
250
|
|
|
$this->assertContains('comments/delete/' . $commentID . '?t=', $adminComment1Link); |
251
|
|
|
|
252
|
|
|
// Test that this link can't be shared / XSS exploited |
253
|
|
|
$this->logInAs('commentadmin2'); |
254
|
|
|
$delete = $this->get($adminComment1Link); |
255
|
|
|
$this->assertEquals(400, $delete->getStatusCode()); |
256
|
|
|
$check = DataObject::get_by_id(Comment::class, $commentID); |
257
|
|
|
$this->assertTrue($check && $check->exists()); |
258
|
|
|
|
259
|
|
|
// Test that this other admin can delete the comment with their own link |
260
|
|
|
$adminComment2Link = $comment->DeleteLink(); |
261
|
|
|
$this->assertNotEquals($adminComment2Link, $adminComment1Link); |
262
|
|
|
$this->autoFollowRedirection = false; |
263
|
|
|
$delete = $this->get($adminComment2Link); |
264
|
|
|
$this->assertEquals(302, $delete->getStatusCode()); |
265
|
|
|
$check = DataObject::get_by_id(Comment::class, $commentID); |
266
|
|
|
$this->assertFalse($check && $check->exists()); |
267
|
|
|
} |
268
|
|
|
|
269
|
|
View Code Duplication |
public function testSpamComment() |
|
|
|
|
270
|
|
|
{ |
271
|
|
|
// Test anonymous user |
272
|
|
|
if ($member = Member::currentUser()) { |
|
|
|
|
273
|
|
|
$member->logOut(); |
|
|
|
|
274
|
|
|
} |
275
|
|
|
$comment = $this->objFromFixture(Comment::class, 'firstComA'); |
276
|
|
|
$commentID = $comment->ID; |
277
|
|
|
$this->assertNull($comment->SpamLink(), 'No permission to see mark as spam link'); |
278
|
|
|
$spam = $this->get('comments/spam/'.$comment->ID.'?ajax=1'); |
279
|
|
|
$this->assertEquals(403, $spam->getStatusCode()); |
280
|
|
|
$check = DataObject::get_by_id(Comment::class, $commentID); |
281
|
|
|
$this->assertEquals(0, $check->IsSpam, 'No permission to mark as spam'); |
282
|
|
|
|
283
|
|
|
// Test non-authenticated user |
284
|
|
|
$this->logInAs('visitor'); |
285
|
|
|
$this->assertNull($comment->SpamLink(), 'No permission to see mark as spam link'); |
286
|
|
|
|
287
|
|
|
// Test authenticated user |
288
|
|
|
$this->logInAs('commentadmin'); |
289
|
|
|
$comment = $this->objFromFixture(Comment::class, 'firstComA'); |
290
|
|
|
$commentID = $comment->ID; |
291
|
|
|
$adminComment1Link = $comment->SpamLink(); |
292
|
|
|
$this->assertContains('comments/spam/' . $commentID . '?t=', $adminComment1Link); |
293
|
|
|
|
294
|
|
|
// Test that this link can't be shared / XSS exploited |
295
|
|
|
$this->logInAs('commentadmin2'); |
296
|
|
|
$spam = $this->get($adminComment1Link); |
297
|
|
|
$this->assertEquals(400, $spam->getStatusCode()); |
298
|
|
|
$check = DataObject::get_by_id(Comment::class, $comment->ID); |
299
|
|
|
$this->assertEquals(0, $check->IsSpam, 'No permission to mark as spam'); |
300
|
|
|
|
301
|
|
|
// Test that this other admin can spam the comment with their own link |
302
|
|
|
$adminComment2Link = $comment->SpamLink(); |
303
|
|
|
$this->assertNotEquals($adminComment2Link, $adminComment1Link); |
304
|
|
|
$this->autoFollowRedirection = false; |
305
|
|
|
$spam = $this->get($adminComment2Link); |
306
|
|
|
$this->assertEquals(302, $spam->getStatusCode()); |
307
|
|
|
$check = DataObject::get_by_id(Comment::class, $commentID); |
308
|
|
|
$this->assertEquals(1, $check->IsSpam); |
309
|
|
|
|
310
|
|
|
// Cannot re-spam spammed comment |
311
|
|
|
$this->assertNull($check->SpamLink()); |
312
|
|
|
} |
313
|
|
|
|
314
|
|
View Code Duplication |
public function testHamComment() |
|
|
|
|
315
|
|
|
{ |
316
|
|
|
// Test anonymous user |
317
|
|
|
if ($member = Member::currentUser()) { |
|
|
|
|
318
|
|
|
$member->logOut(); |
|
|
|
|
319
|
|
|
} |
320
|
|
|
$comment = $this->objFromFixture(Comment::class, 'secondComC'); |
321
|
|
|
$commentID = $comment->ID; |
322
|
|
|
$this->assertNull($comment->HamLink(), 'No permission to see mark as ham link'); |
323
|
|
|
$ham = $this->get('comments/ham/' . $comment->ID . '?ajax=1'); |
324
|
|
|
$this->assertEquals(403, $ham->getStatusCode()); |
325
|
|
|
$check = DataObject::get_by_id(Comment::class, $commentID); |
326
|
|
|
$this->assertEquals(1, $check->IsSpam, 'No permission to mark as ham'); |
327
|
|
|
|
328
|
|
|
// Test non-authenticated user |
329
|
|
|
$this->logInAs('visitor'); |
330
|
|
|
$this->assertNull($comment->HamLink(), 'No permission to see mark as ham link'); |
331
|
|
|
|
332
|
|
|
// Test authenticated user |
333
|
|
|
$this->logInAs('commentadmin'); |
334
|
|
|
$comment = $this->objFromFixture(Comment::class, 'secondComC'); |
335
|
|
|
$commentID = $comment->ID; |
336
|
|
|
$adminComment1Link = $comment->HamLink(); |
337
|
|
|
$this->assertContains('comments/ham/' . $commentID . '?t=', $adminComment1Link); |
338
|
|
|
|
339
|
|
|
// Test that this link can't be shared / XSS exploited |
340
|
|
|
$this->logInAs('commentadmin2'); |
341
|
|
|
$ham = $this->get($adminComment1Link); |
342
|
|
|
$this->assertEquals(400, $ham->getStatusCode()); |
343
|
|
|
$check = DataObject::get_by_id(Comment::class, $comment->ID); |
344
|
|
|
$this->assertEquals(1, $check->IsSpam, 'No permission to mark as ham'); |
345
|
|
|
|
346
|
|
|
// Test that this other admin can ham the comment with their own link |
347
|
|
|
$adminComment2Link = $comment->HamLink(); |
348
|
|
|
$this->assertNotEquals($adminComment2Link, $adminComment1Link); |
349
|
|
|
$this->autoFollowRedirection = false; |
350
|
|
|
$ham = $this->get($adminComment2Link); |
351
|
|
|
$this->assertEquals(302, $ham->getStatusCode()); |
352
|
|
|
$check = DataObject::get_by_id(Comment::class, $commentID); |
353
|
|
|
$this->assertEquals(0, $check->IsSpam); |
354
|
|
|
|
355
|
|
|
// Cannot re-ham hammed comment |
356
|
|
|
$this->assertNull($check->HamLink()); |
357
|
|
|
} |
358
|
|
|
|
359
|
|
View Code Duplication |
public function testApproveComment() |
|
|
|
|
360
|
|
|
{ |
361
|
|
|
// Test anonymous user |
362
|
|
|
if ($member = Member::currentUser()) { |
|
|
|
|
363
|
|
|
$member->logOut(); |
|
|
|
|
364
|
|
|
} |
365
|
|
|
$comment = $this->objFromFixture(Comment::class, 'secondComB'); |
366
|
|
|
$commentID = $comment->ID; |
367
|
|
|
$this->assertNull($comment->ApproveLink(), 'No permission to see approve link'); |
368
|
|
|
$approve = $this->get('comments/approve/' . $comment->ID . '?ajax=1'); |
369
|
|
|
$this->assertEquals(403, $approve->getStatusCode()); |
370
|
|
|
$check = DataObject::get_by_id(Comment::class, $commentID); |
371
|
|
|
$this->assertEquals(0, $check->Moderated, 'No permission to approve'); |
372
|
|
|
|
373
|
|
|
// Test non-authenticated user |
374
|
|
|
$this->logInAs('visitor'); |
375
|
|
|
$this->assertNull($comment->ApproveLink(), 'No permission to see approve link'); |
376
|
|
|
|
377
|
|
|
// Test authenticated user |
378
|
|
|
$this->logInAs('commentadmin'); |
379
|
|
|
$comment = $this->objFromFixture(Comment::class, 'secondComB'); |
380
|
|
|
$commentID = $comment->ID; |
381
|
|
|
$adminComment1Link = $comment->ApproveLink(); |
382
|
|
|
$this->assertContains('comments/approve/' . $commentID . '?t=', $adminComment1Link); |
383
|
|
|
|
384
|
|
|
// Test that this link can't be shared / XSS exploited |
385
|
|
|
$this->logInAs('commentadmin2'); |
386
|
|
|
$approve = $this->get($adminComment1Link); |
387
|
|
|
$this->assertEquals(400, $approve->getStatusCode()); |
388
|
|
|
$check = DataObject::get_by_id(Comment::class, $comment->ID); |
389
|
|
|
$this->assertEquals(0, $check->Moderated, 'No permission to approve'); |
390
|
|
|
|
391
|
|
|
// Test that this other admin can approve the comment with their own link |
392
|
|
|
$adminComment2Link = $comment->ApproveLink(); |
393
|
|
|
$this->assertNotEquals($adminComment2Link, $adminComment1Link); |
394
|
|
|
$this->autoFollowRedirection = false; |
395
|
|
|
$approve = $this->get($adminComment2Link); |
396
|
|
|
$this->assertEquals(302, $approve->getStatusCode()); |
397
|
|
|
$check = DataObject::get_by_id(Comment::class, $commentID); |
398
|
|
|
$this->assertEquals(1, $check->Moderated); |
399
|
|
|
|
400
|
|
|
// Cannot re-approve approved comment |
401
|
|
|
$this->assertNull($check->ApproveLink()); |
402
|
|
|
} |
403
|
|
|
|
404
|
|
|
public function testCommenterURLWrite() |
405
|
|
|
{ |
406
|
|
|
$comment = new Comment(); |
407
|
|
|
// We only care about the CommenterURL, so only set that |
408
|
|
|
// Check a http and https URL. Add more test urls here as needed. |
409
|
|
|
$protocols = array( |
410
|
|
|
'Http', |
411
|
|
|
'Https', |
412
|
|
|
); |
413
|
|
|
$url = '://example.com'; |
414
|
|
|
|
415
|
|
|
foreach ($protocols as $protocol) { |
416
|
|
|
$comment->CommenterURL = $protocol . $url; |
|
|
|
|
417
|
|
|
// The protocol should stay as if, assuming it is valid |
418
|
|
|
$comment->write(); |
419
|
|
|
$this->assertEquals($comment->CommenterURL, $protocol . $url, $protocol . ':// is a valid protocol'); |
|
|
|
|
420
|
|
|
} |
421
|
|
|
} |
422
|
|
|
|
423
|
|
|
public function testSanitizesWithAllowHtml() |
424
|
|
|
{ |
425
|
|
|
if (!class_exists('\\HTMLPurifier')) { |
426
|
|
|
$this->markTestSkipped('HTMLPurifier class not found'); |
427
|
|
|
return; |
428
|
|
|
} |
429
|
|
|
|
430
|
|
|
// Add p for paragraph |
431
|
|
|
// NOTE: The config method appears to append to the existing array |
432
|
|
|
Config::modify()->merge(CommentableItem::class, 'comments', array( |
433
|
|
|
'html_allowed_elements' => array('p'), |
434
|
|
|
)); |
435
|
|
|
|
436
|
|
|
// Without HTML allowed |
437
|
|
|
$comment1 = new Comment(); |
438
|
|
|
$comment1->AllowHtml = false; |
439
|
|
|
$comment1->ParentClass = CommentableItem::class; |
|
|
|
|
440
|
|
|
$comment1->Comment = '<p><script>alert("w00t")</script>my comment</p>'; |
441
|
|
|
$comment1->write(); |
442
|
|
|
$this->assertEquals( |
443
|
|
|
'<p><script>alert("w00t")</script>my comment</p>', |
444
|
|
|
$comment1->Comment, |
445
|
|
|
'Does not remove HTML tags with html_allowed=false, ' . |
446
|
|
|
'which is correct behaviour because the HTML will be escaped' |
447
|
|
|
); |
448
|
|
|
|
449
|
|
|
// With HTML allowed |
450
|
|
|
$comment2 = new Comment(); |
451
|
|
|
$comment2->AllowHtml = true; |
452
|
|
|
$comment2->ParentClass = CommentableItem::class; |
|
|
|
|
453
|
|
|
$comment2->Comment = '<p><script>alert("w00t")</script>my comment</p>'; |
454
|
|
|
$comment2->write(); |
455
|
|
|
$this->assertEquals( |
456
|
|
|
'<p>my comment</p>', |
457
|
|
|
$comment2->Comment, |
458
|
|
|
'Removes HTML tags which are not on the whitelist' |
459
|
|
|
); |
460
|
|
|
} |
461
|
|
|
|
462
|
|
|
public function testDefaultTemplateRendersHtmlWithAllowHtml() |
463
|
|
|
{ |
464
|
|
|
if (!class_exists('\\HTMLPurifier')) { |
465
|
|
|
$this->markTestSkipped('HTMLPurifier class not found'); |
466
|
|
|
} |
467
|
|
|
|
468
|
|
|
Config::modify()->merge(CommentableItem::class, 'comments', array( |
469
|
|
|
'html_allowed_elements' => array('p'), |
470
|
|
|
)); |
471
|
|
|
|
472
|
|
|
$item = new CommentableItem(); |
473
|
|
|
$item->write(); |
474
|
|
|
|
475
|
|
|
// Without HTML allowed |
476
|
|
|
$comment = new Comment(); |
477
|
|
|
$comment->Comment = '<p>my comment</p>'; |
478
|
|
|
$comment->AllowHtml = false; |
479
|
|
|
$comment->ParentID = $item->ID; |
480
|
|
|
$comment->ParentClass = CommentableItem::class; |
|
|
|
|
481
|
|
|
$comment->write(); |
482
|
|
|
|
483
|
|
|
$html = $item->customise(array('CommentsEnabled' => true))->renderWith('CommentsInterface'); |
484
|
|
|
$this->assertContains( |
485
|
|
|
'<p>my comment</p>', |
486
|
|
|
$html |
487
|
|
|
); |
488
|
|
|
|
489
|
|
|
$comment->AllowHtml = true; |
490
|
|
|
$comment->write(); |
491
|
|
|
$html = $item->customise(array('CommentsEnabled' => true))->renderWith('CommentsInterface'); |
492
|
|
|
$this->assertContains( |
493
|
|
|
'<p>my comment</p>', |
494
|
|
|
$html |
495
|
|
|
); |
496
|
|
|
} |
497
|
|
|
|
498
|
|
|
|
499
|
|
|
/** |
500
|
|
|
* Tests whether comments are enabled or disabled by default |
501
|
|
|
*/ |
502
|
|
|
public function testDefaultEnabled() |
503
|
|
|
{ |
504
|
|
|
Config::modify()->merge(CommentableItem::class, 'comments', array( |
505
|
|
|
'enabled_cms' => true, |
506
|
|
|
'require_moderation_cms' => true, |
507
|
|
|
'require_login_cms' => true |
508
|
|
|
)); |
509
|
|
|
|
510
|
|
|
// With default = true |
511
|
|
|
$obj = new CommentableItem(); |
512
|
|
|
$this->assertTrue((bool)$obj->getCommentsOption('enabled'), "Default setting is enabled"); |
|
|
|
|
513
|
|
|
$this->assertTrue((bool)$obj->ProvideComments); |
|
|
|
|
514
|
|
|
$this->assertEquals('None', $obj->ModerationRequired); |
|
|
|
|
515
|
|
|
$this->assertFalse((bool)$obj->CommentsRequireLogin); |
|
|
|
|
516
|
|
|
|
517
|
|
|
$obj = new CommentableItemEnabled(); |
518
|
|
|
$this->assertTrue((bool)$obj->ProvideComments); |
|
|
|
|
519
|
|
|
$this->assertEquals('Required', $obj->ModerationRequired); |
|
|
|
|
520
|
|
|
$this->assertTrue((bool)$obj->CommentsRequireLogin); |
|
|
|
|
521
|
|
|
|
522
|
|
|
$obj = new CommentableItemDisabled(); |
523
|
|
|
$this->assertFalse((bool)$obj->ProvideComments); |
|
|
|
|
524
|
|
|
$this->assertEquals('None', $obj->ModerationRequired); |
|
|
|
|
525
|
|
|
$this->assertFalse((bool)$obj->CommentsRequireLogin); |
|
|
|
|
526
|
|
|
|
527
|
|
|
// With default = false |
528
|
|
|
// Because of config rules about falsey values, apply config to object directly |
529
|
|
|
Config::modify()->merge(CommentableItem::class, 'comments', array( |
530
|
|
|
'enabled' => false, |
531
|
|
|
'require_login' => true, |
532
|
|
|
'require_moderation' => true |
533
|
|
|
)); |
534
|
|
|
|
535
|
|
|
$obj = new CommentableItem(); |
536
|
|
|
|
537
|
|
|
$this->assertFalse((bool)$obj->getCommentsOption('enabled'), 'Default setting is disabled'); |
|
|
|
|
538
|
|
|
$this->assertFalse((bool)$obj->ProvideComments); |
|
|
|
|
539
|
|
|
$this->assertEquals('Required', $obj->ModerationRequired); |
|
|
|
|
540
|
|
|
$this->assertTrue((bool)$obj->CommentsRequireLogin); |
|
|
|
|
541
|
|
|
|
542
|
|
|
$obj = new CommentableItemEnabled(); |
543
|
|
|
|
544
|
|
|
$this->assertTrue((bool)$obj->ProvideComments); |
|
|
|
|
545
|
|
|
$this->assertEquals('Required', $obj->ModerationRequired); |
|
|
|
|
546
|
|
|
$this->assertTrue((bool)$obj->CommentsRequireLogin); |
|
|
|
|
547
|
|
|
|
548
|
|
|
$obj = new CommentableItemDisabled(); |
549
|
|
|
|
550
|
|
|
$this->assertFalse((bool)$obj->ProvideComments); |
|
|
|
|
551
|
|
|
$this->assertEquals('None', $obj->ModerationRequired); |
|
|
|
|
552
|
|
|
$this->assertFalse((bool)$obj->CommentsRequireLogin); |
|
|
|
|
553
|
|
|
} |
554
|
|
|
|
555
|
|
|
public function testOnBeforeDelete() |
556
|
|
|
{ |
557
|
|
|
$comment = $this->objFromFixture(Comment::class, 'firstComA'); |
558
|
|
|
|
559
|
|
|
$child = new Comment(); |
560
|
|
|
$child->Name = 'Fred Bloggs'; |
561
|
|
|
$child->Comment = 'Child of firstComA'; |
562
|
|
|
$child->write(); |
563
|
|
|
$comment->ChildComments()->add($child); |
564
|
|
|
$this->assertEquals(4, $comment->ChildComments()->count()); |
565
|
|
|
|
566
|
|
|
$commentID = $comment->ID; |
567
|
|
|
$childCommentID = $child->ID; |
568
|
|
|
|
569
|
|
|
$comment->delete(); |
570
|
|
|
|
571
|
|
|
// assert that the new child been deleted |
572
|
|
|
$this->assertNull(DataObject::get_by_id(Comment::class, $commentID)); |
573
|
|
|
$this->assertNull(DataObject::get_by_id(Comment::class, $childCommentID)); |
574
|
|
|
} |
575
|
|
|
|
576
|
|
|
public function testRequireDefaultRecords() |
577
|
|
|
{ |
578
|
|
|
$this->markTestSkipped('TODO'); |
579
|
|
|
} |
580
|
|
|
|
581
|
|
|
public function testLink() |
582
|
|
|
{ |
583
|
|
|
$comment = $this->objFromFixture(Comment::class, 'thirdComD'); |
584
|
|
|
$this->assertEquals( |
585
|
|
|
'CommentableItemController#comment-' . $comment->ID, |
586
|
|
|
$comment->Link() |
587
|
|
|
); |
588
|
|
|
$this->assertEquals($comment->ID, $comment->ID); |
589
|
|
|
|
590
|
|
|
// An orphan comment has no link |
591
|
|
|
$comment->ParentID = 0; |
592
|
|
|
$comment->ParentClass = null; |
593
|
|
|
$comment->write(); |
594
|
|
|
$this->assertEquals('', $comment->Link()); |
595
|
|
|
} |
596
|
|
|
|
597
|
|
|
public function testPermalink() |
598
|
|
|
{ |
599
|
|
|
$comment = $this->objFromFixture(Comment::class, 'thirdComD'); |
600
|
|
|
$this->assertEquals('comment-' . $comment->ID, $comment->Permalink()); |
601
|
|
|
} |
602
|
|
|
|
603
|
|
|
/** |
604
|
|
|
* Test field labels in 2 languages |
605
|
|
|
*/ |
606
|
|
|
public function testFieldLabels() |
607
|
|
|
{ |
608
|
|
|
$locale = i18n::get_locale(); |
609
|
|
|
i18n::set_locale('fr'); |
610
|
|
|
$comment = $this->objFromFixture(Comment::class, 'firstComA'); |
611
|
|
|
$labels = $comment->FieldLabels(); |
612
|
|
|
$expected = array( |
613
|
|
|
'Name' => 'Nom de l\'Auteur', |
614
|
|
|
'Comment' => 'Commentaire', |
615
|
|
|
'Email' => 'Email', |
616
|
|
|
'URL' => 'URL', |
617
|
|
|
'Moderated' => 'Modéré?', |
618
|
|
|
'IsSpam' => 'Spam?', |
619
|
|
|
'AllowHtml' => 'Allow Html', |
620
|
|
|
'SecretToken' => 'Secret Token', |
621
|
|
|
'Depth' => 'Depth', |
622
|
|
|
'Author' => 'Author Member', |
623
|
|
|
'ParentComment' => 'Parent Comment', |
624
|
|
|
'ChildComments' => 'Child Comments', |
625
|
|
|
'ParentTitle' => 'Parent', |
626
|
|
|
'Created' => 'Date de publication', |
627
|
|
|
'Parent' => 'Parent' |
628
|
|
|
); |
629
|
|
|
i18n::set_locale($locale); |
630
|
|
|
$this->assertEquals($expected, $labels); |
631
|
|
|
$labels = $comment->FieldLabels(); |
632
|
|
|
$expected = array( |
633
|
|
|
'Name' => 'Author Name', |
634
|
|
|
'Comment' => 'Comment', |
635
|
|
|
'Email' => 'Email', |
636
|
|
|
'URL' => 'URL', |
637
|
|
|
'Moderated' => 'Moderated?', |
638
|
|
|
'IsSpam' => 'Spam?', |
639
|
|
|
'AllowHtml' => 'Allow Html', |
640
|
|
|
'SecretToken' => 'Secret Token', |
641
|
|
|
'Depth' => 'Depth', |
642
|
|
|
'Author' => 'Author Member', |
643
|
|
|
'ParentComment' => 'Parent Comment', |
644
|
|
|
'ChildComments' => 'Child Comments', |
645
|
|
|
'ParentTitle' => 'Parent', |
646
|
|
|
'Created' => 'Date posted', |
647
|
|
|
'Parent' => 'Parent' |
648
|
|
|
); |
649
|
|
|
$this->assertEquals($expected, $labels); |
650
|
|
|
} |
651
|
|
|
|
652
|
|
|
public function testGetParent() |
653
|
|
|
{ |
654
|
|
|
$comment = $this->objFromFixture(Comment::class, 'firstComA'); |
655
|
|
|
$item = $this->objFromFixture(CommentableItem::class, 'first'); |
656
|
|
|
$parent = $comment->Parent(); |
657
|
|
|
$this->assertSame($item->getClassName(), $parent->getClassName()); |
658
|
|
|
$this->assertSame($item->ID, $parent->ID); |
659
|
|
|
} |
660
|
|
|
|
661
|
|
View Code Duplication |
public function testGetParentTitle() |
|
|
|
|
662
|
|
|
{ |
663
|
|
|
$comment = $this->objFromFixture(Comment::class, 'firstComA'); |
664
|
|
|
$title = $comment->getParentTitle(); |
665
|
|
|
$this->assertEquals('First', $title); |
666
|
|
|
|
667
|
|
|
// Title from a comment with no parent is blank |
668
|
|
|
$comment->ParentID = 0; |
669
|
|
|
$comment->ParentClass = null; |
670
|
|
|
$comment->write(); |
671
|
|
|
$this->assertEquals('', $comment->getParentTitle()); |
672
|
|
|
} |
673
|
|
|
|
674
|
|
|
public function testGetParentClassName() |
675
|
|
|
{ |
676
|
|
|
$comment = $this->objFromFixture(Comment::class, 'firstComA'); |
677
|
|
|
$className = $comment->getParentClassName(); |
678
|
|
|
$this->assertEquals(CommentableItem::class, $className); |
679
|
|
|
} |
680
|
|
|
|
681
|
|
|
public function testCastingHelper() |
682
|
|
|
{ |
683
|
|
|
$this->markTestSkipped('TODO'); |
684
|
|
|
} |
685
|
|
|
|
686
|
|
|
public function testGetEscapedComment() |
687
|
|
|
{ |
688
|
|
|
$this->markTestSkipped('TODO'); |
689
|
|
|
} |
690
|
|
|
|
691
|
|
|
public function testIsPreview() |
692
|
|
|
{ |
693
|
|
|
$comment = new Comment(); |
694
|
|
|
$comment->Name = 'Fred Bloggs'; |
695
|
|
|
$comment->Comment = 'this is a test comment'; |
696
|
|
|
$this->assertTrue($comment->isPreview()); |
697
|
|
|
$comment->write(); |
698
|
|
|
$this->assertFalse($comment->isPreview()); |
699
|
|
|
} |
700
|
|
|
|
701
|
|
|
public function testCanCreate() |
702
|
|
|
{ |
703
|
|
|
$comment = $this->objFromFixture(Comment::class, 'firstComA'); |
704
|
|
|
|
705
|
|
|
// admin can create - this is always false |
706
|
|
|
$this->logInAs('commentadmin'); |
707
|
|
|
$this->assertFalse($comment->canCreate()); |
708
|
|
|
|
709
|
|
|
// visitor can view |
710
|
|
|
$this->logInAs('visitor'); |
711
|
|
|
$this->assertFalse($comment->canCreate()); |
712
|
|
|
} |
713
|
|
|
|
714
|
|
View Code Duplication |
public function testCanView() |
|
|
|
|
715
|
|
|
{ |
716
|
|
|
$comment = $this->objFromFixture(Comment::class, 'firstComA'); |
717
|
|
|
|
718
|
|
|
// admin can view |
719
|
|
|
$this->logInAs('commentadmin'); |
720
|
|
|
$this->assertTrue($comment->canView()); |
721
|
|
|
|
722
|
|
|
// visitor can view |
723
|
|
|
$this->logInAs('visitor'); |
724
|
|
|
$this->assertTrue($comment->canView()); |
725
|
|
|
|
726
|
|
|
$comment->ParentID = 0; |
727
|
|
|
$comment->write(); |
728
|
|
|
$this->assertFalse($comment->canView()); |
729
|
|
|
} |
730
|
|
|
|
731
|
|
View Code Duplication |
public function testCanEdit() |
|
|
|
|
732
|
|
|
{ |
733
|
|
|
$comment = $this->objFromFixture(Comment::class, 'firstComA'); |
734
|
|
|
|
735
|
|
|
// admin can edit |
736
|
|
|
$this->logInAs('commentadmin'); |
737
|
|
|
$this->assertTrue($comment->canEdit()); |
738
|
|
|
|
739
|
|
|
// visitor cannot |
740
|
|
|
$this->logInAs('visitor'); |
741
|
|
|
$this->assertFalse($comment->canEdit()); |
742
|
|
|
|
743
|
|
|
$comment->ParentID = 0; |
744
|
|
|
$comment->write(); |
745
|
|
|
$this->assertFalse($comment->canEdit()); |
746
|
|
|
} |
747
|
|
|
|
748
|
|
View Code Duplication |
public function testCanDelete() |
|
|
|
|
749
|
|
|
{ |
750
|
|
|
$comment = $this->objFromFixture(Comment::class, 'firstComA'); |
751
|
|
|
|
752
|
|
|
// admin can delete |
753
|
|
|
$this->logInAs('commentadmin'); |
754
|
|
|
$this->assertTrue($comment->canDelete()); |
755
|
|
|
|
756
|
|
|
// visitor cannot |
757
|
|
|
$this->logInAs('visitor'); |
758
|
|
|
$this->assertFalse($comment->canDelete()); |
759
|
|
|
|
760
|
|
|
$comment->ParentID = 0; |
761
|
|
|
$comment->write(); |
762
|
|
|
$this->assertFalse($comment->canDelete()); |
763
|
|
|
} |
764
|
|
|
|
765
|
|
|
public function testGetMember() |
766
|
|
|
{ |
767
|
|
|
$this->logInAs('visitor'); |
768
|
|
|
$current = Security::getCurrentUser(); |
769
|
|
|
$comment = $this->objFromFixture(Comment::class, 'firstComA'); |
770
|
|
|
$method = $this->getMethod('getMember'); |
771
|
|
|
|
772
|
|
|
// null case |
773
|
|
|
$member = $method->invokeArgs($comment, array()); |
774
|
|
|
$this->assertEquals($current->ID, $member->ID); |
775
|
|
|
|
776
|
|
|
// numeric ID case |
777
|
|
|
$member = $method->invokeArgs($comment, array($current->ID)); |
778
|
|
|
$this->assertEquals($current->ID, $member->ID); |
779
|
|
|
|
780
|
|
|
// identity case |
781
|
|
|
$member = $method->invokeArgs($comment, array($current)); |
782
|
|
|
$this->assertEquals($current->ID, $member->ID); |
783
|
|
|
} |
784
|
|
|
|
785
|
|
|
public function testGetAuthorName() |
786
|
|
|
{ |
787
|
|
|
$comment = $this->objFromFixture(Comment::class, 'firstComA'); |
788
|
|
|
$this->assertEquals( |
789
|
|
|
'FA', |
790
|
|
|
$comment->getAuthorName() |
791
|
|
|
); |
792
|
|
|
|
793
|
|
|
$comment->Name = ''; |
794
|
|
|
$this->assertEquals( |
795
|
|
|
'', |
796
|
|
|
$comment->getAuthorName() |
797
|
|
|
); |
798
|
|
|
|
799
|
|
|
$author = $this->objFromFixture(Member::class, 'visitor'); |
800
|
|
|
$comment->AuthorID = $author->ID; |
801
|
|
|
$comment->write(); |
802
|
|
|
$this->assertEquals( |
803
|
|
|
'visitor', |
804
|
|
|
$comment->getAuthorName() |
805
|
|
|
); |
806
|
|
|
|
807
|
|
|
// null the names, expect null back |
808
|
|
|
$comment->Name = null; |
809
|
|
|
$comment->AuthorID = 0; |
810
|
|
|
$this->assertNull($comment->getAuthorName()); |
811
|
|
|
} |
812
|
|
|
|
813
|
|
|
|
814
|
|
|
public function testLinks() |
815
|
|
|
{ |
816
|
|
|
$comment = $this->objFromFixture(Comment::class, 'firstComA'); |
817
|
|
|
$this->logInAs('commentadmin'); |
818
|
|
|
|
819
|
|
|
$method = $this->getMethod('ActionLink'); |
820
|
|
|
|
821
|
|
|
// test with starts of strings and tokens and salts change each time |
822
|
|
|
$this->assertContains( |
823
|
|
|
'/comments/theaction/' . $comment->ID, |
824
|
|
|
$method->invokeArgs($comment, array('theaction')) |
825
|
|
|
); |
826
|
|
|
|
827
|
|
|
$this->assertContains( |
828
|
|
|
'/comments/delete/' . $comment->ID, |
829
|
|
|
$comment->DeleteLink() |
830
|
|
|
); |
831
|
|
|
|
832
|
|
|
$this->assertContains( |
833
|
|
|
'/comments/spam/' . $comment->ID, |
834
|
|
|
$comment->SpamLink() |
835
|
|
|
); |
836
|
|
|
|
837
|
|
|
$comment->markSpam(); |
838
|
|
|
$this->assertContains( |
839
|
|
|
'/comments/ham/' . $comment->ID, |
840
|
|
|
$comment->HamLink() |
841
|
|
|
); |
842
|
|
|
|
843
|
|
|
//markApproved |
844
|
|
|
$comment->markUnapproved(); |
845
|
|
|
$this->assertContains( |
846
|
|
|
'/comments/approve/' . $comment->ID, |
847
|
|
|
$comment->ApproveLink() |
848
|
|
|
); |
849
|
|
|
} |
850
|
|
|
|
851
|
|
|
public function testMarkSpam() |
852
|
|
|
{ |
853
|
|
|
$comment = $this->objFromFixture(Comment::class, 'firstComA'); |
854
|
|
|
$comment->markSpam(); |
855
|
|
|
$this->assertTrue($comment->Moderated); |
856
|
|
|
$this->assertTrue($comment->IsSpam); |
857
|
|
|
} |
858
|
|
|
|
859
|
|
|
public function testMarkApproved() |
860
|
|
|
{ |
861
|
|
|
$comment = $this->objFromFixture(Comment::class, 'firstComA'); |
862
|
|
|
$comment->markApproved(); |
863
|
|
|
$this->assertTrue($comment->Moderated); |
864
|
|
|
$this->assertFalse($comment->IsSpam); |
865
|
|
|
} |
866
|
|
|
|
867
|
|
|
public function testMarkUnapproved() |
868
|
|
|
{ |
869
|
|
|
$comment = $this->objFromFixture(Comment::class, 'firstComA'); |
870
|
|
|
$comment->markApproved(); |
871
|
|
|
$this->assertTrue($comment->Moderated); |
872
|
|
|
} |
873
|
|
|
|
874
|
|
View Code Duplication |
public function testSpamClass() |
|
|
|
|
875
|
|
|
{ |
876
|
|
|
$comment = $this->objFromFixture(Comment::class, 'firstComA'); |
877
|
|
|
$this->assertEquals('notspam', $comment->spamClass()); |
878
|
|
|
$comment->Moderated = false; |
879
|
|
|
$this->assertEquals('unmoderated', $comment->spamClass()); |
880
|
|
|
$comment->IsSpam = true; |
881
|
|
|
$this->assertEquals('spam', $comment->spamClass()); |
882
|
|
|
} |
883
|
|
|
|
884
|
|
|
public function testGetTitle() |
885
|
|
|
{ |
886
|
|
|
$comment = $this->objFromFixture(Comment::class, 'firstComA'); |
887
|
|
|
$this->assertEquals( |
888
|
|
|
'Comment by FA on First', |
889
|
|
|
$comment->getTitle() |
890
|
|
|
); |
891
|
|
|
} |
892
|
|
|
|
893
|
|
|
public function testGetCMSFields() |
894
|
|
|
{ |
895
|
|
|
$comment = $this->objFromFixture(Comment::class, 'firstComA'); |
896
|
|
|
$fields = $comment->getCMSFields(); |
897
|
|
|
$names = array(); |
898
|
|
|
foreach ($fields as $field) { |
899
|
|
|
$names[] = $field->getName(); |
900
|
|
|
} |
901
|
|
|
$expected = array( |
902
|
|
|
'Created', |
903
|
|
|
'Name', |
904
|
|
|
'Comment', |
905
|
|
|
'Email', |
906
|
|
|
'URL', |
907
|
|
|
'Options' |
908
|
|
|
); |
909
|
|
|
$this->assertEquals($expected, $names); |
910
|
|
|
} |
911
|
|
|
|
912
|
|
|
public function testGetCMSFieldsCommentHasAuthor() |
913
|
|
|
{ |
914
|
|
|
$member = Member::get()->filter('FirstName', 'visitor')->first(); |
915
|
|
|
$comment = $this->objFromFixture(Comment::class, 'firstComA'); |
916
|
|
|
$comment->AuthorID = $member->ID; |
917
|
|
|
$comment->write(); |
918
|
|
|
|
919
|
|
|
$fields = $comment->getCMSFields(); |
920
|
|
|
$names = array(); |
921
|
|
|
foreach ($fields as $field) { |
922
|
|
|
$names[] = $field->getName(); |
923
|
|
|
} |
924
|
|
|
$expected = array( |
925
|
|
|
'Created', |
926
|
|
|
'Name', |
927
|
|
|
'AuthorMember', |
928
|
|
|
'Comment', |
929
|
|
|
'Email', |
930
|
|
|
'URL', |
931
|
|
|
'Options' |
932
|
|
|
); |
933
|
|
|
$this->assertEquals($expected, $names); |
934
|
|
|
} |
935
|
|
|
|
936
|
|
|
public function testGetCMSFieldsWithParentComment() |
937
|
|
|
{ |
938
|
|
|
$comment = $this->objFromFixture(Comment::class, 'firstComA'); |
939
|
|
|
|
940
|
|
|
$child = new Comment(); |
941
|
|
|
$child->Name = 'John Smith'; |
942
|
|
|
$child->Comment = 'This is yet another test commnent'; |
943
|
|
|
$child->ParentCommentID = $comment->ID; |
|
|
|
|
944
|
|
|
$child->write(); |
945
|
|
|
|
946
|
|
|
$fields = $child->getCMSFields(); |
947
|
|
|
$names = array(); |
948
|
|
|
foreach ($fields as $field) { |
949
|
|
|
$names[] = $field->getName(); |
950
|
|
|
} |
951
|
|
|
$expected = array( |
952
|
|
|
'Created', |
953
|
|
|
'Name', |
954
|
|
|
'Comment', |
955
|
|
|
'Email', |
956
|
|
|
'URL', |
957
|
|
|
'Options', |
958
|
|
|
'ParentComment_Title', |
959
|
|
|
'ParentComment_Created', |
960
|
|
|
'ParentComment_AuthorName', |
961
|
|
|
'ParentComment_EscapedComment' |
962
|
|
|
); |
963
|
|
|
$this->assertEquals($expected, $names); |
964
|
|
|
} |
965
|
|
|
|
966
|
|
|
public function testPurifyHtml() |
967
|
|
|
{ |
968
|
|
|
if (!class_exists(HTMLPurifier_Config::class)) { |
969
|
|
|
$this->markTestSkipped('HTMLPurifier class not found'); |
970
|
|
|
return; |
971
|
|
|
} |
972
|
|
|
|
973
|
|
|
$comment = $this->objFromFixture(Comment::class, 'firstComA'); |
974
|
|
|
|
975
|
|
|
$dirtyHTML = '<p><script>alert("w00t")</script>my comment</p>'; |
976
|
|
|
$this->assertEquals( |
977
|
|
|
'my comment', |
978
|
|
|
$comment->purifyHtml($dirtyHTML) |
979
|
|
|
); |
980
|
|
|
} |
981
|
|
|
|
982
|
|
|
public function testGravatar() |
983
|
|
|
{ |
984
|
|
|
// Turn gravatars on |
985
|
|
|
Config::modify()->merge(CommentableItem::class, 'comments', array( |
986
|
|
|
'use_gravatar' => true, |
987
|
|
|
'gravatar_size' => 80, |
988
|
|
|
'gravatar_default' => 'identicon', |
989
|
|
|
'gravatar_rating' => 'g' |
990
|
|
|
)); |
991
|
|
|
|
992
|
|
|
$comment = $this->objFromFixture(Comment::class, 'firstComA'); |
993
|
|
|
|
994
|
|
|
$this->assertEquals( |
995
|
|
|
'http://www.gravatar.com/avatar/d41d8cd98f00b204e9800998ecf8427e?s' |
996
|
|
|
. '=80&d=identicon&r=g', |
997
|
|
|
$comment->Gravatar() |
998
|
|
|
); |
999
|
|
|
|
1000
|
|
|
// Turn gravatars off |
1001
|
|
|
Config::modify()->merge(CommentableItem::class, 'comments', array( |
1002
|
|
|
'use_gravatar' => false |
1003
|
|
|
)); |
1004
|
|
|
|
1005
|
|
|
$comment = $this->objFromFixture(Comment::class, 'firstComA'); |
1006
|
|
|
|
1007
|
|
|
$this->assertEquals( |
1008
|
|
|
'', |
1009
|
|
|
$comment->Gravatar() |
1010
|
|
|
); |
1011
|
|
|
} |
1012
|
|
|
|
1013
|
|
|
public function testGetRepliesEnabled() |
1014
|
|
|
{ |
1015
|
|
|
Config::modify()->merge(CommentableItem::class, 'comments', array( |
1016
|
|
|
'nested_comments' => false |
1017
|
|
|
)); |
1018
|
|
|
|
1019
|
|
|
$comment = $this->objFromFixture(Comment::class, 'firstComA'); |
1020
|
|
|
$this->assertFalse($comment->getRepliesEnabled()); |
1021
|
|
|
|
1022
|
|
|
Config::modify()->merge(CommentableItem::class, 'comments', array( |
1023
|
|
|
'nested_comments' => true, |
1024
|
|
|
'nested_depth' => 4 |
1025
|
|
|
)); |
1026
|
|
|
|
1027
|
|
|
$this->assertTrue($comment->getRepliesEnabled()); |
1028
|
|
|
|
1029
|
|
|
$comment->Depth = 4; |
1030
|
|
|
$this->assertFalse($comment->getRepliesEnabled()); |
1031
|
|
|
|
1032
|
|
|
|
1033
|
|
|
// 0 indicates no limit for nested_depth |
1034
|
|
|
Config::modify()->merge(CommentableItem::class, 'comments', array( |
1035
|
|
|
'nested_comments' => true, |
1036
|
|
|
'nested_depth' => 0 |
1037
|
|
|
)); |
1038
|
|
|
|
1039
|
|
|
$comment = $this->objFromFixture(Comment::class, 'firstComA'); |
1040
|
|
|
$comment->Depth = 234; |
1041
|
|
|
|
1042
|
|
|
$comment->markUnapproved(); |
1043
|
|
|
$this->assertFalse($comment->getRepliesEnabled()); |
1044
|
|
|
|
1045
|
|
|
$comment->markSpam(); |
1046
|
|
|
$this->assertFalse($comment->getRepliesEnabled()); |
1047
|
|
|
|
1048
|
|
|
$comment->markApproved(); |
1049
|
|
|
$this->assertTrue($comment->getRepliesEnabled()); |
1050
|
|
|
} |
1051
|
|
|
|
1052
|
|
|
public function testAllReplies() |
1053
|
|
|
{ |
1054
|
|
|
Config::modify()->merge(CommentableItem::class, 'comments', array( |
1055
|
|
|
'nested_comments' => true, |
1056
|
|
|
'nested_depth' => 4 |
1057
|
|
|
)); |
1058
|
|
|
|
1059
|
|
|
$comment = $this->objFromFixture(Comment::class, 'firstComA'); |
1060
|
|
|
|
1061
|
|
|
$this->assertEquals( |
1062
|
|
|
3, |
1063
|
|
|
$comment->allReplies()->count() |
1064
|
|
|
); |
1065
|
|
|
|
1066
|
|
|
$child = new Comment(); |
1067
|
|
|
$child->Name = 'Fred Smith'; |
1068
|
|
|
$child->Comment = 'This is a child comment'; |
1069
|
|
|
$child->ParentCommentID = $comment->ID; |
|
|
|
|
1070
|
|
|
|
1071
|
|
|
// spam should be returned by this method |
1072
|
|
|
$child->markSpam(); |
1073
|
|
|
$child->write(); |
1074
|
|
|
$replies = $comment->allReplies(); |
|
|
|
|
1075
|
|
|
$this->assertEquals( |
1076
|
|
|
4, |
1077
|
|
|
$comment->allReplies()->count() |
1078
|
|
|
); |
1079
|
|
|
|
1080
|
|
|
Config::modify()->merge(CommentableItem::class, 'comments', array( |
1081
|
|
|
'nested_comments' => false |
1082
|
|
|
)); |
1083
|
|
|
|
1084
|
|
|
$this->assertEquals(0, $comment->allReplies()->count()); |
1085
|
|
|
} |
1086
|
|
|
|
1087
|
|
|
public function testReplies() |
1088
|
|
|
{ |
1089
|
|
|
CommentableItem::add_extension(CommentsExtension::class); |
1090
|
|
|
$this->logInWithPermission('ADMIN'); |
1091
|
|
|
Config::modify()->merge(CommentableItem::class, 'comments', array( |
1092
|
|
|
'nested_comments' => true, |
1093
|
|
|
'nested_depth' => 4 |
1094
|
|
|
)); |
1095
|
|
|
$comment = $this->objFromFixture(Comment::class, 'firstComA'); |
1096
|
|
|
$this->assertEquals( |
1097
|
|
|
3, |
1098
|
|
|
$comment->Replies()->count() |
1099
|
|
|
); |
1100
|
|
|
|
1101
|
|
|
// Test that spam comments are not returned |
1102
|
|
|
$childComment = $comment->Replies()->first(); |
1103
|
|
|
$childComment->IsSpam = 1; |
1104
|
|
|
$childComment->write(); |
1105
|
|
|
$this->assertEquals( |
1106
|
|
|
2, |
1107
|
|
|
$comment->Replies()->count() |
1108
|
|
|
); |
1109
|
|
|
|
1110
|
|
|
// Test that unmoderated comments are not returned |
1111
|
|
|
// |
1112
|
|
|
$childComment = $comment->Replies()->first(); |
1113
|
|
|
|
1114
|
|
|
// FIXME - moderation settings scenarios need checked here |
1115
|
|
|
$childComment->Moderated = 0; |
1116
|
|
|
$childComment->IsSpam = 0; |
1117
|
|
|
$childComment->write(); |
1118
|
|
|
$this->assertEquals( |
1119
|
|
|
2, |
1120
|
|
|
$comment->Replies()->count() |
1121
|
|
|
); |
1122
|
|
|
|
1123
|
|
|
|
1124
|
|
|
// Test moderation required on the front end |
1125
|
|
|
$item = $this->objFromFixture(CommentableItem::class, 'first'); |
1126
|
|
|
$item->ModerationRequired = 'Required'; |
1127
|
|
|
$item->write(); |
1128
|
|
|
|
1129
|
|
|
Config::modify()->merge(CommentableItemDisabled::class, 'comments', array( |
1130
|
|
|
'nested_comments' => true, |
1131
|
|
|
'nested_depth' => 4, |
1132
|
|
|
'frontend_moderation' => true |
1133
|
|
|
)); |
1134
|
|
|
|
1135
|
|
|
$comment = DataObject::get_by_id(Comment::class, $comment->ID); |
1136
|
|
|
|
1137
|
|
|
$this->assertEquals( |
1138
|
|
|
2, |
1139
|
|
|
$comment->Replies()->count() |
1140
|
|
|
); |
1141
|
|
|
|
1142
|
|
|
// Turn off nesting, empty array should be returned |
1143
|
|
|
Config::modify()->merge(CommentableItem::class, 'comments', array( |
1144
|
|
|
'nested_comments' => false |
1145
|
|
|
)); |
1146
|
|
|
|
1147
|
|
|
$this->assertEquals( |
1148
|
|
|
0, |
1149
|
|
|
$comment->Replies()->count() |
1150
|
|
|
); |
1151
|
|
|
|
1152
|
|
|
CommentableItem::remove_extension(CommentsExtension::class); |
1153
|
|
|
} |
1154
|
|
|
|
1155
|
|
|
public function testPagedReplies() |
1156
|
|
|
{ |
1157
|
|
|
Config::modify()->merge(CommentableItem::class, 'comments', array( |
1158
|
|
|
'nested_comments' => true, |
1159
|
|
|
'nested_depth' => 4, |
1160
|
|
|
'comments_per_page' => 2 |
1161
|
|
|
)); |
1162
|
|
|
|
1163
|
|
|
$comment = $this->objFromFixture(Comment::class, 'firstComA'); |
1164
|
|
|
$pagedList = $comment->pagedReplies(); |
1165
|
|
|
|
1166
|
|
|
$this->assertEquals( |
1167
|
|
|
2, |
1168
|
|
|
$pagedList->TotalPages() |
1169
|
|
|
); |
1170
|
|
|
|
1171
|
|
|
$this->assertEquals( |
1172
|
|
|
3, |
1173
|
|
|
$pagedList->getTotalItems() |
1174
|
|
|
); |
1175
|
|
|
|
1176
|
|
|
Config::modify()->merge(CommentableItem::class, 'comments', array( |
1177
|
|
|
'nested_comments' => false |
1178
|
|
|
)); |
1179
|
|
|
|
1180
|
|
|
$this->assertEquals(0, $comment->PagedReplies()->count()); |
1181
|
|
|
} |
1182
|
|
|
|
1183
|
|
|
public function testReplyForm() |
1184
|
|
|
{ |
1185
|
|
|
Config::modify()->merge(CommentableItem::class, 'comments', array( |
1186
|
|
|
'nested_comments' => false, |
1187
|
|
|
'nested_depth' => 4 |
1188
|
|
|
)); |
1189
|
|
|
|
1190
|
|
|
$comment = $this->objFromFixture(Comment::class, 'firstComA'); |
1191
|
|
|
|
1192
|
|
|
// No nesting, no reply form |
1193
|
|
|
$form = $comment->replyForm(); |
1194
|
|
|
$this->assertNull($form); |
1195
|
|
|
|
1196
|
|
|
// parent item so show form |
1197
|
|
|
Config::modify()->merge(CommentableItem::class, 'comments', array( |
1198
|
|
|
'nested_comments' => true, |
1199
|
|
|
'nested_depth' => 4 |
1200
|
|
|
)); |
1201
|
|
|
$form = $comment->ReplyForm(); |
1202
|
|
|
$this->assertNotNull($form); |
1203
|
|
|
$names = array(); |
1204
|
|
|
|
1205
|
|
|
foreach ($form->Fields() as $field) { |
1206
|
|
|
array_push($names, $field->getName()); |
1207
|
|
|
} |
1208
|
|
|
|
1209
|
|
|
$this->assertEquals( |
1210
|
|
|
array( |
1211
|
|
|
'NameEmailURLComment', // The CompositeField name? |
1212
|
|
|
'ParentID', |
1213
|
|
|
'ParentClassName', |
1214
|
|
|
'ReturnURL', |
1215
|
|
|
'ParentCommentID' |
1216
|
|
|
), |
1217
|
|
|
$names |
1218
|
|
|
); |
1219
|
|
|
|
1220
|
|
|
// no parent, no reply form |
1221
|
|
|
|
1222
|
|
|
$comment->ParentID = 0; |
1223
|
|
|
$comment->ParentClass = null; |
1224
|
|
|
$comment->write(); |
1225
|
|
|
$form = $comment->replyForm(); |
1226
|
|
|
$this->assertNull($form); |
1227
|
|
|
} |
1228
|
|
|
|
1229
|
|
|
public function testUpdateDepth() |
1230
|
|
|
{ |
1231
|
|
|
Config::modify()->merge(CommentableItem::class, 'comments', array( |
1232
|
|
|
'nested_comments' => true, |
1233
|
|
|
'nested_depth' => 4 |
1234
|
|
|
)); |
1235
|
|
|
|
1236
|
|
|
$comment = $this->objFromFixture(Comment::class, 'firstComA'); |
1237
|
|
|
$children = $comment->allReplies()->toArray(); |
1238
|
|
|
// Make the second child a child of the first |
1239
|
|
|
// Make the third child a child of the second |
1240
|
|
|
$reply1 = $children[0]; |
1241
|
|
|
$reply2 = $children[1]; |
1242
|
|
|
$reply3 = $children[2]; |
1243
|
|
|
$reply2->ParentCommentID = $reply1->ID; |
1244
|
|
|
$reply2->write(); |
1245
|
|
|
$this->assertEquals(3, $reply2->Depth); |
1246
|
|
|
$reply3->ParentCommentID = $reply2->ID; |
1247
|
|
|
$reply3->write(); |
1248
|
|
|
$this->assertEquals(4, $reply3->Depth); |
1249
|
|
|
} |
1250
|
|
|
|
1251
|
|
|
public function testGetToken() |
1252
|
|
|
{ |
1253
|
|
|
$this->markTestSkipped('TODO'); |
1254
|
|
|
} |
1255
|
|
|
|
1256
|
|
|
public function testMemberSalt() |
1257
|
|
|
{ |
1258
|
|
|
$this->markTestSkipped('TODO'); |
1259
|
|
|
} |
1260
|
|
|
|
1261
|
|
|
public function testAddToUrl() |
1262
|
|
|
{ |
1263
|
|
|
$this->markTestSkipped('TODO'); |
1264
|
|
|
} |
1265
|
|
|
|
1266
|
|
|
public function testCheckRequest() |
1267
|
|
|
{ |
1268
|
|
|
$this->markTestSkipped('TODO'); |
1269
|
|
|
} |
1270
|
|
|
|
1271
|
|
|
public function testGenerate() |
1272
|
|
|
{ |
1273
|
|
|
$this->markTestSkipped('TODO'); |
1274
|
|
|
} |
1275
|
|
|
|
1276
|
|
|
protected static function getMethod($name) |
1277
|
|
|
{ |
1278
|
|
|
$class = new ReflectionClass(Comment::class); |
1279
|
|
|
$method = $class->getMethod($name); |
1280
|
|
|
$method->setAccessible(true); |
1281
|
|
|
return $method; |
1282
|
|
|
} |
1283
|
|
|
} |
1284
|
|
|
|
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignore
PhpDoc annotation to the duplicate definition and it will be ignored.