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