1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* ForumHolder represents the top forum overview page. Its children |
5
|
|
|
* should be Forums. On this page you can also edit your global settings |
6
|
|
|
* for the entire forum. |
7
|
|
|
* |
8
|
|
|
* @package forum |
9
|
|
|
*/ |
10
|
|
|
|
11
|
|
|
class ForumHolder extends Page |
12
|
|
|
{ |
13
|
|
|
|
14
|
|
|
private static $avatars_folder = 'forum/avatars/'; |
15
|
|
|
|
16
|
|
|
private static $attachments_folder = 'forum/attachments/'; |
17
|
|
|
|
18
|
|
|
private static $db = array( |
19
|
|
|
"HolderSubtitle" => "Varchar(200)", |
20
|
|
|
"ProfileSubtitle" => "Varchar(200)", |
21
|
|
|
"ForumSubtitle" => "Varchar(200)", |
22
|
|
|
"HolderAbstract" => "HTMLText", |
23
|
|
|
"ProfileAbstract" => "HTMLText", |
24
|
|
|
"ForumAbstract" => "HTMLText", |
25
|
|
|
"ProfileModify" => "HTMLText", |
26
|
|
|
"ProfileAdd" => "HTMLText", |
27
|
|
|
"DisplaySignatures" => "Boolean", |
28
|
|
|
"ShowInCategories" => "Boolean", |
29
|
|
|
"AllowGravatars" => "Boolean", |
30
|
|
|
"GravatarType" => "Varchar(10)", |
31
|
|
|
"ForbiddenWords" => "Text", |
32
|
|
|
"CanPostType" => "Enum('Anyone, LoggedInUsers, OnlyTheseUsers, NoOne', 'LoggedInUsers')", |
33
|
|
|
); |
34
|
|
|
|
35
|
|
|
private static $has_one = array(); |
36
|
|
|
|
37
|
|
|
private static $has_many = array( |
38
|
|
|
"Categories" => "ForumCategory" |
39
|
|
|
); |
40
|
|
|
|
41
|
|
|
private static $allowed_children = array('Forum'); |
42
|
|
|
|
43
|
|
|
private static $defaults = array( |
44
|
|
|
"HolderSubtitle" => "Welcome to our forum!", |
45
|
|
|
"ProfileSubtitle" => "Edit Your Profile", |
46
|
|
|
"ForumSubtitle" => "Start a new topic", |
47
|
|
|
"HolderAbstract" => "<p>If this is your first visit, you will need to <a class=\"broken\" title=\"Click here to register\" href=\"ForumMemberProfile/register\">register</a> before you can post. However, you can browse all messages below.</p>", |
48
|
|
|
"ProfileAbstract" => "<p>Please fill out the fields below. You can choose whether some are publically visible by using the checkbox for each one.</p>", |
49
|
|
|
"ForumAbstract" => "<p>From here you can start a new topic.</p>", |
50
|
|
|
"ProfileModify" => "<p>Thanks, your member profile has been modified.</p>", |
51
|
|
|
"ProfileAdd" => "<p>Thanks, you are now signed up to the forum.</p>", |
52
|
|
|
); |
53
|
|
|
|
54
|
|
|
/** |
55
|
|
|
* If the user has spam protection enabled and setup then we can provide spam |
56
|
|
|
* prevention for the forum. This stores whether we actually want the registration |
57
|
|
|
* form to have such protection |
58
|
|
|
* |
59
|
|
|
* @var bool |
60
|
|
|
*/ |
61
|
|
|
public static $use_spamprotection_on_register = true; |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* If the user has spam protection enabled and setup then we can provide spam |
65
|
|
|
* prevention for the forum. This stores whether we actually want the posting |
66
|
|
|
* form (adding, replying) to have such protection |
67
|
|
|
* |
68
|
|
|
* @var bool |
69
|
|
|
*/ |
70
|
|
|
public static $use_spamprotection_on_posts = false; |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* Add a hidden field to the form which should remain empty |
74
|
|
|
* If its filled out, we can assume that a spam bot is auto-filling fields. |
75
|
|
|
* |
76
|
|
|
* @var bool |
77
|
|
|
*/ |
78
|
|
|
public static $use_honeypot_on_register = false; |
79
|
|
|
|
80
|
|
|
/** |
81
|
|
|
* @var bool If TRUE, each logged in Member who visits a Forum will write the LastViewed field |
82
|
|
|
* which is for the "Currently online" functionality. |
83
|
|
|
*/ |
84
|
|
|
private static $currently_online_enabled = true; |
85
|
|
|
|
86
|
|
|
public function getCMSFields() |
87
|
|
|
{ |
88
|
|
|
$self = $this; |
89
|
|
|
|
90
|
|
|
$this->beforeUpdateCMSFields(function ($fields) use ($self) { |
91
|
|
|
|
92
|
|
|
$fields->addFieldsToTab("Root.Messages", array( |
93
|
|
|
TextField::create("HolderSubtitle", "Forum Holder Subtitle"), |
94
|
|
|
HTMLEditorField::create("HolderAbstract", "Forum Holder Abstract"), |
95
|
|
|
TextField::create("ProfileSubtitle", "Member Profile Subtitle"), |
96
|
|
|
HTMLEditorField::create("ProfileAbstract", "Member Profile Abstract"), |
97
|
|
|
TextField::create("ForumSubtitle", "Create topic Subtitle"), |
98
|
|
|
HTMLEditorField::create("ForumAbstract", "Create topic Abstract"), |
99
|
|
|
HTMLEditorField::create("ProfileModify", "Create message after modifing forum member"), |
100
|
|
|
HTMLEditorField::create("ProfileAdd", "Create message after adding forum member") |
101
|
|
|
)); |
102
|
|
|
$fields->addFieldsToTab("Root.Settings", array( |
103
|
|
|
CheckboxField::create("DisplaySignatures", "Display Member Signatures?"), |
104
|
|
|
CheckboxField::create("ShowInCategories", "Show Forums In Categories?"), |
105
|
|
|
CheckboxField::create("AllowGravatars", "Allow <a href='http://www.gravatar.com/' target='_blank'>Gravatars</a>?"), |
106
|
|
|
DropdownField::create("GravatarType", "Gravatar Type", array( |
107
|
|
|
"standard" => _t('Forum.STANDARD', 'Standard'), |
108
|
|
|
"identicon" => _t('Forum.IDENTICON', 'Identicon'), |
109
|
|
|
"wavatar" => _t('Forum.WAVATAR', 'Wavatar'), |
110
|
|
|
"monsterid" => _t('Forum.MONSTERID', 'Monsterid'), |
111
|
|
|
"retro" => _t('Forum.RETRO', 'Retro'), |
112
|
|
|
"mm" => _t('Forum.MM', 'Mystery Man'), |
113
|
|
|
))->setEmptyString('Use Forum Default') |
114
|
|
|
)); |
115
|
|
|
|
116
|
|
|
// add a grid field to the category tab with all the categories |
117
|
|
|
$categoryConfig = GridFieldConfig::create() |
118
|
|
|
->addComponents( |
119
|
|
|
new GridFieldSortableHeader(), |
120
|
|
|
new GridFieldButtonRow(), |
121
|
|
|
new GridFieldDataColumns(), |
122
|
|
|
new GridFieldEditButton(), |
123
|
|
|
new GridFieldViewButton(), |
124
|
|
|
new GridFieldDeleteAction(), |
125
|
|
|
new GridFieldAddNewButton('buttons-before-left'), |
126
|
|
|
new GridFieldPaginator(), |
127
|
|
|
new GridFieldDetailForm() |
128
|
|
|
); |
129
|
|
|
|
130
|
|
|
$categories = GridField::create( |
131
|
|
|
'Category', |
132
|
|
|
_t('Forum.FORUMCATEGORY', 'Forum Category'), |
133
|
|
|
$self->Categories(), |
134
|
|
|
$categoryConfig |
135
|
|
|
); |
136
|
|
|
|
137
|
|
|
$fields->addFieldsToTab("Root.Categories", $categories); |
138
|
|
|
|
139
|
|
|
|
140
|
|
|
$fields->addFieldsToTab("Root.LanguageFilter", array( |
141
|
|
|
TextField::create("ForbiddenWords", "Forbidden words (comma separated)"), |
142
|
|
|
LiteralField::create("FWLabel", "These words will be replaced by an asterisk") |
143
|
|
|
)); |
144
|
|
|
|
145
|
|
|
$fields->addFieldToTab("Root.Access", HeaderField::create(_t('Forum.ACCESSPOST', 'Who can post to the forum?'), 2)); |
146
|
|
|
$fields->addFieldToTab("Root.Access", OptionsetField::create("CanPostType", "", array( |
147
|
|
|
"Anyone" => _t('Forum.READANYONE', 'Anyone'), |
148
|
|
|
"LoggedInUsers" => _t('Forum.READLOGGEDIN', 'Logged-in users'), |
149
|
|
|
"NoOne" => _t('Forum.READNOONE', 'Nobody. Make Forum Read Only') |
150
|
|
|
))); |
151
|
|
|
}); |
152
|
|
|
|
153
|
|
|
$fields = parent::getCMSFields(); |
154
|
|
|
|
155
|
|
|
return $fields; |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
public function canPost($member = null) |
159
|
|
|
{ |
160
|
|
|
if (!$member) { |
161
|
|
|
$member = Member::currentUser(); |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
if ($this->CanPostType == "NoOne") { |
165
|
|
|
return false; |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
if ($this->CanPostType == "Anyone" || $this->canEdit($member)) { |
169
|
|
|
return true; |
170
|
|
|
} |
171
|
|
|
|
172
|
|
View Code Duplication |
if ($member) { |
|
|
|
|
173
|
|
|
if ($member->IsSuspended()) { |
174
|
|
|
return false; |
175
|
|
|
} |
176
|
|
|
if ($member->IsBanned()) { |
177
|
|
|
return false; |
178
|
|
|
} |
179
|
|
|
if ($this->CanPostType == "LoggedInUsers") { |
180
|
|
|
return true; |
181
|
|
|
} |
182
|
|
|
|
183
|
|
|
if ($groups = $this->PosterGroups()) { |
184
|
|
|
foreach ($groups as $group) { |
185
|
|
|
if ($member->inGroup($group)) { |
186
|
|
|
return true; |
187
|
|
|
} |
188
|
|
|
} |
189
|
|
|
} |
190
|
|
|
} |
191
|
|
|
|
192
|
|
|
return false; |
193
|
|
|
} |
194
|
|
|
|
195
|
|
|
/** |
196
|
|
|
* Ensure that any categories that exist with no forum holder are updated to be owned by the first forum holder |
197
|
|
|
* if there is one. This is required now that multiple forum holds are allowed, and categories belong to holders. |
198
|
|
|
* |
199
|
|
|
* @see sapphire/core/model/DataObject#requireDefaultRecords() |
200
|
|
|
*/ |
201
|
|
|
public function requireDefaultRecords() |
202
|
|
|
{ |
203
|
|
|
parent::requireDefaultRecords(); |
204
|
|
|
|
205
|
|
|
$forumCategories = ForumCategory::get()->filter('ForumHolderID', 0); |
206
|
|
|
if (!$forumCategories->exists()) { |
207
|
|
|
return; |
208
|
|
|
} |
209
|
|
|
|
210
|
|
|
$forumHolder = ForumHolder::get()->first(); |
211
|
|
|
if (!$forumHolder) { |
212
|
|
|
return; |
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
foreach ($forumCategories as $forumCategory) { |
216
|
|
|
$forumCategory->ForumHolderID = $forumHolder->ID; |
217
|
|
|
$forumCategory->write(); |
218
|
|
|
} |
219
|
|
|
} |
220
|
|
|
|
221
|
|
|
/** |
222
|
|
|
* If we're on the search action, we need to at least show |
223
|
|
|
* a breadcrumb to get back to the ForumHolder page. |
224
|
|
|
* @return string |
225
|
|
|
*/ |
226
|
|
|
public function Breadcrumbs($maxDepth = 20, $unlinked = false, $stopAtPageType = false, $showHidden = false) |
227
|
|
|
{ |
228
|
|
|
if (isset($this->urlParams['Action'])) { |
229
|
|
|
switch ($this->urlParams['Action']) { |
230
|
|
|
case 'search': |
231
|
|
|
return '<a href="' . $this->Link() . '">' . $this->Title . '</a> » ' . _t('SEARCHBREADCRUMB', 'Search'); |
232
|
|
|
case 'memberlist': |
233
|
|
|
return '<a href="' . $this->Link() . '">' . $this->Title . '</a> » ' . _t('MEMBERLIST', 'Member List'); |
234
|
|
|
case 'popularthreads': |
235
|
|
|
return '<a href="' . $this->Link() . '">' . $this->Title . '</a> » ' . _t('MOSTPOPULARTHREADS', 'Most popular threads'); |
236
|
|
|
} |
237
|
|
|
} |
238
|
|
|
} |
239
|
|
|
|
240
|
|
|
|
241
|
|
|
/** |
242
|
|
|
* Get the number of total posts |
243
|
|
|
* |
244
|
|
|
* @return int Returns the number of posts |
245
|
|
|
*/ |
246
|
|
View Code Duplication |
public function getNumPosts() |
|
|
|
|
247
|
|
|
{ |
248
|
|
|
$sqlQuery = new SQLQuery(); |
|
|
|
|
249
|
|
|
$sqlQuery->setFrom('"Post"'); |
250
|
|
|
$sqlQuery->setSelect('COUNT("Post"."ID")'); |
251
|
|
|
$sqlQuery->addInnerJoin('Member', '"Post"."AuthorID" = "Member"."ID"'); |
252
|
|
|
$sqlQuery->addInnerJoin('SiteTree', '"Post"."ForumID" = "SiteTree"."ID"'); |
253
|
|
|
$sqlQuery->addWhere('"Member"."ForumStatus" = \'Normal\''); |
254
|
|
|
$sqlQuery->addWhere('"SiteTree"."ParentID" = ' . $this->ID); |
255
|
|
|
return $sqlQuery->execute()->value(); |
256
|
|
|
} |
257
|
|
|
|
258
|
|
|
|
259
|
|
|
/** |
260
|
|
|
* Get the number of total topics (threads) |
261
|
|
|
* |
262
|
|
|
* @return int Returns the number of topics (threads) |
263
|
|
|
*/ |
264
|
|
View Code Duplication |
public function getNumTopics() |
|
|
|
|
265
|
|
|
{ |
266
|
|
|
$sqlQuery = new SQLQuery(); |
|
|
|
|
267
|
|
|
$sqlQuery->setFrom('"Post"'); |
268
|
|
|
$sqlQuery->setSelect('COUNT(DISTINCT("ThreadID"))'); |
269
|
|
|
$sqlQuery->addInnerJoin('Member', '"Post"."AuthorID" = "Member"."ID"'); |
270
|
|
|
$sqlQuery->addInnerJoin('SiteTree', '"Post"."ForumID" = "SiteTree"."ID"'); |
271
|
|
|
$sqlQuery->addWhere('"Member"."ForumStatus" = \'Normal\''); |
272
|
|
|
$sqlQuery->addWhere('"SiteTree"."ParentID" = ' . $this->ID); |
273
|
|
|
return $sqlQuery->execute()->value(); |
274
|
|
|
} |
275
|
|
|
|
276
|
|
|
|
277
|
|
|
/** |
278
|
|
|
* Get the number of distinct authors |
279
|
|
|
* |
280
|
|
|
* @return int Returns the number of distinct authors |
281
|
|
|
*/ |
282
|
|
View Code Duplication |
public function getNumAuthors() |
|
|
|
|
283
|
|
|
{ |
284
|
|
|
$sqlQuery = new SQLQuery(); |
|
|
|
|
285
|
|
|
$sqlQuery->setFrom('"Post"'); |
286
|
|
|
$sqlQuery->setSelect('COUNT(DISTINCT("AuthorID"))'); |
287
|
|
|
$sqlQuery->addInnerJoin('Member', '"Post"."AuthorID" = "Member"."ID"'); |
288
|
|
|
$sqlQuery->addInnerJoin('SiteTree', '"Post"."ForumID" = "SiteTree"."ID"'); |
289
|
|
|
$sqlQuery->addWhere('"Member"."ForumStatus" = \'Normal\''); |
290
|
|
|
$sqlQuery->addWhere('"SiteTree"."ParentID" = ' . $this->ID); |
291
|
|
|
return $sqlQuery->execute()->value(); |
292
|
|
|
} |
293
|
|
|
|
294
|
|
|
/** |
295
|
|
|
* Is the "Currently Online" functionality enabled? |
296
|
|
|
* @return bool |
297
|
|
|
*/ |
298
|
|
|
public function CurrentlyOnlineEnabled() |
299
|
|
|
{ |
300
|
|
|
return $this->config()->currently_online_enabled; |
301
|
|
|
} |
302
|
|
|
|
303
|
|
|
/** |
304
|
|
|
* Get a list of currently online users (last 15 minutes) |
305
|
|
|
* that belong to the "forum-members" code {@link Group}. |
306
|
|
|
* |
307
|
|
|
* @return DataList of {@link Member} objects |
308
|
|
|
*/ |
309
|
|
|
public function CurrentlyOnline() |
310
|
|
|
{ |
311
|
|
|
if (!$this->CurrentlyOnlineEnabled()) { |
312
|
|
|
return false; |
|
|
|
|
313
|
|
|
} |
314
|
|
|
|
315
|
|
|
$groupIDs = array(); |
316
|
|
|
|
317
|
|
|
if ($forumGroup = Group::get()->filter('Code', 'forum-members')->first()) { |
318
|
|
|
$groupIDs[] = $forumGroup->ID; |
319
|
|
|
} |
320
|
|
|
|
321
|
|
|
if ($adminGroup = Group::get()->filter('Code', array('administrators', 'Administrators'))->first()) { |
322
|
|
|
$groupIDs[] = $adminGroup->ID; |
323
|
|
|
} |
324
|
|
|
|
325
|
|
|
return Member::get() |
326
|
|
|
->leftJoin('Group_Members', '"Member"."ID" = "Group_Members"."MemberID"') |
327
|
|
|
->filter('GroupID', $groupIDs) |
328
|
|
|
->where('"Member"."LastViewed" > ' . DB::getConn()->datetimeIntervalClause('NOW', '-15 MINUTE')) |
|
|
|
|
329
|
|
|
->sort('"Member"."FirstName", "Member"."Surname"'); |
330
|
|
|
} |
331
|
|
|
|
332
|
|
|
/** |
333
|
|
|
* @deprecated 0.5 |
334
|
|
|
*/ |
335
|
|
|
public function LatestMember($limit = 1) |
336
|
|
|
{ |
337
|
|
|
user_error('Please use LatestMembers($limit) instead of LatestMember', E_USER_NOTICE); |
338
|
|
|
|
339
|
|
|
return $this->LatestMembers($limit); |
340
|
|
|
} |
341
|
|
|
|
342
|
|
|
/** |
343
|
|
|
* Get the latest members from the forum group. |
344
|
|
|
* |
345
|
|
|
* @param int $limit Number of members to return |
346
|
|
|
* @return ArrayList |
347
|
|
|
*/ |
348
|
|
|
public function getLatestMembers($limit = null) |
349
|
|
|
{ |
350
|
|
|
if (!is_null($limit)) { |
351
|
|
|
Deprecation::notice('1.0', '$limit parameter is deprecated, please chain the limit clause'); |
352
|
|
|
} |
353
|
|
|
$groupID = DB::query('SELECT "ID" FROM "Group" WHERE "Code" = \'forum-members\'')->value(); |
354
|
|
|
|
355
|
|
|
// if we're just looking for a single MemberID, do a quicker query on the join table. |
356
|
|
|
if ($limit == 1) { |
357
|
|
|
$latestMemberId = DB::query(sprintf( |
358
|
|
|
'SELECT MAX("MemberID") |
359
|
|
|
FROM "Group_Members" |
360
|
|
|
WHERE "Group_Members"."GroupID" = \'%s\'', |
361
|
|
|
$groupID |
362
|
|
|
))->value(); |
363
|
|
|
|
364
|
|
|
$latestMembers = Member::get()->byId($latestMemberId); |
|
|
|
|
365
|
|
|
} else { |
366
|
|
|
$latestMembers = Member::get() |
367
|
|
|
->leftJoin('Group_Members', '"Member"."ID" = "Group_Members"."MemberID"') |
368
|
|
|
->filter('GroupID', $groupID) |
369
|
|
|
->sort('"Member"."ID" DESC'); |
370
|
|
|
if ($limit) { |
|
|
|
|
371
|
|
|
$latestMembers = $latestMembers->limit($limit); |
372
|
|
|
} |
373
|
|
|
} |
374
|
|
|
|
375
|
|
|
return $latestMembers; |
376
|
|
|
} |
377
|
|
|
|
378
|
|
|
/** |
379
|
|
|
* Get a list of Forum Categories |
380
|
|
|
* @return DataList |
381
|
|
|
*/ |
382
|
|
|
public function getShowInCategories() |
383
|
|
|
{ |
384
|
|
|
$forumCategories = ForumCategory::get()->filter('ForumHolderID', $this->ID); |
385
|
|
|
$showInCategories = $this->getField('ShowInCategories'); |
386
|
|
|
return $forumCategories->exists() && $showInCategories; |
387
|
|
|
} |
388
|
|
|
|
389
|
|
|
/** |
390
|
|
|
* Get the forums. Actually its a bit more complex than that |
391
|
|
|
* we need to group by the Forum Categories. |
392
|
|
|
* |
393
|
|
|
* @return ArrayList |
394
|
|
|
*/ |
395
|
|
|
public function Forums() |
396
|
|
|
{ |
397
|
|
|
$categoryText = isset($_REQUEST['Category']) ? Convert::raw2xml($_REQUEST['Category']) : null; |
398
|
|
|
$holder = $this; |
399
|
|
|
|
400
|
|
|
if ($this->getShowInCategories()) { |
401
|
|
|
return ForumCategory::get() |
402
|
|
|
->filter('ForumHolderID', $this->ID) |
403
|
|
|
->filterByCallback(function ($category) use ($categoryText, $holder) { |
404
|
|
|
// Don't include if we've specified a Category, and it doesn't match this one |
405
|
|
|
if ($categoryText !== null && $category->Title != $categoryText) { |
406
|
|
|
return false; |
407
|
|
|
} |
408
|
|
|
|
409
|
|
|
// Get a list of forums that live under this holder & category |
410
|
|
|
$category->CategoryForums = Forum::get() |
411
|
|
|
->filter(array( |
412
|
|
|
'CategoryID' => $category->ID, |
413
|
|
|
'ParentID' => $holder->ID, |
414
|
|
|
'ShowInMenus' => 1 |
415
|
|
|
)) |
416
|
|
|
->filterByCallback(function ($forum) { |
417
|
|
|
return $forum->canView(); |
418
|
|
|
}); |
419
|
|
|
|
420
|
|
|
return $category->CategoryForums->exists(); |
421
|
|
|
}); |
422
|
|
|
} else { |
423
|
|
|
return Forum::get() |
424
|
|
|
->filter(array( |
425
|
|
|
'ParentID' => $this->ID, |
426
|
|
|
'ShowInMenus' => 1 |
427
|
|
|
)) |
428
|
|
|
->filterByCallback(function ($forum) { |
429
|
|
|
return $forum->canView(); |
430
|
|
|
}); |
431
|
|
|
} |
432
|
|
|
} |
433
|
|
|
|
434
|
|
|
/** |
435
|
|
|
* A function that returns the correct base table to use for custom forum queries. It uses the getVar stage to determine |
436
|
|
|
* what stage we are looking at, and determines whether to use SiteTree or SiteTree_Live (the general case). If the stage is |
437
|
|
|
* not specified, live is assumed (general case). It is a static function so it can be used for both ForumHolder and Forum. |
438
|
|
|
* |
439
|
|
|
* @return String |
440
|
|
|
*/ |
441
|
|
|
static function baseForumTable() |
|
|
|
|
442
|
|
|
{ |
443
|
|
|
$stage = (Controller::curr()->getRequest()) ? Controller::curr()->getRequest()->getVar('stage') : false; |
444
|
|
|
if (!$stage) { |
445
|
|
|
$stage = Versioned::get_live_stage(); |
446
|
|
|
} |
447
|
|
|
|
448
|
|
|
if ((class_exists('SapphireTest', false) && SapphireTest::is_running_test()) |
449
|
|
|
|| $stage == "Stage" |
450
|
|
|
) { |
451
|
|
|
return "SiteTree"; |
452
|
|
|
} else { |
453
|
|
|
return "SiteTree_Live"; |
454
|
|
|
} |
455
|
|
|
} |
456
|
|
|
|
457
|
|
|
|
458
|
|
|
/** |
459
|
|
|
* Is OpenID support available? |
460
|
|
|
* |
461
|
|
|
* This method checks if the {@link OpenIDAuthenticator} is available and |
462
|
|
|
* registered. |
463
|
|
|
* |
464
|
|
|
* @return bool Returns TRUE if OpenID is available, FALSE otherwise. |
465
|
|
|
*/ |
466
|
|
|
public function OpenIDAvailable() |
467
|
|
|
{ |
468
|
|
|
if (class_exists('Authenticator') == false) { |
|
|
|
|
469
|
|
|
return false; |
470
|
|
|
} |
471
|
|
|
|
472
|
|
|
return Authenticator::is_registered("OpenIDAuthenticator"); |
473
|
|
|
} |
474
|
|
|
|
475
|
|
|
|
476
|
|
|
/** |
477
|
|
|
* Get the latest posts |
478
|
|
|
* |
479
|
|
|
* @param int $limit Number of posts to return |
480
|
|
|
* @param int $forumID - Forum ID to limit it to |
481
|
|
|
* @param int $threadID - Thread ID to limit it to |
482
|
|
|
* @param int $lastVisit Optional: Unix timestamp of the last visit (GMT) |
483
|
|
|
* @param int $lastPostID Optional: ID of the last read post |
484
|
|
|
*/ |
485
|
|
|
public function getRecentPosts($limit = 50, $forumID = null, $threadID = null, $lastVisit = null, $lastPostID = null) |
486
|
|
|
{ |
487
|
|
|
$filter = array(); |
488
|
|
|
|
489
|
|
|
if ($lastVisit) { |
|
|
|
|
490
|
|
|
$lastVisit = @date('Y-m-d H:i:s', $lastVisit); |
491
|
|
|
} |
492
|
|
|
|
493
|
|
|
$lastPostID = (int) $lastPostID; |
494
|
|
|
|
495
|
|
|
// last post viewed |
496
|
|
|
if ($lastPostID > 0) { |
497
|
|
|
$filter[] = "\"Post\".\"ID\" > '". Convert::raw2sql($lastPostID) ."'"; |
498
|
|
|
} |
499
|
|
|
|
500
|
|
|
// last time visited |
501
|
|
|
if ($lastVisit) { |
502
|
|
|
$filter[] = "\"Post\".\"Created\" > '". Convert::raw2sql($lastVisit) ."'"; |
503
|
|
|
} |
504
|
|
|
|
505
|
|
|
// limit to a forum |
506
|
|
|
if ($forumID) { |
|
|
|
|
507
|
|
|
$filter[] = "\"Post\".\"ForumID\" = '". Convert::raw2sql($forumID) ."'"; |
508
|
|
|
} |
509
|
|
|
|
510
|
|
|
// limit to a thread |
511
|
|
|
if ($threadID) { |
|
|
|
|
512
|
|
|
$filter[] = "\"Post\".\"ThreadID\" = '". Convert::raw2sql($threadID) ."'"; |
513
|
|
|
} |
514
|
|
|
|
515
|
|
|
// limit to just this forum install |
516
|
|
|
$filter[] = "\"ForumPage\".\"ParentID\"='{$this->ID}'"; |
517
|
|
|
|
518
|
|
|
$posts = Post::get() |
519
|
|
|
->leftJoin('ForumThread', '"Post"."ThreadID" = "ForumThread"."ID"') |
520
|
|
|
->leftJoin(ForumHolder::baseForumTable(), '"ForumPage"."ID" = "Post"."ForumID"', 'ForumPage') |
521
|
|
|
->limit($limit) |
522
|
|
|
->sort('"Post"."ID"', 'DESC') |
523
|
|
|
->where($filter); |
524
|
|
|
|
525
|
|
|
$recentPosts = new ArrayList(); |
526
|
|
|
foreach ($posts as $post) { |
527
|
|
|
$recentPosts->push($post); |
528
|
|
|
} |
529
|
|
|
if ($recentPosts->count() > 0) { |
530
|
|
|
return $recentPosts; |
531
|
|
|
} |
532
|
|
|
return null; |
533
|
|
|
} |
534
|
|
|
|
535
|
|
|
|
536
|
|
|
/** |
537
|
|
|
* Are new posts available? |
538
|
|
|
* |
539
|
|
|
* @param int $id |
540
|
|
|
* @param array $data Optional: If an array is passed, the timestamp of |
541
|
|
|
* the last created post and it's ID will be stored in |
542
|
|
|
* it (keys: 'last_id', 'last_created') |
543
|
|
|
* @param int $lastVisit Unix timestamp of the last visit (GMT) |
544
|
|
|
* @param int $lastPostID ID of the last read post |
545
|
|
|
* @param int $thread ID of the relevant topic (set to NULL for all |
|
|
|
|
546
|
|
|
* topics) |
547
|
|
|
* @return bool Returns TRUE if there are new posts available, otherwise |
548
|
|
|
* FALSE. |
549
|
|
|
*/ |
550
|
|
|
public static function new_posts_available($id, &$data = array(), $lastVisit = null, $lastPostID = null, $forumID = null, $threadID = null) |
551
|
|
|
{ |
552
|
|
|
$filter = array(); |
553
|
|
|
|
554
|
|
|
// last post viewed |
555
|
|
|
$filter[] = "\"ForumPage\".\"ParentID\" = '". Convert::raw2sql($id) ."'"; |
556
|
|
|
if ($lastPostID) { |
|
|
|
|
557
|
|
|
$filter[] = "\"Post\".\"ID\" > '". Convert::raw2sql($lastPostID) ."'"; |
558
|
|
|
} |
559
|
|
|
if ($lastVisit) { |
|
|
|
|
560
|
|
|
$filter[] = "\"Post\".\"Created\" > '". Convert::raw2sql($lastVisit) ."'"; |
561
|
|
|
} |
562
|
|
|
if ($forumID) { |
563
|
|
|
$filter[] = "\"Post\".\"ForumID\" = '". Convert::raw2sql($forumID) ."'"; |
564
|
|
|
} |
565
|
|
|
if ($threadID) { |
566
|
|
|
$filter[] = "\"ThreadID\" = '". Convert::raw2sql($threadID) ."'"; |
567
|
|
|
} |
568
|
|
|
|
569
|
|
|
$filter = implode(" AND ", $filter); |
570
|
|
|
|
571
|
|
|
$version = DB::query(" |
572
|
|
|
SELECT MAX(\"Post\".\"ID\") AS \"LastID\", MAX(\"Post\".\"Created\") AS \"LastCreated\" |
573
|
|
|
FROM \"Post\" |
574
|
|
|
JOIN \"" . ForumHolder::baseForumTable() . "\" AS \"ForumPage\" ON \"Post\".\"ForumID\"=\"ForumPage\".\"ID\" |
575
|
|
|
WHERE $filter")->first(); |
576
|
|
|
|
577
|
|
|
if ($version == false) { |
578
|
|
|
return false; |
579
|
|
|
} |
580
|
|
|
|
581
|
|
|
if ($data) { |
|
|
|
|
582
|
|
|
$data['last_id'] = (int)$version['LastID']; |
583
|
|
|
$data['last_created'] = strtotime($version['LastCreated']); |
584
|
|
|
} |
585
|
|
|
|
586
|
|
|
$lastVisit = (int) $lastVisit; |
587
|
|
|
|
588
|
|
|
if ($lastVisit <= 0) { |
589
|
|
|
$lastVisit = false; |
590
|
|
|
} |
591
|
|
|
|
592
|
|
|
$lastPostID = (int)$lastPostID; |
593
|
|
|
if ($lastPostID <= 0) { |
594
|
|
|
$lastPostID = false; |
595
|
|
|
} |
596
|
|
|
|
597
|
|
|
if (!$lastVisit && !$lastPostID) { |
|
|
|
|
598
|
|
|
return true; |
599
|
|
|
} |
600
|
|
|
if ($lastVisit && (strtotime($version['LastCreated']) > $lastVisit)) { |
|
|
|
|
601
|
|
|
return true; |
602
|
|
|
} |
603
|
|
|
|
604
|
|
|
if ($lastPostID && ((int)$version['LastID'] > $lastPostID)) { |
|
|
|
|
605
|
|
|
return true; |
606
|
|
|
} |
607
|
|
|
|
608
|
|
|
return false; |
609
|
|
|
} |
610
|
|
|
|
611
|
|
|
/** |
612
|
|
|
* Helper Method from the template includes. Uses $ForumHolder so in order for it work |
613
|
|
|
* it needs to be included on this page |
614
|
|
|
* |
615
|
|
|
* @return ForumHolder |
616
|
|
|
*/ |
617
|
|
|
public function getForumHolder() |
618
|
|
|
{ |
619
|
|
|
return $this; |
620
|
|
|
} |
621
|
|
|
} |
622
|
|
|
|
623
|
|
|
|
624
|
|
|
class ForumHolder_Controller extends Page_Controller |
625
|
|
|
{ |
626
|
|
|
|
627
|
|
|
private static $allowed_actions = array( |
628
|
|
|
'popularthreads', |
629
|
|
|
'login', |
630
|
|
|
'logout', |
631
|
|
|
'search', |
632
|
|
|
'rss', |
633
|
|
|
); |
634
|
|
|
|
635
|
|
|
public function init() |
636
|
|
|
{ |
637
|
|
|
parent::init(); |
638
|
|
|
|
639
|
|
|
Requirements::javascript(THIRDPARTY_DIR . "/jquery/jquery.js"); |
640
|
|
|
Requirements::javascript("forum/javascript/jquery.MultiFile.js"); |
641
|
|
|
Requirements::javascript("forum/javascript/forum.js"); |
642
|
|
|
|
643
|
|
|
Requirements::themedCSS('Forum', 'forum', 'all'); |
644
|
|
|
|
645
|
|
|
RSSFeed::linkToFeed($this->Link("rss"), _t('ForumHolder.POSTSTOALLFORUMS', "Posts to all forums")); |
646
|
|
|
|
647
|
|
|
// Set the back url |
648
|
|
View Code Duplication |
if (isset($_SERVER['REQUEST_URI'])) { |
|
|
|
|
649
|
|
|
Session::set('BackURL', $_SERVER['REQUEST_URI']); |
650
|
|
|
} else { |
651
|
|
|
Session::set('BackURL', $this->Link()); |
652
|
|
|
} |
653
|
|
|
} |
654
|
|
|
|
655
|
|
|
/** |
656
|
|
|
* Generate a complete list of all the members data. Return a |
657
|
|
|
* set of all these members sorted by a GET variable |
658
|
|
|
* |
659
|
|
|
* @todo Sort via AJAX |
660
|
|
|
* @return DataObjectSet A DataObjectSet of all the members which are signed up |
661
|
|
|
*/ |
662
|
|
|
public function memberlist() |
663
|
|
|
{ |
664
|
|
|
return $this->httpError(404); |
665
|
|
|
|
666
|
|
|
$forumGroupID = (int) DataObject::get_one('Group', "\"Code\" = 'forum-members'")->ID; |
|
|
|
|
667
|
|
|
|
668
|
|
|
// If sort has been defined then save it as in the session |
669
|
|
|
$order = (isset($_GET['order'])) ? $_GET['order']: ""; |
670
|
|
|
|
671
|
|
|
if (!isset($_GET['start']) || !is_numeric($_GET['start']) || (int) $_GET['start'] < 1) { |
672
|
|
|
$_GET['start'] = 0; |
673
|
|
|
} |
674
|
|
|
|
675
|
|
|
$SQL_start = (int) $_GET['start']; |
676
|
|
|
|
677
|
|
|
switch ($order) { |
678
|
|
|
case "joined": |
679
|
|
|
// $members = DataObject::get("Member", "\"GroupID\" = '$forumGroupID'", "\"Member\".\"Created\" ASC", "LEFT JOIN \"Group_Members\" ON \"Member\".\"ID\" = \"Group_Members\".\"MemberID\"", "{$SQL_start},100"); |
680
|
|
|
$members = Member::get() |
681
|
|
|
->filter('Member.GroupID', $forumGroupID) |
682
|
|
|
->leftJoin('Group_Members', '"Member"."ID" = "Group_Members"."MemberID"') |
683
|
|
|
->sort('"Member"."Created" ASC') |
684
|
|
|
->limit($SQL_start . ',100'); |
685
|
|
|
break; |
686
|
|
View Code Duplication |
case "name": |
|
|
|
|
687
|
|
|
// $members = DataObject::get("Member", "\"GroupID\" = '$forumGroupID'", "\"Member\".\"Nickname\" ASC", "LEFT JOIN \"Group_Members\" ON \"Member\".\"ID\" = \"Group_Members\".\"MemberID\"", "{$SQL_start},100"); |
688
|
|
|
$members = Member::get() |
689
|
|
|
->filter('Member.GroupID', $forumGroupID) |
690
|
|
|
->leftJoin('Group_Members', '"Member"."ID" = "Group_Members"."MemberID"') |
691
|
|
|
->sort('"Member"."Nickname" ASC') |
692
|
|
|
->limit($SQL_start . ',100'); |
693
|
|
|
break; |
694
|
|
View Code Duplication |
case "country": |
|
|
|
|
695
|
|
|
// $members = DataObject::get("Member", "\"GroupID\" = '$forumGroupID' AND \"Member\".\"CountryPublic\" = TRUE", "\"Member\".\"Country\" ASC", "LEFT JOIN \"Group_Members\" ON \"Member\".\"ID\" = \"Group_Members\".\"MemberID\"", "{$SQL_start},100"); |
696
|
|
|
$members = Member::get() |
697
|
|
|
->filter(array('Member.GroupID' => $forumGroupID, 'Member.CountryPublic' => true)) |
698
|
|
|
->leftJoin('Group_Members', '"Member"."ID" = "Group_Members"."MemberID"') |
699
|
|
|
->sort('"Member"."Nickname" ASC') |
700
|
|
|
->limit($SQL_start . ',100'); |
701
|
|
|
break; |
702
|
|
|
case "posts": |
703
|
|
|
$query = singleton('Member')->extendedSQL('', "\"NumPosts\" DESC", "{$SQL_start},100"); |
704
|
|
|
$query->select[] = "(SELECT COUNT(*) FROM \"Post\" WHERE \"Post\".\"AuthorID\" = \"Member\".\"ID\") AS \"NumPosts\""; |
705
|
|
|
$records = $query->execute(); |
706
|
|
|
$members = singleton('Member')->buildDataObjectSet($records, 'DataObjectSet', $query, 'Member'); |
707
|
|
|
$members->parseQueryLimit($query); |
708
|
|
|
break; |
709
|
|
|
default: |
710
|
|
|
//$members = DataObject::get("Member", "\"GroupID\" = '$forumGroupID'", "\"Member\".\"Created\" DESC", "LEFT JOIN \"Group_Members\" ON \"Member\".\"ID\" = \"Group_Members\".\"MemberID\"", "{$SQL_start},100"); |
711
|
|
|
$members = Member::get() |
712
|
|
|
->filter('Member.GroupID', $forumGroupID) |
713
|
|
|
->leftJoin('Group_Members', '"Member"."ID" = "Group_Members"."MemberID"') |
714
|
|
|
->sort('"Member"."Created" DESC') |
715
|
|
|
->limit($SQL_start . ',100'); |
716
|
|
|
break; |
717
|
|
|
} |
718
|
|
|
|
719
|
|
|
return array( |
|
|
|
|
720
|
|
|
'Subtitle' => _t('ForumHolder.MEMBERLIST', 'Forum member List'), |
721
|
|
|
'Abstract' => $this->MemberListAbstract, |
722
|
|
|
'Members' => $members, |
723
|
|
|
'Title' => _t('ForumHolder.MEMBERLIST', 'Forum member List') |
724
|
|
|
); |
725
|
|
|
} |
726
|
|
|
|
727
|
|
|
/** |
728
|
|
|
* Show the 20 most popular threads across all {@link Forum} children. |
729
|
|
|
* |
730
|
|
|
* Two configuration options are available: |
731
|
|
|
* 1. "posts" - most popular threads by posts |
732
|
|
|
* 2. "views" - most popular threads by views |
733
|
|
|
* |
734
|
|
|
* e.g. mysite.com/forums/popularthreads?by=posts |
735
|
|
|
* |
736
|
|
|
* @return array |
737
|
|
|
*/ |
738
|
|
|
public function popularthreads() |
739
|
|
|
{ |
740
|
|
|
$start = isset($_GET['start']) ? (int) $_GET['start'] : 0; |
741
|
|
|
$limit = 20; |
742
|
|
|
$method = isset($_GET['by']) ? $_GET['by'] : null; |
743
|
|
|
if (!$method) { |
744
|
|
|
$method = 'posts'; |
745
|
|
|
} |
746
|
|
|
|
747
|
|
|
if ($method == 'posts') { |
748
|
|
|
$threadsQuery = singleton('ForumThread')->buildSQL( |
749
|
|
|
"\"SiteTree\".\"ParentID\" = '" . $this->ID ."'", |
750
|
|
|
"\"PostCount\" DESC", |
751
|
|
|
"$start,$limit", |
752
|
|
|
"LEFT JOIN \"Post\" ON \"Post\".\"ThreadID\" = \"ForumThread\".\"ID\" LEFT JOIN \"SiteTree\" ON \"SiteTree\".\"ID\" = \"ForumThread\".\"ForumID\"" |
753
|
|
|
); |
754
|
|
|
$threadsQuery->select[] = "COUNT(\"Post\".\"ID\") AS 'PostCount'"; |
755
|
|
|
$threadsQuery->groupby[] = "\"ForumThread\".\"ID\""; |
756
|
|
|
$threads = singleton('ForumThread')->buildDataObjectSet($threadsQuery->execute()); |
757
|
|
|
if ($threads) { |
758
|
|
|
$threads->setPageLimits($start, $limit, $threadsQuery->unlimitedRowCount()); |
759
|
|
|
} |
760
|
|
|
} elseif ($method == 'views') { |
761
|
|
|
$threads = DataObject::get('ForumThread', '', "\"NumViews\" DESC", '', "$start,$limit"); |
762
|
|
|
} |
763
|
|
|
|
764
|
|
|
return array( |
765
|
|
|
'Title' => _t('ForumHolder.POPULARTHREADS', 'Most popular forum threads'), |
766
|
|
|
'Subtitle' => _t('ForumHolder.POPULARTHREADS', 'Most popular forum threads'), |
767
|
|
|
'Method' => $method, |
768
|
|
|
'Threads' => $threads |
|
|
|
|
769
|
|
|
); |
770
|
|
|
} |
771
|
|
|
|
772
|
|
|
/** |
773
|
|
|
* The login action |
774
|
|
|
* |
775
|
|
|
* It simple sets the return URL and forwards to the standard login form. |
776
|
|
|
*/ |
777
|
|
|
public function login() |
778
|
|
|
{ |
779
|
|
|
Session::set('Security.Message.message', _t('Forum.CREDENTIALS')); |
780
|
|
|
Session::set('Security.Message.type', 'status'); |
781
|
|
|
Session::set("BackURL", $this->Link()); |
782
|
|
|
|
783
|
|
|
$this->redirect('Security/login'); |
784
|
|
|
} |
785
|
|
|
|
786
|
|
|
|
787
|
|
|
public function logout() |
788
|
|
|
{ |
789
|
|
|
if ($member = Member::currentUser()) { |
790
|
|
|
$member->logOut(); |
791
|
|
|
} |
792
|
|
|
|
793
|
|
|
$this->redirect($this->Link()); |
794
|
|
|
} |
795
|
|
|
|
796
|
|
|
/** |
797
|
|
|
* The search action |
798
|
|
|
* |
799
|
|
|
* @return array Returns an array to render the search results. |
800
|
|
|
*/ |
801
|
|
|
public function search() |
802
|
|
|
{ |
803
|
|
|
$keywords = (isset($_REQUEST['Search'])) ? Convert::raw2xml($_REQUEST['Search']) : null; |
804
|
|
|
$order = (isset($_REQUEST['order'])) ? Convert::raw2xml($_REQUEST['order']) : null; |
805
|
|
|
$start = (isset($_REQUEST['start'])) ? (int) $_REQUEST['start'] : 0; |
806
|
|
|
|
807
|
|
|
$abstract = ($keywords) ? "<p>" . sprintf(_t('ForumHolder.SEARCHEDFOR', "You searched for '%s'."), $keywords) . "</p>": null; |
808
|
|
|
|
809
|
|
|
// get the results of the query from the current search engine |
810
|
|
|
$search = ForumSearch::get_search_engine(); |
811
|
|
|
|
812
|
|
|
if ($search) { |
813
|
|
|
$engine = new $search(); |
814
|
|
|
|
815
|
|
|
$results = $engine->getResults($this->ID, $keywords, $order, $start); |
816
|
|
|
} else { |
817
|
|
|
$results = false; |
818
|
|
|
} |
819
|
|
|
|
820
|
|
|
//Paginate the results |
821
|
|
|
$results = PaginatedList::create( |
822
|
|
|
$results, |
823
|
|
|
$this->request->getVars() |
824
|
|
|
); |
825
|
|
|
|
826
|
|
|
|
827
|
|
|
// if the user has requested this search as an RSS feed then output the contents as xml |
828
|
|
|
// rather than passing it to the template |
829
|
|
|
if (isset($_REQUEST['rss'])) { |
830
|
|
|
$rss = new RSSFeed($results, $this->Link(), _t('ForumHolder.SEARCHRESULTS', 'Search results'), "", "Title", "RSSContent", "RSSAuthor"); |
831
|
|
|
|
832
|
|
|
return $rss->outputToBrowser(); |
833
|
|
|
} |
834
|
|
|
|
835
|
|
|
// attach a link to a RSS feed version of the search results |
836
|
|
|
$rssLink = $this->Link() ."search/?Search=".urlencode($keywords). "&order=".urlencode($order)."&rss"; |
837
|
|
|
RSSFeed::linkToFeed($rssLink, _t('ForumHolder.SEARCHRESULTS', 'Search results')); |
838
|
|
|
|
839
|
|
|
return array( |
840
|
|
|
"Subtitle" => DBField::create_field('Text', _t('ForumHolder.SEARCHRESULTS', 'Search results')), |
841
|
|
|
"Abstract" => DBField::create_field('HTMLText', $abstract), |
842
|
|
|
"Query" => DBField::create_field('Text', $_REQUEST['Search']), |
843
|
|
|
"Order" => DBField::create_field('Text', ($order) ? $order : "relevance"), |
844
|
|
|
"RSSLink" => DBField::create_field('HTMLText', $rssLink), |
845
|
|
|
"SearchResults" => $results |
846
|
|
|
); |
847
|
|
|
} |
848
|
|
|
|
849
|
|
|
/** |
850
|
|
|
* Get the RSS feed |
851
|
|
|
* |
852
|
|
|
* This method will output the RSS feed with the last 50 posts to the |
853
|
|
|
* browser. |
854
|
|
|
*/ |
855
|
|
|
public function rss() |
856
|
|
|
{ |
857
|
|
|
HTTP::set_cache_age(3600); // cache for one hour |
858
|
|
|
|
859
|
|
|
$threadID = null; |
860
|
|
|
$forumID = null; |
861
|
|
|
|
862
|
|
|
// optionally allow filtering of the forum posts by the url in the format |
863
|
|
|
// rss/thread/$ID or rss/forum/$ID |
864
|
|
|
if (isset($this->urlParams['ID']) && ($action = $this->urlParams['ID'])) { |
865
|
|
|
if (isset($this->urlParams['OtherID']) && ($id = $this->urlParams['OtherID'])) { |
866
|
|
|
switch ($action) { |
867
|
|
|
case 'forum': |
868
|
|
|
$forumID = (int) $id; |
869
|
|
|
break; |
870
|
|
|
case 'thread': |
871
|
|
|
$threadID = (int) $id; |
872
|
|
|
} |
873
|
|
|
} else { |
874
|
|
|
// fallback is that it is the ID of a forum like it was in |
875
|
|
|
// previous versions |
876
|
|
|
$forumID = (int) $action; |
877
|
|
|
} |
878
|
|
|
} |
879
|
|
|
|
880
|
|
|
$data = array('last_created' => null, 'last_id' => null); |
881
|
|
|
|
882
|
|
|
if (!isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && !isset($_SERVER['HTTP_IF_NONE_MATCH'])) { |
883
|
|
|
// just to get the version data.. |
884
|
|
|
$available = ForumHolder::new_posts_available($this->ID, $data, null, null, $forumID, $threadID); |
|
|
|
|
885
|
|
|
|
886
|
|
|
// No information provided by the client, just return the last posts |
887
|
|
|
$rss = new RSSFeed( |
888
|
|
|
$this->getRecentPosts(50, $forumID, $threadID), |
889
|
|
|
$this->Link() . 'rss', |
890
|
|
|
sprintf(_t('Forum.RSSFORUMPOSTSTO'), $this->Title), |
891
|
|
|
"", |
892
|
|
|
"Title", |
893
|
|
|
"RSSContent", |
894
|
|
|
"RSSAuthor", |
895
|
|
|
$data['last_created'], |
896
|
|
|
$data['last_id'] |
897
|
|
|
); |
898
|
|
|
return $rss->outputToBrowser(); |
899
|
|
|
} else { |
900
|
|
|
// Return only new posts, check the request headers! |
901
|
|
|
$since = null; |
902
|
|
|
$etag = null; |
903
|
|
|
|
904
|
|
|
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) { |
905
|
|
|
// Split the If-Modified-Since (Netscape < v6 gets this wrong) |
906
|
|
|
$since = explode(';', $_SERVER['HTTP_IF_MODIFIED_SINCE']); |
907
|
|
|
// Turn the client request If-Modified-Since into a timestamp |
908
|
|
|
$since = @strtotime($since[0]); |
909
|
|
|
if (!$since) { |
910
|
|
|
$since = null; |
911
|
|
|
} |
912
|
|
|
} |
913
|
|
|
|
914
|
|
|
if (isset($_SERVER['HTTP_IF_NONE_MATCH']) && is_numeric($_SERVER['HTTP_IF_NONE_MATCH'])) { |
915
|
|
|
$etag = (int)$_SERVER['HTTP_IF_NONE_MATCH']; |
916
|
|
|
} |
917
|
|
|
if ($available = ForumHolder::new_posts_available($this->ID, $data, $since, $etag, $forumID, $threadID)) { |
|
|
|
|
918
|
|
|
HTTP::register_modification_timestamp($data['last_created']); |
919
|
|
|
$rss = new RSSFeed( |
920
|
|
|
$this->getRecentPosts(50, $forumID, $threadID, $etag), |
921
|
|
|
$this->Link() . 'rss', |
922
|
|
|
sprintf(_t('Forum.RSSFORUMPOSTSTO'), $this->Title), |
923
|
|
|
"", |
924
|
|
|
"Title", |
925
|
|
|
"RSSContent", |
926
|
|
|
"RSSAuthor", |
927
|
|
|
$data['last_created'], |
928
|
|
|
$data['last_id'] |
929
|
|
|
); |
930
|
|
|
return $rss->outputToBrowser(); |
931
|
|
|
} else { |
932
|
|
|
if ($data['last_created']) { |
933
|
|
|
HTTP::register_modification_timestamp($data['last_created']); |
934
|
|
|
} |
935
|
|
|
|
936
|
|
|
if ($data['last_id']) { |
937
|
|
|
HTTP::register_etag($data['last_id']); |
938
|
|
|
} |
939
|
|
|
|
940
|
|
|
// There are no new posts, just output an "304 Not Modified" message |
941
|
|
|
HTTP::add_cache_headers(); |
942
|
|
|
header('HTTP/1.1 304 Not Modified'); |
943
|
|
|
} |
944
|
|
|
} |
945
|
|
|
exit; |
946
|
|
|
} |
947
|
|
|
|
948
|
|
|
/** |
949
|
|
|
* Return the GlobalAnnouncements from the individual forums |
950
|
|
|
* |
951
|
|
|
* @return DataObjectSet |
952
|
|
|
*/ |
953
|
|
|
public function GlobalAnnouncements() |
954
|
|
|
{ |
955
|
|
|
//dump(ForumHolder::baseForumTable()); |
956
|
|
|
|
957
|
|
|
// Get all the forums with global sticky threads |
958
|
|
|
return ForumThread::get() |
959
|
|
|
->filter('IsGlobalSticky', 1) |
960
|
|
|
->innerJoin(ForumHolder::baseForumTable(), '"ForumThread"."ForumID"="ForumPage"."ID"', "ForumPage") |
961
|
|
|
->where('"ForumPage"."ParentID" = '.$this->ID) |
962
|
|
|
->filterByCallback(function ($thread) { |
963
|
|
|
if ($thread->canView()) { |
964
|
|
|
$post = Post::get()->filter('ThreadID', $thread->ID)->sort('Post.Created DESC'); |
965
|
|
|
$thread->Post = $post; |
966
|
|
|
return true; |
967
|
|
|
} |
968
|
|
|
}); |
969
|
|
|
} |
970
|
|
|
} |
971
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.