on-demand release 2.3dev
[moodle.git] / mod / forum / rsslib.php
CommitLineData
1adbd2c3 1<?php
8adcb49f 2
8f685009
SH
3// This file is part of Moodle - http://moodle.org/
4//
5// Moodle is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// Moodle is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
17
18/**
13d1c9ed
JF
19 * This file adds support to rss feeds generation
20 *
21 * @package mod_forum
22 * @category rss
23 * @copyright 2001 Eloy Lafuente (stronk7) http://contiento.com
24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 */
fcce139a
AD
26
27/**
28 * Returns the path to the cached rss feed contents. Creates/updates the cache if necessary.
13d1c9ed
JF
29 * @param stdClass $context the context
30 * @param array $args the arguments received in the url
fcce139a 31 * @return string the full path to the cached RSS feed directory. Null if there is a problem.
8f685009 32 */
274f9840 33function forum_rss_get_feed($context, $args) {
fcce139a 34 global $CFG, $DB;
8f685009 35
fcce139a 36 $status = true;
8adcb49f 37
fcce139a
AD
38 //are RSS feeds enabled?
39 if (empty($CFG->forum_enablerssfeeds)) {
40 debugging('DISABLED (module configuration)');
41 return null;
42 }
8adcb49f 43
e65ce4c1 44 $forumid = clean_param($args[3], PARAM_INT);
4df53223 45 $cm = get_coursemodule_from_instance('forum', $forumid, 0, false, MUST_EXIST);
af89cdd4 46 $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
4df53223 47
af89cdd4
DP
48 //context id from db should match the submitted one
49 if ($context->id != $modcontext->id || !has_capability('mod/forum:viewdiscussion', $modcontext)) {
50 return null;
4df53223
AD
51 }
52
fcce139a 53 $forum = $DB->get_record('forum', array('id' => $forumid), '*', MUST_EXIST);
43b92251 54 if (!rss_enabled_for_mod('forum', $forum)) {
fcce139a 55 return null;
8adcb49f 56 }
57
fcce139a
AD
58 //the sql that will retreive the data for the feed and be hashed to get the cache filename
59 $sql = forum_rss_get_sql($forum, $cm);
83da3d28 60
fcce139a
AD
61 //hash the sql to get the cache file name
62 $filename = rss_get_file_name($forum, $sql);
43b92251 63 $cachedfilepath = rss_get_file_full_name('mod_forum', $filename);
fcce139a
AD
64
65 //Is the cache out of date?
66 $cachedfilelastmodified = 0;
67 if (file_exists($cachedfilepath)) {
68 $cachedfilelastmodified = filemtime($cachedfilepath);
69 }
da8ae44e
AD
70 //if the cache is more than 60 seconds old and there's new stuff
71 $dontrecheckcutoff = time()-60;
72 if ( $dontrecheckcutoff > $cachedfilelastmodified && forum_rss_newstuff($forum, $cm, $cachedfilelastmodified)) {
fcce139a 73 //need to regenerate the cached version
af89cdd4 74 $result = forum_rss_feed_contents($forum, $sql, $modcontext);
fcce139a 75 if (!empty($result)) {
43b92251 76 $status = rss_save_file('mod_forum',$filename,$result);
83da3d28 77 }
78 }
79
fcce139a
AD
80 //return the path to the cached version
81 return $cachedfilepath;
82}
83da3d28 83
fcce139a
AD
84/**
85 * Given a forum object, deletes all cached RSS files associated with it.
86 *
13d1c9ed 87 * @param stdClass $forum
fcce139a
AD
88 */
89function forum_rss_delete_file($forum) {
43b92251 90 rss_delete_file('mod_forum', $forum);
fcce139a
AD
91}
92
93///////////////////////////////////////////////////////
94//Utility functions
95
96/**
97 * If there is new stuff in the forum since $time this returns true
98 * Otherwise it returns false.
99 *
13d1c9ed
JF
100 * @param stdClass $forum the forum object
101 * @param stdClass $cm Course Module object
102 * @param int $time check for items since this epoch timestamp
103 * @return bool True for new items
fcce139a
AD
104 */
105function forum_rss_newstuff($forum, $cm, $time) {
106 global $DB;
107
108 $sql = forum_rss_get_sql($forum, $cm, $time);
109
110 $recs = $DB->get_records_sql($sql, null, 0, 1);//limit of 1. If we get even 1 back we have new stuff
111 return ($recs && !empty($recs));
112}
113
13d1c9ed
JF
114/**
115 * Determines which type of SQL query is required, one for posts or one for discussions, and returns the appropriate query
116 *
117 * @param stdClass $forum the forum object
118 * @param stdClass $cm Course Module object
119 * @param int $time check for items since this epoch timestamp
120 * @return string the SQL query to be used to get the Discussion/Post details from the forum table of the database
121 */
fcce139a
AD
122function forum_rss_get_sql($forum, $cm, $time=0) {
123 $sql = null;
124
125 if (!empty($forum->rsstype)) {
126 if ($forum->rsstype == 1) { //Discussion RSS
127 $sql = forum_rss_feed_discussions_sql($forum, $cm, $time);
128 } else { //Post RSS
129 $sql = forum_rss_feed_posts_sql($forum, $cm, $time);
6069e206 130 }
6069e206 131 }
132
fcce139a
AD
133 return $sql;
134}
8f0cd6ef 135
13d1c9ed
JF
136/**
137 * Generates the SQL query used to get the Discussion details from the forum table of the database
138 *
139 * @param stdClass $forum the forum object
140 * @param stdClass $cm Course Module object
141 * @param int $newsince check for items since this epoch timestamp
142 * @return string the SQL query to be used to get the Discussion details from the forum table of the database
143 */
fcce139a
AD
144function forum_rss_feed_discussions_sql($forum, $cm, $newsince=0) {
145 global $CFG, $DB, $USER;
146
147 $timelimit = '';
148
149 $modcontext = null;
150
151 $now = round(time(), -2);
152 $params = array($cm->instance);
153
154 $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
155
156 if (!empty($CFG->forum_enabletimedposts)) { /// Users must fulfill timed posts
157 if (!has_capability('mod/forum:viewhiddentimedposts', $modcontext)) {
158 $timelimit = " AND ((d.timestart <= :now1 AND (d.timeend = 0 OR d.timeend > :now2))";
159 $params['now1'] = $now;
160 $params['now2'] = $now;
161 if (isloggedin()) {
162 $timelimit .= " OR d.userid = :userid";
163 $params['userid'] = $USER->id;
8adcb49f 164 }
fcce139a 165 $timelimit .= ")";
8adcb49f 166 }
8adcb49f 167 }
168
fcce139a
AD
169 //do we only want new posts?
170 if ($newsince) {
171 $newsince = " AND p.modified > '$newsince'";
172 } else {
173 $newsince = '';
174 }
8adcb49f 175
fcce139a
AD
176 //get group enforcing SQL
177 $groupmode = groups_get_activity_groupmode($cm);
178 $currentgroup = groups_get_activity_group($cm);
179 $groupselect = forum_rss_get_group_sql($cm, $groupmode, $currentgroup, $modcontext);
8adcb49f 180
fcce139a
AD
181 if ($groupmode && $currentgroup) {
182 $params['groupid'] = $currentgroup;
183 }
8adcb49f 184
fcce139a 185 $forumsort = "d.timemodified DESC";
af89cdd4 186 $postdata = "p.id AS postid, p.subject, p.created as postcreated, p.modified, p.discussion, p.userid, p.message as postmessage, p.messageformat AS postformat, p.messagetrust AS posttrust";
fcce139a
AD
187
188 $sql = "SELECT $postdata, d.id as discussionid, d.name as discussionname, d.timemodified, d.usermodified, d.groupid, d.timestart, d.timeend,
189 u.firstname as userfirstname, u.lastname as userlastname, u.email, u.picture, u.imagealt
190 FROM {forum_discussions} d
191 JOIN {forum_posts} p ON p.discussion = d.id
192 JOIN {user} u ON p.userid = u.id
193 WHERE d.forum = {$forum->id} AND p.parent = 0
194 $timelimit $groupselect $newsince
195 ORDER BY $forumsort";
196 return $sql;
197}
198
13d1c9ed
JF
199/**
200 * Generates the SQL query used to get the Post details from the forum table of the database
201 *
202 * @param stdClass $forum the forum object
203 * @param stdClass $cm Course Module object
204 * @param int $newsince check for items since this epoch timestamp
205 * @return string the SQL query to be used to get the Post details from the forum table of the database
206 */
fcce139a
AD
207function forum_rss_feed_posts_sql($forum, $cm, $newsince=0) {
208 $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
46d39cf3 209
fcce139a
AD
210 //get group enforcement SQL
211 $groupmode = groups_get_activity_groupmode($cm);
212 $currentgroup = groups_get_activity_group($cm);
213
214 $groupselect = forum_rss_get_group_sql($cm, $groupmode, $currentgroup, $modcontext);
215
216 if ($groupmode && $currentgroup) {
217 $params['groupid'] = $currentgroup;
218 }
6069e206 219
fcce139a
AD
220 //do we only want new posts?
221 if ($newsince) {
222 $newsince = " AND p.modified > '$newsince'";
223 } else {
224 $newsince = '';
225 }
ec41cb3c 226
fcce139a
AD
227 $sql = "SELECT p.id AS postid,
228 d.id AS discussionid,
229 d.name AS discussionname,
230 u.id AS userid,
231 u.firstname AS userfirstname,
232 u.lastname AS userlastname,
233 p.subject AS postsubject,
234 p.message AS postmessage,
235 p.created AS postcreated,
236 p.messageformat AS postformat,
237 p.messagetrust AS posttrust
238 FROM {forum_discussions} d,
239 {forum_posts} p,
240 {user} u
241 WHERE d.forum = {$forum->id} AND
242 p.discussion = d.id AND
243 u.id = p.userid $newsince
244 $groupselect
245 ORDER BY p.created desc";
246
247 return $sql;
248}
249
13d1c9ed
JF
250/**
251 * Retrieve the correct SQL snippet for group-only forums
252 *
253 * @param stdClass $cm Course Module object
254 * @param int $groupmode the mode in which the forum's groups are operating
255 * @param bool $currentgroup true if the user is from the a group enabled on the forum
256 * @param stdClass $modcontext The context instance of the forum module
257 * @return string SQL Query for group details of the forum
258 */
fcce139a
AD
259function forum_rss_get_group_sql($cm, $groupmode, $currentgroup, $modcontext=null) {
260 $groupselect = '';
261
262 if ($groupmode) {
263 if ($groupmode == VISIBLEGROUPS or has_capability('moodle/site:accessallgroups', $modcontext)) {
264 if ($currentgroup) {
265 $groupselect = "AND (d.groupid = :groupid OR d.groupid = -1)";
266 $params['groupid'] = $currentgroup;
267 }
268 } else {
269 //seprate groups without access all
270 if ($currentgroup) {
271 $groupselect = "AND (d.groupid = :groupid OR d.groupid = -1)";
272 $params['groupid'] = $currentgroup;
273 } else {
274 $groupselect = "AND d.groupid = -1";
8adcb49f 275 }
276 }
8adcb49f 277 }
8f0cd6ef 278
fcce139a
AD
279 return $groupselect;
280}
8adcb49f 281
fcce139a
AD
282/**
283 * This function return the XML rss contents about the forum
284 * It returns false if something is wrong
285 *
13d1c9ed
JF
286 * @param stdClass $forum the forum object
287 * @param string $sql The SQL used to retrieve the contents from the database
af89cdd4 288 * @param object $context the context this forum relates to
13d1c9ed
JF
289 * @return bool|string false if the contents is empty, otherwise the contents of the feed is returned
290 *
291 * @Todo MDL-31129 implement post attachment handling
fcce139a 292 */
af89cdd4 293function forum_rss_feed_contents($forum, $sql, $context) {
fcce139a 294 global $CFG, $DB;
6069e206 295
fcce139a
AD
296 $status = true;
297
298 $params = array();
299 //$params['forumid'] = $forum->id;
300 $recs = $DB->get_recordset_sql($sql, $params, 0, $forum->rssarticles);
301
302 //set a flag. Are we displaying discussions or posts?
303 $isdiscussion = true;
304 if (!empty($forum->rsstype) && $forum->rsstype!=1) {
cc771939 305 $isdiscussion = false;
fcce139a 306 }
318f2100 307
39790bd8 308 $formatoptions = new stdClass();
fcce139a
AD
309 $items = array();
310 foreach ($recs as $rec) {
39790bd8
PS
311 $item = new stdClass();
312 $user = new stdClass();
cc771939
AD
313 if ($isdiscussion && !empty($rec->discussionname)) {
314 $item->title = format_string($rec->discussionname);
315 } else if (!empty($rec->postsubject)) {
7c810d07
AD
316 $item->title = format_string($rec->postsubject);
317 } else {
cc771939 318 //we should have an item title by now but if we dont somehow then substitute something somewhat meaningful
7c810d07
AD
319 $item->title = format_string($forum->name.' '.userdate($rec->postcreated,get_string('strftimedatetimeshort', 'langconfig')));
320 }
fcce139a
AD
321 $user->firstname = $rec->userfirstname;
322 $user->lastname = $rec->userlastname;
323 $item->author = fullname($user);
324 $item->pubdate = $rec->postcreated;
325 if ($isdiscussion) {
326 $item->link = $CFG->wwwroot."/mod/forum/discuss.php?d=".$rec->discussionid;
327 } else {
8f0cd6ef 328 $item->link = $CFG->wwwroot."/mod/forum/discuss.php?d=".$rec->discussionid."&parent=".$rec->postid;
fcce139a 329 }
410a24c0 330
fcce139a 331 $formatoptions->trusted = $rec->posttrust;
af89cdd4
DP
332 $message = file_rewrite_pluginfile_urls($rec->postmessage, 'pluginfile.php', $context->id,
333 'mod_forum', 'post', $rec->postid);
334 $item->description = format_text($message, $rec->postformat, $formatoptions, $forum->course);
410a24c0 335
13d1c9ed 336 //TODO: MDL-31129 implement post attachment handling
fcce139a 337 /*if (!$isdiscussion) {
318f2100 338 $post_file_area_name = str_replace('//', '/', "$forum->course/$CFG->moddata/forum/$forum->id/$rec->postid");
410a24c0 339 $post_files = get_directory_list("$CFG->dataroot/$post_file_area_name");
4e445355 340
341 if (!empty($post_files)) {
410a24c0 342 $item->attachments = array();
410a24c0 343 }
fcce139a 344 }*/
46d39cf3 345
fcce139a
AD
346 $items[] = $item;
347 }
348 $recs->close();
410a24c0 349
fcce139a
AD
350
351 if (!empty($items)) {
352 //First the RSS header
353 $header = rss_standard_header(strip_tags(format_string($forum->name,true)),
354 $CFG->wwwroot."/mod/forum/view.php?f=".$forum->id,
355 format_string($forum->intro,true)); // TODO: fix format
356 //Now all the rss items
357 if (!empty($header)) {
358 $articles = rss_add_items($items);
359 }
360 //Now the RSS footer
361 if (!empty($header) && !empty($articles)) {
362 $footer = rss_standard_footer();
8adcb49f 363 }
fcce139a
AD
364 //Now, if everything is ok, concatenate it
365 if (!empty($header) && !empty($articles) && !empty($footer)) {
366 $status = $header.$articles.$footer;
367 } else {
368 $status = false;
369 }
370 } else {
371 $status = false;
372 }
373
374 return $status;
375}