rss MDL-23391 rerefactored rss feed generation
[moodle.git] / mod / forum / rsslib.php
1 <?php
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/>.
18 /**
19 * This file adds support to rss feeds generation
20 *
21 * @package mod-forum
22 * @copyright 2001 Eloy Lafuente (stronk7) http://contiento.com
23 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 */
26 /**
27  * Returns the path to the cached rss feed contents. Creates/updates the cache if necessary.
28  * @global object $CFG
29  * @global object $DB
30  * @param object $context the context
31  * @param int $forumid the ID of the forum
32  * @param array $args the arguments received in the url
33  * @return string the full path to the cached RSS feed directory. Null if there is a problem.
34  */
35 function forum_rss_get_feed($context, $args) {
36     global $CFG, $DB;
38     $status = true;
40     //are RSS feeds enabled?
41     if (empty($CFG->forum_enablerssfeeds)) {
42         debugging('DISABLED (module configuration)');
43         return null;
44     }
46     $forumid = $args[3];
48     $uservalidated = false;
50     $cm = get_coursemodule_from_instance('forum', $forumid, 0, false, MUST_EXIST);
51     if ($cm) {
52         $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
54         //context id from db should match the submitted one
55         if ($context->id==$modcontext->id && has_capability('mod/forum:viewdiscussion', $modcontext)) {
56             $uservalidated = true;
57         }
58     }
60     if (!$uservalidated) {
61         return null;
62     }
64     $forum = $DB->get_record('forum', array('id' => $forumid), '*', MUST_EXIST);
66     if (!rss_enabled('forum', $forum)) {
67         return null;
68     }
70     //the sql that will retreive the data for the feed and be hashed to get the cache filename
71     $sql = forum_rss_get_sql($forum, $cm);
73     //hash the sql to get the cache file name
74     $filename = rss_get_file_name($forum, $sql);
75     $cachedfilepath = rss_get_file_full_name('forum', $filename);
77     //Is the cache out of date?
78     $cachedfilelastmodified = 0;
79     if (file_exists($cachedfilepath)) {
80         $cachedfilelastmodified = filemtime($cachedfilepath);
81     }
82     if (forum_rss_newstuff($forum, $cm, $cachedfilelastmodified)) {
83         //need to regenerate the cached version
84         $result = forum_rss_feed_contents($forum, $sql);
85         if (!empty($result)) {
86             $status = rss_save_file('forum',$filename,$result);
87         }
88     }
90     //return the path to the cached version
91     return $cachedfilepath;
92 }
94 /**
95  * Given a forum object, deletes all cached RSS files associated with it.
96  *
97  * @param object $forum
98  * @return void
99  */
100 function forum_rss_delete_file($forum) {
101     rss_delete_file('forum', $forum);
104 ///////////////////////////////////////////////////////
105 //Utility functions
107 /**
108  * If there is new stuff in the forum since $time this returns true
109  * Otherwise it returns false.
110  *
111  * @param object $forum the forum object
112  * @param object $cm
113  * @param int $time timestamp
114  * @return bool
115  */
116 function forum_rss_newstuff($forum, $cm, $time) {
117     global $DB;
119     $sql = forum_rss_get_sql($forum, $cm, $time);
121     $recs = $DB->get_records_sql($sql, null, 0, 1);//limit of 1. If we get even 1 back we have new stuff
122     return ($recs && !empty($recs));
125 function forum_rss_get_sql($forum, $cm, $time=0) {
126     $sql = null;
128     if (!empty($forum->rsstype)) {
129         if ($forum->rsstype == 1) {    //Discussion RSS
130             $sql = forum_rss_feed_discussions_sql($forum, $cm, $time);
131         } else {                //Post RSS
132             $sql = forum_rss_feed_posts_sql($forum, $cm, $time);
133         }
134     }
136     return $sql;
139 function forum_rss_feed_discussions_sql($forum, $cm, $newsince=0) {
140     global $CFG, $DB, $USER;
142     $timelimit = '';
144     $modcontext = null;
146     $now = round(time(), -2);
147     $params = array($cm->instance);
149     $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
151     if (!empty($CFG->forum_enabletimedposts)) { /// Users must fulfill timed posts
152         if (!has_capability('mod/forum:viewhiddentimedposts', $modcontext)) {
153             $timelimit = " AND ((d.timestart <= :now1 AND (d.timeend = 0 OR d.timeend > :now2))";
154             $params['now1'] = $now;
155             $params['now2'] = $now;
156             if (isloggedin()) {
157                 $timelimit .= " OR d.userid = :userid";
158                 $params['userid'] = $USER->id;
159             }
160             $timelimit .= ")";
161         }
162     }
164     //do we only want new posts?
165     if ($newsince) {
166         $newsince = " AND p.modified > '$newsince'";
167     } else {
168         $newsince = '';
169     }
171     //get group enforcing SQL
172     $groupmode    = groups_get_activity_groupmode($cm);
173     $currentgroup = groups_get_activity_group($cm);
174     $groupselect = forum_rss_get_group_sql($cm, $groupmode, $currentgroup, $modcontext);
176     if ($groupmode && $currentgroup) {
177         $params['groupid'] = $currentgroup;
178     }
180     $forumsort = "d.timemodified DESC";
181     $postdata = "p.id, p.subject, p.created as postcreated, p.modified, p.discussion, p.userid, p.message as postmessage, p.messageformat AS postformat, p.messagetrust AS posttrust";
183     $sql = "SELECT $postdata, d.id as discussionid, d.name as discussionname, d.timemodified, d.usermodified, d.groupid, d.timestart, d.timeend,
184                    u.firstname as userfirstname, u.lastname as userlastname, u.email, u.picture, u.imagealt
185               FROM {forum_discussions} d
186                    JOIN {forum_posts} p ON p.discussion = d.id
187                    JOIN {user} u ON p.userid = u.id
188              WHERE d.forum = {$forum->id} AND p.parent = 0
189                    $timelimit $groupselect $newsince
190           ORDER BY $forumsort";
191     return $sql;
194 function forum_rss_feed_posts_sql($forum, $cm, $newsince=0) {
195     $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
196     
197     //get group enforcement SQL
198     $groupmode    = groups_get_activity_groupmode($cm);
199     $currentgroup = groups_get_activity_group($cm);
201     $groupselect = forum_rss_get_group_sql($cm, $groupmode, $currentgroup, $modcontext);
203     if ($groupmode && $currentgroup) {
204         $params['groupid'] = $currentgroup;
205     }
207     //do we only want new posts?
208     if ($newsince) {
209         $newsince = " AND p.modified > '$newsince'";
210     } else {
211         $newsince = '';
212     }
214     $sql = "SELECT p.id AS postid,
215                  d.id AS discussionid,
216                  d.name AS discussionname,
217                  u.id AS userid,
218                  u.firstname AS userfirstname,
219                  u.lastname AS userlastname,
220                  p.subject AS postsubject,
221                  p.message AS postmessage,
222                  p.created AS postcreated,
223                  p.messageformat AS postformat,
224                  p.messagetrust AS posttrust
225             FROM {forum_discussions} d,
226                {forum_posts} p,
227                {user} u
228             WHERE d.forum = {$forum->id} AND
229                 p.discussion = d.id AND
230                 u.id = p.userid $newsince
231                 $groupselect
232             ORDER BY p.created desc";
234     return $sql;
237 function forum_rss_get_group_sql($cm, $groupmode, $currentgroup, $modcontext=null) {
238     $groupselect = '';
240     if ($groupmode) {
241         if ($groupmode == VISIBLEGROUPS or has_capability('moodle/site:accessallgroups', $modcontext)) {
242             if ($currentgroup) {
243                 $groupselect = "AND (d.groupid = :groupid OR d.groupid = -1)";
244                 $params['groupid'] = $currentgroup;
245             }
246         } else {
247             //seprate groups without access all
248             if ($currentgroup) {
249                 $groupselect = "AND (d.groupid = :groupid OR d.groupid = -1)";
250                 $params['groupid'] = $currentgroup;
251             } else {
252                 $groupselect = "AND d.groupid = -1";
253             }
254         }
255     }
257     return $groupselect;
261     
263 /**
264  * This function return the XML rss contents about the forum
265  * It returns false if something is wrong
266  *
267  * @param object $forum
268  * @param bool
269  */
270 function forum_rss_feed_contents($forum, $sql) {
271     global $CFG, $DB;
273     $status = true;
275     $params = array();
276     //$params['forumid'] = $forum->id;
277     $recs = $DB->get_recordset_sql($sql, $params, 0, $forum->rssarticles);
279     //set a flag. Are we displaying discussions or posts?
280     $isdiscussion = true;
281     if (!empty($forum->rsstype) && $forum->rsstype!=1) {
282             $isdiscussion = false;
283     }
285     $formatoptions = new object;
286     $items = array();
287     foreach ($recs as $rec) {
288             unset($item);
289             unset($user);
290             $item->title = format_string($rec->discussionname);
291             $user->firstname = $rec->userfirstname;
292             $user->lastname = $rec->userlastname;
293             $item->author = fullname($user);
294             $item->pubdate = $rec->postcreated;
295             if ($isdiscussion) {
296                 $item->link = $CFG->wwwroot."/mod/forum/discuss.php?d=".$rec->discussionid;
297             } else {
298                 $item->link = $CFG->wwwroot."/mod/forum/discuss.php?d=".$rec->discussionid."&parent=".$rec->postid;
299             }
301             $formatoptions->trusted = $rec->posttrust;
302             $item->description = format_text($rec->postmessage,$rec->postformat,$formatoptions,$forum->course);
304             //TODO: implement post attachment handling
305             /*if (!$isdiscussion) {
306                 $post_file_area_name = str_replace('//', '/', "$forum->course/$CFG->moddata/forum/$forum->id/$rec->postid");
307                 $post_files = get_directory_list("$CFG->dataroot/$post_file_area_name");
309                 if (!empty($post_files)) {
310                     $item->attachments = array();
311                 }
312             }*/
313             
314             $items[] = $item;
315         }
316     $recs->close();
319     if (!empty($items)) {
320         //First the RSS header
321         $header = rss_standard_header(strip_tags(format_string($forum->name,true)),
322                                       $CFG->wwwroot."/mod/forum/view.php?f=".$forum->id,
323                                       format_string($forum->intro,true)); // TODO: fix format
324         //Now all the rss items
325         if (!empty($header)) {
326             $articles = rss_add_items($items);
327         }
328         //Now the RSS footer
329         if (!empty($header) && !empty($articles)) {
330             $footer = rss_standard_footer();
331         }
332         //Now, if everything is ok, concatenate it
333         if (!empty($header) && !empty($articles) && !empty($footer)) {
334             $status = $header.$articles.$footer;
335         } else {
336             $status = false;
337         }
338     } else {
339         $status = false;
340     }
342     return $status;