root/trunk/gregarius/admin/channels.php

Revision 1774, 42.9 kB (checked in by cfriesen, 10 months ago)

Individual update (hope nothing is missing)

  • Property svn:eol-style set to native
Line 
1<?php
2###############################################################################
3# Gregarius - A PHP based RSS aggregator.
4# Copyright (C) 2003 - 2006 Marco Bonetti
5#
6###############################################################################
7# This program is free software and open source software; you can redistribute
8# it and/or modify it under the terms of the GNU General Public License as
9# published by the Free Software Foundation; either version 2 of the License,
10# or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful, but WITHOUT
13# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14# FITNESS FOR A PARTICULAR PURPOSE.      See the GNU General Public License for
15# more details.
16#
17# You should have received a copy of the GNU General Public License along
18# with this program; if not, write to the Free Software Foundation, Inc.,
19# 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  or visit
20# http://www.gnu.org/licenses/gpl.html
21#
22###############################################################################
23# E-mail:          mbonetti at gmail dot com
24# Web page:      http://gregarius.net/
25#
26###############################################################################
27
28/*************** Channel management ************/
29
30/**
31 * renders the subscribe feed form, and the currently subscribed
32 * feeds table
33 */
34
35define ('CST_ADMIN_MULTIEDIT','multiedit');
36
37
38function channels() {
39    echo "<h2>". __('Feeds:') ."</h2>\n";
40    echo "<div id=\"admin_channels\">\n";
41    echo "<form method=\"post\" action=\"" .$_SERVER['PHP_SELF'] ."\">\n";
42    echo "<p><input type=\"hidden\" name=\"". CST_ADMIN_DOMAIN."\" value=\"".CST_ADMIN_DOMAIN_CHANNEL."\" />\n";
43    echo "<label for=\"new_channel\">". __('Add a feed:') ."</label>\n";
44    echo "<input type=\"text\" name=\"new_channel\" id=\"new_channel\" value=\"http://\" onmouseover=\"clearOnHover(this);\" onfocus=\"this.select()\" />\n";
45
46    echo "<label for=\"add_channel_to_folder\">". __('to folder:') . "</label>\n";
47    echo rss_toolkit_folders_combo('add_channel_to_folder');
48    echo "<label for=\"channel_tags\">" . __('Categories') . ":</label>\n";
49    echo "<input type=\"text\" name=\"channel_tags\" id=\"channel_tags\" />\n";
50    echo "<input type=\"hidden\" name=\"". CST_ADMIN_METAACTION ."\" value=\"ACT_ADMIN_ADD\" />\n";
51    echo "<input type=\"submit\" name=\"action\" value=\"". __('Add') ."\" /></p>\n";
52    echo "<p style=\"font-size:small\">".__('(Enter either the URL of an RSS feed or of a Website whose feed you wish to subscribe to)')."</p>";
53    echo "</form>\n\n";
54
55    // bookmarklet
56    $b_url = guessTransportProto() . $_SERVER["HTTP_HOST"] . getPath() . "admin/index.php";
57    $b_url .= "?domain=feeds&amp;add_channel_to_folder=0&amp;action=Add&amp;new_channel=";
58
59    $bookmarklet = "javascript:void(document.location = "
60                   ."('$b_url'.concat(escape(document.location).replace(/\s/,'%2520'))))";
61
62    echo "<p style=\"font-size:small\">" . __('Subscription bookmarklet [<a href="http://www.squarefree.com/bookmarklets/">?</a>]:') . " <a class=\"bookmarklet\" href=\"$bookmarklet\">".__('Subscribe in Gregarius!')."</a></p>\n";
63    // feed handler - similar to bookmarklet, but with %s
64    $feedhandler_url = "javascript:navigator.registerContentHandler(\'application/vnd.mozilla.maybe.feed\',\'$b_url%s\',\'Gregarius\');";
65    echo "<script type=\"text/javascript\">\n"
66    ."//<!--\n"
67    ."if (navigator && typeof(navigator.registerContentHandler) == 'function'){\n"
68    ."\tdocument.write('<p style=\"font-size:small\">"
69    . __('Register as Feed Handler [<a href="http://www.bengoodger.com/software/mb/feeds/feed-handling.html">?</a>]:')
70    . " <a class=\"bookmarklet\" href=\"$feedhandler_url\">"
71    .__('Register Gregarius!')."</a></p>');\n"
72    ."}\n"
73    ."// -->\n"
74    ."</script>\n";
75
76    // feeds
77?>
78<script type="text/javascript">
79// <!--
80        function cbtoggle() {
81        var c=document.getElementById('mastercb').checked;
82        var cs=document.getElementById('channeltable').getElementsByTagName('input');
83        for(i=0;i<cs.length;i++) {
84                if (cs[i].type == 'checkbox') cs[i].checked = c;
85        }
86    }
87    function clearOnHover(o) {
88        if (o.value && o.value=='http://') o.value='';
89    };
90        function admin_menu_toggle(o,id){
91                var i,lis=document.getElementById('channels_admin_sidemenu').getElementsByTagName('li');
92                for(i=0;i<lis.length;i++) {
93                        lis[i].className='';
94                }
95                o.parentNode.className='active';               
96                var ps = document.getElementById('channels_admin_menu').getElementsByTagName('p');
97                for(i=0;i<ps.length;i++) {
98                        if (ps[i].id == 'channels_admin_'+id) {
99                                ps[i].style.display='block';
100                        } else {
101                                ps[i].style.display='none';
102                        }
103                }
104                return false;
105        }
106        /** quick hack to toggle through deprecated / private feeds' checkbox */
107        document.checkedState='none';
108        function cb_state_toggle() {
109                switch (document.checkedState) {
110                        case 'none': document.checkedState = 'deprecated'; break;
111                        case 'deprecated': document.checkedState = 'private'; break;
112                        case 'private': document.checkedState = 'none'; break;
113                }
114                var id,trs = document.getElementById('channeltable').getElementsByTagName('tr');
115                for(var i in trs) {
116                        if (id = trs[i].id) {
117                                document.getElementById('scb_'+id.replace(/[^0-9]/g,'')).checked =
118                                        (trs[i].className.search(document.checkedState) >= 0);
119                        }
120                }
121                return false;
122        }
123
124// -->
125</script>
126<?php
127    echo "<form method=\"post\" action=\"" .$_SERVER['PHP_SELF'] ."\">\n";
128    echo "<table id=\"channeltable\">\n"
129    ."<tr>\n"
130    ."\t<th><input type=\"checkbox\" id=\"mastercb\" onclick=\"cbtoggle();\" /></th>\n"
131    ."\t<th>". __('Title') ."</th>\n"
132    ."\t<th class=\"cntr\">". __('Folder') ."</th>\n"
133    ."\t<th>". __('Description') ."</th>\n"
134    ."\t<th>". __('Categories')."</th>\n"
135    ."\t<th><a href=\"#\" onclick=\"return cb_state_toggle();\">". __('Flags')."</a></th>\n";
136
137    if (getConfig('rss.config.absoluteordering')) {
138        echo "\t<th>".__('Move')."</th>\n";
139    }
140
141    echo "\t<th class=\"cntr\">". __('Action') ."</th>\n"
142    ."</tr>\n";
143
144    $sql = "select "
145           ." c.id, c.title, c.url, c.siteurl, d.name, c.descr, c.parent, c.icon, c.mode, c.daterefreshed "
146           ." from " .getTable("channels") ." c "
147           ." inner join " . getTable("folders") ." d "
148           ."   on d.id = c.parent ";
149
150    if (getConfig('rss.config.absoluteordering')) {
151        $sql .=" order by d.position asc, c.position asc";
152    } else {
153        $sql .=" order by d.name asc, c.title asc";
154    }
155
156    $res = rss_query($sql);
157    $cntr = 0;
158    while (list($id, $title, $url, $siteurl, $parent, $descr, $pid, $icon, $mode, $daterefreshed) = rss_fetch_row($res)) {
159
160        if (getConfig('rss.output.usemodrewrite')) {
161            $outUrl = getPath() . preg_replace("/[^A-Za-z0-9\.]/","_","$title") ."/";
162        } else {
163            $outUrl = getPath() . "feed.php?channel=$id";
164        }
165
166        $parentLabel = $parent == ''? __('Root'):$parent;
167
168        $class_ = (($cntr++ % 2 == 0)?"even":"odd");
169
170        // get feed's tags
171        $tags = "";
172        $sql2 = "select t.id, t.tag from " . getTable('tag') . " t "
173                . "inner join " . getTable('metatag') . " m "
174                . "  on m.tid = t.id "
175                . "where m.ttype = 'channel' and m.fid = $id";
176        $res2 = rss_query($sql2);
177
178        while(list ($id_, $name_) = rss_fetch_row($res2)) {
179            if (getConfig('rss.output.usemodrewrite')) {
180                $tags .= "<a href=\"".getPath()."$name_/\">$name_</a> ";
181            } else {
182                $tags .= "<a href=\"".getPath()."feed.php?vfolder=$id_\">$name_</a> ";
183            }
184        }
185
186        if(NULL == $daterefreshed) {
187            $dead = true;
188        } else {
189            $dead = (time() - strtotime($daterefreshed) > getConfig('rss.config.deadthreshhold')*60*60 ? true : false);
190        }
191
192        $fmode = array();
193        if ($mode & RSS_MODE_PRIVATE_STATE) {
194            $fmode[] = "P";
195                        $class_ .= ' private';
196        }
197        if ($mode & RSS_MODE_DELETED_STATE) {
198            $fmode[] = "D";
199            $dead = false;
200                        $class_ .= ' deprecated';
201        }
202
203        $slabel = count($fmode)?implode(", ",$fmode):"&nbsp;";
204        if ($icon && substr($icon,0,5) == 'blob:') {
205            $icon = getPath( "extlib/favicon.php?url=" .rss_real_escape_string(substr($icon,5)));
206        }
207        $style_ = "display:block;";
208        if($icon && getConfig('rss.output.showfavicons')) {
209            $style_ .= "background: url($icon) no-repeat; padding-left: 22px;";
210        }
211        if ($dead) {
212            $style_ .= 'text-decoration:line-through';
213        }
214           
215        echo "<tr class=\"$class_\" id=\"fa$id\">\n"
216        ."\t<td><input type=\"checkbox\" name=\"fcb$id\" value=\"$id\" id=\"scb_$id\" /></td>\n"
217        ."\t<td>"
218        ."<label for=\"scb_$id\" style=\"$style_\">".$title."</label>"
219        ."</td>\n"
220        ."\t<td class=\"cntr\">".preg_replace('/ /','&nbsp;',$parentLabel)."</td>\n"
221        ."\t<td>$descr</td>\n"
222        ."\t<td>$tags</td>\n"
223        ."\t<td class=\"cntr\">$slabel</td>\n";
224
225        if (getConfig('rss.config.absoluteordering')) {
226            echo "\t<td class=\"cntr\"><a href=\"".$_SERVER['PHP_SELF']. "?".CST_ADMIN_DOMAIN."=". CST_ADMIN_DOMAIN_CHANNEL
227            ."&amp;action=". CST_ADMIN_MOVE_UP_ACTION. "&amp;cid=$id\">". __('&uarr;')
228            ."</a>&nbsp;-&nbsp;<a href=\"".$_SERVER['PHP_SELF']. "?".CST_ADMIN_DOMAIN."=". CST_ADMIN_DOMAIN_CHANNEL
229            ."&amp;action=". CST_ADMIN_MOVE_DOWN_ACTION ."&amp;cid=$id\">".__('&darr;') ."</a></td>\n";
230        }
231        echo "\t<td class=\"cntr\"><a href=\"".$_SERVER['PHP_SELF']. "?".CST_ADMIN_DOMAIN."=". CST_ADMIN_DOMAIN_CHANNEL
232        ."&amp;".CST_ADMIN_VIEW."=". CST_ADMIN_DOMAIN_CHANNEL
233        ."&amp;action=". CST_ADMIN_EDIT_ACTION. "&amp;cid=$id\">" . __('edit')
234        ."</a>";
235        if(!getConfig('rss.config.restrictrefresh')) {
236                echo "|<a href=\"".getPath()."update.php?cid=$id\">" . __('update') . "</a>\n";
237                                }
238        echo "|<a href=\"".$_SERVER['PHP_SELF']. "?".CST_ADMIN_DOMAIN."=". CST_ADMIN_DOMAIN_CHANNEL
239        ."&amp;".CST_ADMIN_VIEW."=". CST_ADMIN_DOMAIN_CHANNEL
240        ."&amp;action=". CST_ADMIN_DELETE_ACTION ."&amp;cid=$id\">" . __('delete') ."</a></td>\n"
241        ."</tr>\n";
242    }
243
244    echo "</table>\n";
245
246        echo ""
247        ."<ul class=\"sidemenu\" id=\"channels_admin_sidemenu\">\n"
248        ."<li class=\"active\"><a href=\"#\" onclick=\"return admin_menu_toggle(this,'folders');\">". __('Folders') ."</a></li>\n"
249        ."<li><a href=\"#\" onclick=\"return admin_menu_toggle(this,'categories');\">". __('Categories') ."</a></li>\n"
250        ."<li><a href=\"#\" onclick=\"return admin_menu_toggle(this,'state');\">". __('State') ."</a></li>\n"
251        ."<li><a href=\"#\" onclick=\"return admin_menu_toggle(this,'delete');\">". __('Delete') ."</a></li>\n"
252        ."</ul>";
253       
254        echo "<div id=\"channels_admin_menu\" class=\"frame\">";
255       
256       
257        echo ""
258        ."<p id=\"channels_admin_folders\" style=\"display:block\">"
259    ."<label for=\"me_folder\">".__('In folder:')."</label>\n"
260    .rss_toolkit_folders_combo('me_folder',null)
261    ."<input type=\"submit\" id=\"me_move_to_folder\" name=\"me_move_to_folder\" value=\"".__('Move')."\" />\n"
262        ."</p>";
263       
264       
265        echo ""
266        ."<p id=\"channels_admin_categories\" style=\"display:none\">"
267    ."<label for=\"me_categories\">".__('Categories:')."</label>\n"
268        ."<input id=\"me_categories\" name=\"me_categories\" type=\"text\" />"
269    ."<input type=\"submit\" id=\"me_set_categories\" name=\"me_set_categories\" value=\"".__('Set')."\" />\n"
270        ."</p>";
271       
272       
273        echo ""
274        ."<p id=\"channels_admin_state\" style=\"display:none\">"
275    ."<label>".__('State:')."</label>\n"
276    ."<input type=\"checkbox\" name=\"me_deprecated\" id=\"me_deprecated\" value=\"".RSS_MODE_DELETED_STATE."\" />\n"
277    ."<label for=\"me_deprecated\">".__('Deprecated')."</label>\n"
278
279    ."<input type=\"checkbox\" name=\"me_private\" id=\"me_private\" value=\"".RSS_MODE_PRIVATE_STATE."\" />\n"
280    ."<label for=\"me_private\">".__('Private')."</label>\n"
281
282    ."<input type=\"submit\" id=\"me_state\" name=\"me_state\" value=\"".__('Set')."\" />\n"
283        ."</p>";
284
285        echo ""
286        ."<p id=\"channels_admin_delete\" style=\"display:none\">"
287
288        ."<input type=\"checkbox\" name=\"me_do_delete\" id=\"me_do_delete\" value=\"1\" />\n"
289    ."<label for=\"me_do_delete\">".__("I'm sure!")."</label>\n"
290
291    ."<input type=\"submit\" id=\"me_delete\" name=\"me_delete\" value=\"".__('Delete')."\" />\n"
292   
293
294    ."<input type=\"hidden\" name=\"".CST_ADMIN_DOMAIN."\" value=\"".CST_ADMIN_DOMAIN_CHANNEL."\" />\n"
295    ."<input type=\"hidden\" name=\"action\" value=\"" .CST_ADMIN_MULTIEDIT ."\" />\n"
296    ."</p>\n";
297 
298        echo"</div>";
299
300
301
302    echo "</form></div>\n\n\n";
303}
304
305/**
306 * Performs all the feed-related admin actions
307 */
308
309function channel_admin() {
310
311
312    // Fix for #16: Admin (et al.) should not rely on l10n labels for actions:
313    // Look for a meta-action first, which should be the (untranslated) *name* of
314    // the (translated) action constant.
315
316    // Fixme: should replace 'action's with a constant
317    if (array_key_exists(CST_ADMIN_METAACTION,$_REQUEST)) {
318        $__action__ = $_REQUEST[CST_ADMIN_METAACTION];
319    }
320    elseif (array_key_exists('action',$_REQUEST)) {
321        $__action__ = $_REQUEST['action'];
322    }
323    else {
324        $__action__ = "";
325    }
326
327
328    $ret__ = CST_ADMIN_DOMAIN_NONE;
329    switch ($__action__) {
330
331    case __('Add'):
332                case 'ACT_ADMIN_ADD':
333                    case 'Add':
334
335                            $label      = trim(sanitize($_REQUEST['new_channel'], RSS_SANITIZER_URL));
336        $fid            = trim(sanitize($_REQUEST['add_channel_to_folder'], RSS_SANITIZER_NUMERIC));
337        list($flabel) = rss_fetch_row(rss_query(
338                                          "select name from " . getTable('folders') . " where id=$fid"));
339
340        // handle "feed:" urls
341                if (substr($label, 0,5) == 'feed:') {
342
343            if (substr($label, 0, 11 ) == "feed://http") {
344                $label = substr($label,5);
345            } else { // handle feed://example.com/rss.xml urls
346                $label = "http:" . substr($label,5);
347            }
348        }
349
350        if ($label != 'http://' &&      substr($label, 0,4) == "http") {
351            $tags = @$_REQUEST['channel_tags'];
352            $ret = add_channel($label,$fid,null,null,$tags);
353            //var_dump($ret);
354            if (is_array($ret) && $ret[0] > -1) {
355                update($ret[0]);
356                rss_invalidate_cache();
357
358                // feedback
359                $newCid = $ret[0];
360                rss_error(sprintf(
361                              __('Adding %s to %s... '),
362                              htmlentities($label),"/$flabel")
363                          . __('OK')
364                          . "&nbsp;[<a href=\"".getPath()."admin/index.php?domain=".CST_ADMIN_DOMAIN_CHANNEL
365                          ."&amp;action=edit&amp;cid=$newCid\">"
366                          . __('edit')
367                          ."</a>]",
368                          RSS_ERROR_ERROR,true);
369                $ret__ = CST_ADMIN_DOMAIN_CHANNEL;
370            }
371            elseif  (is_array($ret) && $ret[0] > -2) {
372                // okay, something went wrong, maybe thats a html url after all?
373                // let's try and see if we can extract some feeds
374                $feeds = extractFeeds($label);
375                if (!is_array($feeds) || sizeof($feeds) == 0) {
376                    rss_error($ret[1], RSS_ERROR_ERROR,true);
377                    $ret__ = CST_ADMIN_DOMAIN_CHANNEL;
378                } else {
379                    //one single feed in the html doc, add that
380                    if (is_array($feeds) && sizeof($feeds) == 1 && array_key_exists('href',$feeds[0])) {
381                        $ret = add_channel($feeds[0]['href'],$fid);
382                        if (is_array($ret) && $ret[0] > -1) {
383                            update($ret[0]);
384                            rss_invalidate_cache();
385
386                            // feedback
387                            $newCid = $ret[0];
388                            rss_error(sprintf(
389                                          __('Adding %s to %s... '),
390                                          htmlentities($label),"/$flabel")
391                                      . __('OK')
392                                      . "&nbsp;[<a href=\"".getPath()."admin/index.php?domain="
393                                      .CST_ADMIN_DOMAIN_CHANNEL
394                                      ."&amp;action=edit&amp;cid=$newCid\">"
395                                      . __('edit')
396                                      ."</a>]",
397                                      RSS_ERROR_ERROR,true);
398
399
400                            $ret__ = CST_ADMIN_DOMAIN_CHANNEL;
401                        } else {
402                            // failure
403                            rss_error($ret[1], RSS_ERROR_ERROR,true);
404                            $ret__ = CST_ADMIN_DOMAIN_CHANNEL;
405                        }
406                    } else {
407                        // multiple feeds in the channel
408                        echo "<form method=\"post\" action=\"" .$_SERVER['PHP_SELF'] ."\">\n"
409                        ."<p>".sprintf(__('The following feeds were found in <a href="%s">%s</a>, which one would you like to subscribe?'),$label,$label)."</p>\n";
410                        $cnt = 0;
411                        while(list($id,$feedarr) = each($feeds)) {
412                            // we need an URL
413                            if (!array_key_exists('href',$feedarr)) {
414                                continue;
415                            } else {
416                                $href = $feedarr['href'];
417                            }
418
419                            if (array_key_exists('type',$feedarr)) {
420                                $typeLbl = " [<a href=\"$href\">" . $feedarr['type']
421                                           . "</a>]";
422                            }
423
424                            $cnt++;
425
426                            if (array_key_exists('title',$feedarr)) {
427                                $lbl = $feedarr['title'];
428                            }
429                            elseif (array_key_exists('type',$feedarr)) {
430                                $lbl = $feedarr['type'];
431                                $typeLbl = "";
432                            }
433                            elseif (array_key_exists('href',$feedarr)) {
434                                $lbl = $feedarr['href'];
435                            }
436                            else {
437                                $lbl = "Resource $cnt";
438                            }
439
440                            echo "<p>\n\t<input class=\"indent\" type=\"radio\" id=\"fd_$cnt\" name=\"new_channel\" "
441                            ." value=\"$href\" />\n"
442                            ."\t<label for=\"fd_$cnt\">$lbl $typeLbl</label>\n"
443                            ."</p>\n";
444                        }
445
446                        echo "<p><input type=\"hidden\" name=\"add_channel_to_folder\" value=\"$fid\" />\n"
447                        ."<input type=\"hidden\" name=\"".CST_ADMIN_DOMAIN."\" value=\"".CST_ADMIN_DOMAIN_CHANNEL."\" />\n"
448                        ."<input type=\"hidden\" name=\"".CST_ADMIN_METAACTION."\" value=\"ACT_ADMIN_ADD\" />\n"
449                        ."<input type=\"submit\" class=\"indent\" name=\"action\" value=\"". __('Add') ."\" />\n"
450                        ."</p>\n</form>\n\n";
451                    }
452                }
453            }
454            elseif (is_array($ret))  {
455                rss_error($ret[1], RSS_ERROR_ERROR,true);
456                $ret__ = CST_ADMIN_DOMAIN_CHANNEL;
457            }
458            else {
459                rss_error(sprintf(__("I'm sorry, I don't think I can handle this URL: '%s'"),$label), RSS_ERROR_ERROR,true);
460                $ret__ = CST_ADMIN_DOMAIN_CHANNEL;
461            }
462        } else {
463            rss_error(sprintf(__("I'm sorry, I don't think I can handle this URL: '%s'"),$label), RSS_ERROR_ERROR,true);
464            $ret__ = CST_ADMIN_DOMAIN_CHANNEL;
465        }
466        break;
467
468    case CST_ADMIN_EDIT_ACTION:
469        $id = sanitize($_REQUEST['cid'],RSS_SANITIZER_NUMERIC);
470        channel_edit_form($id);
471        break;
472
473
474    case CST_ADMIN_DELETE_ACTION:
475        $id = sanitize($_REQUEST['cid'],RSS_SANITIZER_NUMERIC);
476        if (array_key_exists(CST_ADMIN_CONFIRMED,$_POST) && $_POST[CST_ADMIN_CONFIRMED] == __('Yes')) {
477            $rs = rss_query("select distinct id from " .getTable("item") . " where cid=$id");
478            $ids = array();
479            while (list($did) = rss_fetch_row($rs)) {
480                $ids[] = $did;
481            }
482            if (count($ids)) {
483                $sqldel = "delete from " .getTable('metatag') . " where fid in ("
484                          . implode(",",$ids)   .")";
485                rss_query($sqldel);
486            }
487
488            $sql = "delete from " . getTable("item") ." where cid=$id";
489            rss_query($sql);
490