source: OWR/Controller.php @ f9418d

Revision f9418d, 92.1 KB checked in by pierre-alain <pierre-alain@…>, 9 years ago (diff)

quick statistics, to be enhanced later

  • Property mode set to 100644
Line 
1<?php
2/**
3 * Controller class
4 * Get the request, clean it and execute the given action
5 *
6 * PHP 5
7 *
8 * OWR - OpenWebReader
9 *
10 * Copyright (c) 2009, Pierre-Alain Mignot
11 *
12 * Home page: http://openwebreader.org
13 *
14 * E-Mail: contact@openwebreader.org
15 *
16 * All Rights Reserved
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26 * GNU General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31 *
32 * @author Pierre-Alain Mignot <contact@openwebreader.org>
33 * @copyright Copyright (c) 2009, Pierre-Alain Mignot
34 * @license http://www.gnu.org/copyleft/gpl.html
35 * @package OWR
36 */
37namespace OWR;
38use OWR\DB\Request as DBRequest,
39    OWR\Logic\Response as LogicResponse,
40    OWR\View\Utilities as Utilities;
41if(!defined('INC_CONFIG')) die('Please include config file');
42/**
43 * This object is the front door of the application
44 * @uses DAO deals with database
45 * @uses Config the config instance
46 * @uses Cron manages cron settings
47 * @uses Singleton implements the singleton pattern
48 * @uses DB the database link
49 * @uses View the page renderer
50 * @uses Session session managing
51 * @uses Request the request to execute
52 * @uses User the current user
53 * @uses Exception the exceptions handler
54 * @uses Error the errors handler
55 * @uses OWR\DB\Request a request sent to database
56 * @uses Logs the logs/errors storing object
57 * @uses OWR\View\Utilities translate errors
58 * @package OWR
59 */
60class Controller extends Singleton
61{
62    /**
63     * @var mixed the Config instance
64     * @access protected
65     */
66    protected $_cfg;
67
68    /**
69     * @var boolean are we called by the upload frame ?
70     * @access protected
71     */
72    protected $_isFrame = false;
73
74    /**
75     * @var mixed the DB instance
76     * @access protected
77     */
78    protected $_db;
79
80    /**
81     * @var mixed the View instance
82     * @access protected
83     */
84    protected $_view;
85
86    /**
87     * @var mixed the Session instance
88     * @access protected
89     */
90    protected $_sh;
91
92    /**
93     * @var array the list of timezones
94     * @access protected
95     */
96    protected $_tz;
97
98    /**
99     * @var mixed the current User instance
100     * @access protected
101     */
102    protected $_user;
103
104    /**
105     * @var mixed the \IntlDateFormatter instance
106     * @access protected
107     */
108    protected $_dateFormatter;
109
110    /**
111     * @var mixed the Cron instance
112     * @access protected
113     */
114    protected $_cron;
115
116    /**
117     * @var int the actual minimum ttl
118     * @access protected
119     */
120    protected $_minCronTtl;
121
122    /**
123     * @var mixed the current Request instance
124     * @access protected
125     */
126    protected $_request;
127
128    /**
129     * Constructor, sets : all needed instances, session handler, errors and exceptions handler,
130     * starts the session, and register the user session
131     *
132     * @access protected
133     */
134    protected function __construct()
135    {
136        $this->_cfg = Config::iGet();
137
138        // secure only ?
139        if($this->_cfg->get('httpsecure') && (!isset($_SERVER['HTTPS']) || 'on' !== $_SERVER['HTTPS']))
140        {
141            header('Location: https://'.$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI']);
142            exit;
143        }
144
145        set_error_handler(array(__NAMESPACE__.'\Error', 'error_handler')); // errors
146        set_exception_handler(array(__NAMESPACE__.'\Exception', 'exception_handler')); // exceptions not catched
147        error_reporting(DEBUG ? -1 :    E_CORE_ERROR | 
148                                        E_COMPILE_ERROR | 
149                                        E_ERROR | 
150                                        E_PARSE | 
151                                        E_USER_ERROR | 
152                                        E_USER_WARNING | 
153                                        E_USER_NOTICE | 
154                                        E_USER_DEPRECATED);
155
156        try
157        {
158            $this->_db = DB::iGet(); // init DB connexion
159        }
160        catch(Exception $e)
161        {
162            throw new Exception($e->getContent(), Exception::E_OWR_UNAVAILABLE);
163        }
164
165        $this->_sh = Session::iGet(); // init session
166       
167        try
168        {
169            $this->_sh->init(array('sessionLifeTime' => $this->_cfg->get('sessionLifeTime'),
170                'path' => $this->_cfg->get('path'),
171                'domain' => $this->_cfg->get('url'),
172                'httpsecure' => $this->_cfg->get('httpsecure')));
173        }
174        catch(Exception $e)
175        {
176            throw new Exception($e->getContent(), Exception::E_OWR_UNAVAILABLE);
177        }
178
179        $this->_user = $this->_sh->get('User');
180        if(!isset($this->_user) || !($this->_user instanceof User))
181        {
182            $this->_user = User::iGet();
183            $this->_user->reg(); // populate into the session
184        }
185    }
186   
187    /**
188     * Executes the given action
189     * This method only accepts a Request object
190     * It will try to log the user in, and execute the action
191     * Throws a fatal Exception if something goes really wrong
192     *
193     * If you want to execute an action without the controller displays anything
194     * set $isInternal to true, and all errors will be logged instead
195     *
196     * @author Pierre-Alain Mignot <contact@openwebreader.org>
197     * @param mixed Request the request to execute
198     * @access public
199     * @return $this
200     */
201    public function execute(Request $request)
202    {
203        $this->_request = $request;
204        $this->_request->begintime = microtime(true);
205
206        try 
207        {
208            if(!empty($this->_request->identifier) || 'verifyopenid' === $this->_request->do)
209            { // openid, add it to include_path
210                ini_set('include_path', HOME_PATH.'libs'.DIRECTORY_SEPARATOR.
211                        'openID'.DIRECTORY_SEPARATOR.PATH_SEPARATOR.ini_get('include_path'));
212            }
213
214            if(!$this->_user->isLogged())
215            {
216                if(!empty($this->_request->tlogin) && !empty($this->_request->key))
217                {
218                    switch($this->_request->do)
219                    { // atm only getting stream is allowed, but for the future ..
220                        case 'getrss':
221                        case 'getopml':
222                            break;
223                        default: 
224                            throw new Exception(sprintf(Utilities::iGet()->_('Invalid action "%s"'), $this->_request->do), Exception::E_OWR_BAD_REQUEST);
225                            break;
226                    }
227                   
228                    $this->do_login(true);
229                }
230                elseif($this->_request->do !== 'edituser' && $this->_request->do !== 'login' && $this->_request->do !== 'verifyopenid')
231                {
232                    $this->_user->regenerateToken();
233                    $this->redirect('login');
234                }
235            }
236            else
237            {
238                $token = $this->_user->getToken();
239                // check HTTP User-Agent and token
240                if(($this->_user->getAgent() !== md5($token.$_SERVER['HTTP_USER_AGENT'])) ||
241                    empty($this->_request->token) || $this->_request->token !== $token)
242                {
243                    if($this->_request->do !== 'logout')
244                    { // for external action, there's no tokens set
245                    // we prompt the user to log-in to confirm he is really who he pretends to be
246                        if($this->_request->do === 'opensearch' || $this->_request->do === 'add')
247                            $this->_request->back = basename(trim(Filter::iGet()->purify($_SERVER['REQUEST_URI'])));
248                        $this->_getPage('login', array('error' => Utilities::iGet()->_('You lost your token ! Confirm back your identity')));
249                        return $this;
250                    }
251                }
252                unset($token);
253            }
254   
255            $action = 'do_'.$this->_request->do;
256   
257            if(!method_exists($this, $action)) // surely change this to a __call function to allow plugin
258                throw new Exception(sprintf(Utilities::iGet()->_('Invalid action "%s"'), $this->_request->do), Exception::E_OWR_BAD_REQUEST);
259       
260            if($this->_user->isAdmin())
261            {
262                // we redirect if some clear caching is asked
263                // to not have '?clear(db|html)cache' in the url
264                if(!empty($this->_request->clearcache))
265                {
266                    Cache::clear();
267                    $this->redirect();
268                }
269                elseif(!empty($this->_request->clearhtmlcache))
270                {
271                    Cache::clearHTML();
272                    $this->redirect();
273                }
274                elseif(!empty($this->_request->cleardbcache))
275                {
276                    Cache::clearDB();
277                    $this->redirect();
278                }
279            }
280
281            $this->$action(); // execute the given action
282        } 
283        catch(Exception $e) 
284        {
285            $this->_db->rollback();
286
287            throw new Exception($e->getContent(), $e->getCode());
288        }
289
290        return $this;
291    }
292
293    /**
294     * Returns a clone of the current request object
295     *
296     * @author Pierre-Alain Mignot <contact@openwebreader.org>
297     * @return mixed clone of the current request
298     * @access public
299     */
300    public function getRequest()
301    {
302        return clone($this->_request);
303    }
304
305    /**
306     * Render the page
307     *
308     * @author Pierre-Alain Mignot <contact@openwebreader.org>
309     * @param int $statusCode HTTP status code, usefull for errors
310     * @return $this
311     * @access public
312     */
313    public function renderPage($statusCode = 200)
314    {
315        $error = @ob_get_clean();
316        if($error)
317        {
318            do
319            {
320                Logs::iGet()->log($error);
321            }
322            while($error = @ob_get_clean());
323        }
324
325        isset($this->_view) || $this->_view = View::iGet();
326
327        if(isset($_SERVER['HTTP_ACCEPT']) && (false !== strpos($_SERVER['HTTP_ACCEPT'], 'application/json')))
328        {
329            $this->_view->addHeaders(array('Content-Type' => 'application/json; charset=utf-8'));
330            $page = array('contents' => '');
331
332            if(!isset($this->_request->unreads))
333            {
334                try
335                {
336                    $this->do_getunread(true);
337                }
338                catch(Exception $e)
339                {
340                    Logs::iGet()->log($e->getContent(), $e->getCode());
341                }
342            }
343
344            $page['unreads'] =& $this->_request->unreads;
345            $page['contents'] =& $this->_request->page;
346
347            if(Logs::iGet()->hasLogs())
348            {
349                if(DEBUG || $this->_user->isAdmin())
350                {
351                    $page['errors'] = Logs::iGet()->getLogs();
352                    $this->_cleanIndent($page['errors']);
353                }
354                else
355                {
356                    Logs::iGet()->writeLogs();
357                    $errors = Logs::iGet()->getLogs();
358   
359                    foreach($errors as $errcode=>$errmsg)
360                    {
361                        if(Exception::E_OWR_DIE === $errcode)
362                        {
363                            $this->_cleanIndent($errmsg);
364                            foreach($errmsg as $err)
365                                $page['errors'][] = $err;
366                        }
367                    }
368
369                    if(empty($page['errors'])) $page['errors'][] = Utilities::iGet()->_('Non-blocking error(s) occured');
370                }
371            }
372           
373            if(empty($page['errors']) && isset($_SERVER['REQUEST_METHOD']) && 'GET' === $_SERVER['REQUEST_METHOD'])
374            {
375                $etag = '"owr-'.md5(serialize($page)).'"';
376                $this->_view->addHeaders(array(
377                    'Cache-Control' => 'Public, must-revalidate',
378                    "Expires" => gmdate("D, d M Y H:i:s", $this->_request->begintime + $this->_cfg->get('cacheTime'))." GMT",
379                    'Etag' => $etag
380                ), true);
381                if(isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] === $etag)
382                {
383                    $this->_view->setStatusCode(304, true);
384                    flush();
385                    return true;
386                }
387            }
388
389            $now = microtime(true);
390            $page['executionTime'] = round($now - $this->_cfg->get('begintime'), 6);
391            $page['requestTime'] = round($now - $this->_request->begintime, 6);
392            $page['sqlTime'] = round(DB::getTime(), 6);
393            $page['renderingTime'] = round(View::getTime(), 6);
394            $page = json_encode($page);
395        }
396        else
397        {
398            $this->_view->addHeaders(array('Content-type' => 'text/html; charset=utf-8'));
399            if(Logs::iGet()->hasLogs())
400            {
401                if(DEBUG || $this->_user->isAdmin())
402                {
403                    $errors = Logs::iGet()->getLogs();
404                    $err = array();
405                    foreach($errors as $errcode=>$errmsg)
406                    {
407                        $this->_cleanIndent($errmsg);
408                        foreach($errmsg as $msg)
409                            $err[] = $msg;
410                    }
411
412                    $this->_request->page .= '<script type="text/javascript">';
413                    $this->_request->page .= "var e=window.parent||window;if(e.addEvent){ e.addEvent('domready', function(){ if(e.rP) { e.rP.setLogs(e.JSON.decode('".addslashes(json_encode($err))."'),true); }else{ e.document.write('".addslashes(join('<br/>', $err))."'); }});} else {e.document.write('".addslashes(join('<br/>', $err))."');}";
414                    $this->_request->page .= '</script>';
415                    $this->_request->page .= '<noscript>';
416                    $this->_request->page .= join('<br/>', $err);
417                    $this->_request->page .= '</noscript>';
418                }
419                else
420                {
421                    $errors = Logs::iGet()->getLogs();
422                    $err = array();
423                    foreach($errors as $errcode=>$errmsg)
424                    {
425                        if(Exception::E_OWR_DIE === $errcode)
426                        {
427                            $this->_cleanIndent($errmsg);
428                            foreach($errmsg as $msg)
429                                $err[] = $msg;
430                        }
431                    }
432
433                    if(empty($page['errors'])) $page['errors'][] = Utilities::iGet()->_('Non-blocking error(s) occured');
434
435                    Logs::iGet()->writeLogs();
436
437                    if(!empty($err))
438                    {
439                        $this->_request->page .= '<script type="text/javascript">';
440                        $this->_request->page .= "var e=window.parent||window;if(e.addEvent){ e.addEvent('domready', function(){ if(e.rP) { e.rP.setLogs(e.JSON.decode('".addslashes(json_encode($err))."'),true); }else{ e.document.write('".addslashes(join('<br/>', $err))."'); }});} else {e.document.write('".addslashes(join('<br/>', $err))."');}";
441                        $this->_request->page .= '</script>';
442                        $this->_request->page .= '<noscript>';
443                        $this->_request->page .= join('<br/>', $err);
444                        $this->_request->page .= '</noscript>';
445                    }
446                    else
447                    {
448                        if(isset($_SERVER['REQUEST_METHOD']) && 'GET' === $_SERVER['REQUEST_METHOD'])
449                        {
450                            $etag = '"owr-'.md5($this->_request->page).'"';
451                            $this->_view->addHeaders(array(
452                                'Cache-Control' => 'Public, must-revalidate',
453                                "Expires" => gmdate("D, d M Y H:i:s", $this->_request->begintime + $this->_cfg->get('cacheTime'))." GMT",
454                                'Etag' => $etag
455                            ), true);
456                            if(isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] === $etag)
457                            {
458                                $this->_view->setStatusCode(304, true);
459                                flush();
460                                return $this;
461                            }
462                        }
463                        $now = microtime(true);
464                        $this->_request->page .= '<!-- Execution time: '.round($now - $this->_cfg->get('begintime'), 6).'s (Request time: '. round($now - $this->_request->begintime, 6).'s => '.round(DB::getTime(), 6).'s of SQL) -->';
465                    }
466                }
467
468                unset($errors, $err);
469            }
470            else
471            {
472                if(isset($_SERVER['REQUEST_METHOD']) && 'GET' === $_SERVER['REQUEST_METHOD'])
473                {
474                    $etag = '"owr-'.md5($this->_request->page).'"';
475                    $this->_view->addHeaders(array(
476                        'Cache-Control' => 'Public, must-revalidate',
477                        "Expires" => gmdate("D, d M Y H:i:s", $this->_request->begintime + $this->_cfg->get('cacheTime'))." GMT",
478                        'Etag' => $etag
479                    ), true);
480                    if(isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] === $etag)
481                    {
482                        $this->_view->setStatusCode(304, true);
483                        flush();
484                        return $this;
485                    }
486                }
487
488                $now = microtime(true);
489                $this->_request->page .= '<!-- Execution time: '.round($now - $this->_cfg->get('begintime'), 6).'s (Request time: '. round($now - $this->_request->begintime, 6).'s => '.round(DB::getTime(), 6).'s of SQL, '.round(View::getTime(), 6).'s of page rendering) -->';
490            }
491
492            $page =& $this->_request->page;
493        }
494
495        $this->_view->setStatusCode($statusCode, true);
496
497        $this->_view->render($page);
498
499        $this->_request->page = null;
500
501        return $this;
502    }
503
504    /**
505     * Adds a string to $this->_request->page
506     *
507     * @access public
508     * @param mixed $content the content to add (string if page=string, associative array if page=array)
509     */
510    public function addToPage($content)
511    {
512        if(is_array($this->_request->page))
513        {
514            $content = (array) $content;
515            foreach($content as $k=>$v)
516                $this->_request->page[$k] = (string) $v;
517        }
518        else
519        {
520            $this->_request->page .= (string) $content;
521        }
522    }
523
524    /**
525     * Redirects the user to a specific page
526     *
527     * @author Pierre-Alain Mignot <contact@openwebreader.org>
528     * @param string $url the url to redirect
529     * @access public
530     */
531    public function redirect($url = null)
532    {
533        $url = (string) $url;
534
535        if('login' === $url)
536        {
537            $params = 'timeout=1';
538            if(isset($_SERVER['REQUEST_URI']) && (!isset($_SERVER['HTTP_X_REQUESTED_WITH']) || $_SERVER['HTTP_X_REQUESTED_WITH'] !== 'XMLHttpRequest'))
539            {
540                $request = trim(Filter::iGet()->purify($_SERVER['REQUEST_URI']));
541                $current = basename($request);
542                if(false === strpos($current, 'logout') && false === strpos($current, 'login') && $this->_cfg->get('path') !== $request)
543                {
544                    $current = preg_replace('/[?&]token=[^&]*/', '', $current); // strip the token, not needed
545                    if(!empty($current) && $this->_cfg->get('path') !== $request)
546                        $params .= '&back='.urlencode($current);
547                }
548            }
549        }
550        else
551        {
552            $params = 'token='.$this->_user->getToken();
553        }
554
555        $surl = $this->_cfg->makeURI($url, $params, false);
556
557        if(isset($_SERVER['HTTP_ACCEPT']) && (false !== strpos($_SERVER['HTTP_ACCEPT'], 'application/json')))
558        {
559            $page = json_encode(array('location' => $surl));
560            isset($this->_view) || $this->_view = View::iGet();
561            $this->_view->render($page);
562        }
563        elseif(!$this->_isFrame && !headers_sent())
564        {
565            header('Location: '.$surl);
566        } 
567        else
568        {
569            $page = '<a href="'.$surl.'">Redirection</a>';
570            $page .= '<script type="text/javascript">';
571            $page .= $this->_isFrame ? 'window.parent.location.href="'.$surl.'";' : 'window.location.href="'.$surl.'";';
572            $page .= '</script>';
573            $page .= '<noscript>';
574            $page .= '<meta http-equiv="refresh" content="0;url='.$surl.'" />';
575            $page .= '</noscript>';
576            isset($this->_view) || $this->_view = View::iGet();
577            $this->_view->render($page);
578        }
579        exit;
580    }
581
582    /**
583     * Process the response of a Logic call
584     *
585     * @author Pierre-Alain Mignot <contact@openwebreader.org>
586     * @access public
587     * @param mixed LogicResponse the response of the
588     */
589    public function processResponse(LogicResponse $response)
590    {
591        $status = $response->getStatus();
592        if($status)
593            View::iGet()->setStatusCode($status);
594
595        switch($response->getNext())
596        {
597            case 'redirect': // redirection
598                $this->redirect($response->getLocation()); // implicit exit
599                break;
600
601            case 'error': // error
602                $this->_request->errors = $response->getErrors();
603                $tpl = $response->getTpl();
604                if($tpl)
605                {
606                    $this->_getPage($tpl, $response->getDatas());
607                }
608                else Logs::iGet()->log($response->getError(), $response->getStatus());
609                $ret = false;
610                break;
611
612            case 'ok': // ok !
613                $ret = true;
614                $tpl = $response->getTpl();
615                if($tpl)
616                {
617                    $this->_getPage($tpl, $response->getDatas());
618                }
619                break;
620
621            default:
622                throw new Exception('Invalid return from Logic', Exception::E_OWR_DIE);
623                break;
624        }
625
626        return $ret;
627    }
628
629    /**
630     * Returns a date in user lang from a timestamp
631     *
632     * @author Pierre-Alain Mignot <contact@openwebreader.org>
633     * @param int $timestamp the timestamp to convert
634     * @return string the date
635     * @access protected
636     */
637    protected function _getDate($timestamp)
638    {
639        isset($this->_dateFormatter) ||
640        $this->_dateFormatter = new \IntlDateFormatter(
641            $this->_user->getLang(), 
642            \IntlDateFormatter::FULL,
643            \IntlDateFormatter::MEDIUM
644        );
645        return $this->_dateFormatter->format((int)$timestamp);
646    }
647
648    /**
649     * Removes whitespaces characters
650     * Used for javascript response that can not handle them
651     *
652     * @author Pierre-Alain Mignot <contact@openwebreader.org>
653     * @param mixed &$contents the contents to clean, array or string
654     * @access protected
655     */
656    protected function _cleanIndent(&$contents)
657    {
658        if(is_array($contents))
659        {
660            array_walk_recursive($contents, array($this, '_cleanIndent'));
661        }
662        else
663        {
664            $contents = preg_replace('/(\s)\s+/s', "\\1", (string) $contents);
665            $contents = str_replace("\n\n", ' ', $contents);
666            $contents = str_replace("\n", ' ', $contents);
667            $contents = str_replace("\r\r", '', $contents);
668            $contents = str_replace("\r", '', $contents);
669            $contents = str_replace("\t\t", ' ', $contents);
670            $contents = str_replace("\t", ' ', $contents);
671            $contents = str_replace('  ', ' ', $contents);
672        }
673    }
674
675    /**
676     * Gets a template to display
677     *
678     * @author Pierre-Alain Mignot <contact@openwebreader.org>
679     * @param string $tpl the name of the tpl, without the extension
680     * @param array $datas the datas to apply to the template
681     * @param boolean $return returns the template instead of rendering it
682     * @return mixed the template if $return=true, else true
683     * @access protected
684     */
685    protected function _getPage($tpl, array $datas = array(), $return = false)
686    {
687        isset($this->_view) || $this->_view = View::iGet();
688
689        $cacheTime = $this->_cfg->get('cacheTime');
690        $noCacheDatas = array();
691        $empty = false;
692        $page = '';
693
694        switch($tpl)
695        {
696            case 'new_contents':
697                $request = new Request(array('id' => $datas['id']));
698                Logic::getCachedLogic('news')->view($request);
699                $response = $request->getResponse();
700                if('error' !== $response->getNext())
701                {
702                    $datas = $response->getDatas();
703                    if($this->_user->getConfig('blockimg'))
704                    {
705                        array_walk_recursive($datas, function(&$data) {
706                            $data = preg_replace('/<img\b([^>]*)(src\s*=\s*([\'"])?(.*?)\\3\s*)[^>]*\/?>/ise',
707                                "'<a href=\"javascript:;\" title=\"Blocked image, click to see it ! " .
708                                "('.addcslashes(\"\\4\", '\"').')\" class=\"img_blocked backgrounded\" " .
709                                "onclick=\"rP.loadImage(this, \''.addcslashes(\"\\4\", '\'').'\');\">" .
710                                "<img alt=\"&nbsp;&nbsp;&nbsp;&nbsp;\"/></a>'", $data);
711                        });
712                    }
713                    $page .= $this->_view->get('new_contents', $datas, $cacheTime);
714                }
715                else
716                {
717                    Logs::iGet()->log($response->getError(), $response->getStatus());
718                    $empty = true;
719                }
720                unset($response, $request);
721            break;
722
723            case 'new_details':
724                $datas['details'] = array();
725                $request = new Request(array('id' => $datas['id']));
726                Logic::getCachedLogic('news')->view($request);
727                $response = $request->getResponse();
728                if('error' !== $response->getNext())
729                {
730                    $data = $response->getDatas();
731                    $datas['url'] = htmlspecialchars($data['link'], ENT_COMPAT, 'UTF-8');
732                    $datas['title'] = htmlspecialchars($data['title'], ENT_COMPAT, 'UTF-8');
733                    foreach($data['contents'] as $k => $content)
734                    {
735                        switch($k)
736                        {
737                            case 'description':
738                            case 'content':
739                            case 'encoded':
740                            case 'url':
741                            case 'title':
742                                break;
743
744                            default:
745                                $datas['details'][$k] = $content;
746                                break;
747                        }
748                    }
749                }
750                else
751                {
752                    Logs::iGet()->log($response->getError(), $response->getStatus());
753                    $empty = true;
754                }
755                unset($response, $request);
756            break;
757
758            case 'menu_part_category':
759                $datas['gname'] = $datas['name'];
760                $datas['groupid'] = $datas['gid'];
761
762                if(empty($this->_request->unreads))
763                    $this->do_getunread(true);
764
765                $noCacheDatas['unread'] = isset($this->_request->unreads[$datas['gid']]) ? $this->_request->unreads[$datas['gid']] : 0;
766                $noCacheDatas['bold'] = $noCacheDatas['unread'] > 0 ? 'bold ' : '';
767                $tpl = 'menu_contents';
768                break;
769
770            case 'menu_part_group':
771                $streams = DAO::getDAO('streams_relations')->get(array('gid' => $datas['id']), 'rssid');
772                if(!$streams)
773                {
774                    $empty = true;
775                    break;
776                }
777                if(empty($this->_request->unreads))
778                    $this->do_getunread(true);
779                if(is_object($streams))
780                    $streams = array($streams);
781                $request = new Request(array('id'=>null));
782                Logic::getCachedLogic('streams_groups')->view($request, array(), 'name');
783                $response = $request->getResponse();
784                $groups = array();
785                if('error' !== $response->getNext())
786                {
787                    $groups = $response->getDatas();
788                    if(!$response->isMultiple()) $groups = array($groups);
789                }
790                else
791                {
792                    Logs::iGet()->log($response->getError(), $response->getStatus());
793                    $empty = true;
794                    break;
795                }
796                unset($response, $g);
797                $request->getContents = false;
798                $streamsToDisplay = array();
799                foreach($streams as $s)
800                {
801                    $request->id = $s->rssid;
802                    Logic::getCachedLogic('streams')->view($request);
803                    $response = $request->getResponse();
804                    if('error' !== $response->getNext())
805                    {
806                        $stream = $response->getDatas();
807                        if(empty($stream))
808                        {
809                            $empty = true;
810                            break;
811                        }
812                        $stream['groups'] = $groups;
813                        if($stream['status'] > 0) 
814                        {
815                            $stream['unavailable'] = $this->_getDate($stream['status']);
816                        }
817
818                        if(!isset($groups_select[$stream['gid']]))
819                            $groups_select[$stream['gid']] = $this->_view->get('menu_selects', array(
820                                                                        'gid' => $stream['gid'],
821                                                                        'groups' => $groups),
822                                                                        $cacheTime
823                                                        );
824                        $streamsToDisplay[$stream['name']] = $stream;
825                        $streamsToDisplay[$stream['name']]['unread'] = isset($this->_request->unreads[$stream['id']]) ? $this->_request->unreads[$stream['id']] : 0;
826                    }
827                    else
828                    {
829                        Logs::iGet()->log($response->getError(), $response->getStatus());
830                        $empty = true;
831                        break;
832                    }
833                    unset($response);
834                }
835                unset($streams);
836
837                ksort($streamsToDisplay);
838
839                foreach($streamsToDisplay as $stream)
840                {
841                    $unread = $stream['unread'];
842                    unset($stream['unread']);
843                    $page .= $this->_view->get('menu_streams', $stream, $cacheTime, array(
844                            'unread'    => $unread,
845                            'bold'      => $unread > 0 ? 'bold ' : '',
846                            'groups_select'     => $groups_select[$stream['gid']]
847                            ));
848                }
849
850                unset($streamsToDisplay, $request);
851                break;
852
853            case 'news_tags_contents':
854                $request = new Request(array(), true);
855                Logic::getCachedLogic('news_tags')->view($request, array('newsid' => $datas['id']));
856                $response = $request->getResponse();
857                if('error' !== $response->getNext())
858                {
859                    $tags = $response->getDatas();
860                    if(empty($tags))
861                    {
862                        $empty = true;
863                        break;
864                    }
865
866                    if($response->isMultiple())
867                    {
868                        $page = array();
869                        foreach($tags as $tag)
870                            $page[] = $tag['name'];
871                        $page = join(',', $page);
872                    }
873                    else $page .= $tags['name'];
874                }
875                else
876                {
877                    Logs::iGet()->log($response->getError(), $response->getStatus());
878                    $empty = true;
879                }
880                unset($response, $request);
881                break;
882
883            case 'menu_part_stream':
884                $request = new Request(array('id' => $datas['id']));
885                Logic::getCachedLogic('streams')->view($request);
886                $response = $request->getResponse();
887                if('error' !== $response->getNext())
888                {
889                    $datas['stream'] = $response->getDatas();
890                    unset($datas['stream']['title']);
891                    $datas['stream']['contents']['nextRefresh'] = $this->_getDate($datas['stream']['lastupd'] + $datas['stream']['ttl']);
892                    $datas['stream']['contents']['id'] = $datas['stream']['id'];
893                    $datas['stream']['contents']['url'] = $datas['stream']['url'];
894                }
895                else
896                {
897                    Logs::iGet()->log($response->getError(), $response->getStatus());
898                    $empty = true;
899                }
900                unset($response, $request);
901                break;
902
903            case 'news':
904                if(empty($this->_request->unreads))
905                    $this->do_getunread(true);
906
907                $datas['abstract'] = $this->_user->getConfig('abstract');
908                $ids = null;
909                $uid = $this->_user->getUid();
910
911                if(!empty($datas['sort']))
912                {
913                    $order = $datas['sort'].' '.$datas['dir'];
914                    if('news.pubDate' !== $datas['sort'])
915                        $order .= ',news.pubDate DESC';
916                }
917                else
918                {
919                    $order = 'news.pubDate DESC';
920                }
921
922                $offset = 0;
923
924                if(isset($datas['offset']))
925                {
926                    $datas['offset'] = (int)$datas['offset'];
927
928                    if($datas['offset'] > 0)
929                    {
930                        $offset = (int)($datas['offset']*10);
931                    }
932                }
933                else
934                {
935                    $datas['offset'] = 0;
936                }
937
938                $offset = $offset.','.$this->_user->getConfig('nbnews');
939
940                if(isset($datas['id']) && is_array($datas['id']))
941                {
942                    if(empty($datas['id']))
943                    {
944                        $empty = true;
945                        break;
946                    }
947                    $request = new Request(array('ids' => $datas['id'], 'getContents' => $datas['abstract']));
948                    Logic::getCachedLogic('news')->view($request, array(), $order, 'news.id', $offset);
949                    $datas['nbNews'] = count($datas['id']);
950                }
951                elseif(empty($datas['id']))
952                {
953                    $request = new Request(array('id' => null, 'getContents' => $datas['abstract']));
954                    Logic::getCachedLogic('news')->view($request, array('status' => 1), $order, 'news.id', $offset);
955                    $datas['nbNews'] = isset($this->_request->unreads[0]) ? $this->_request->unreads[0] : 0;
956                }
957                else
958                {
959                    try
960                    {
961                        $table = DAO::getType($datas['id']);
962                    }
963                    catch(Exception $e)
964                    {
965                        switch($e->getCode())
966                        {
967                            case Exception::E_OWR_NOTICE:
968                            case Exception::E_OWR_WARNING:
969                                Logs::iGet()->log($e->getContent(), $e->getCode());
970                                $empty = true;
971                                break 2;
972                            default: throw new Exception($e->getContent(), $e->getCode());
973                                break;
974                        }
975                    }
976
977                    $request = new Request(array('id' => null, 'getContents' => $datas['abstract']));
978                    if('streams' === $table)
979                    {
980                        Logic::getCachedLogic('news')->view($request, array('rssid' => $datas['id']), $order, 'news.id', $offset);
981                        $nb = DAO::getCachedDAO('news_relations')->count(array('rssid' => $datas['id']), 'newsid');
982                        $datas['nbNews'] = $nb ? $nb->nb : 0;
983                    }
984                    elseif('streams_groups' === $table)
985                    {
986                        Logic::getCachedLogic('news')->view($request, array('gid' => $datas['id']), $order, 'news.id', $offset);
987                        $nb = DAO::getCachedDAO('news_relations')->count(array('gid' => $datas['id']), 'newsid');
988                        $datas['nbNews'] = $nb ? $nb->nb : 0;
989                    }
990                    elseif('news_tags' === $table)
991                    {
992                        Logic::getCachedLogic('news')->view($request, array('tid' => $datas['id']), $order, 'news.id', $offset);
993                        $nb = DAO::getCachedDAO('news_relations_tags')->count(array('tid' => $datas['id']), 'newsid');
994                        $datas['nbNews'] = $nb ? $nb->nb : 0;
995                    }
996                    else
997                    {
998                        Logs::iGet()->log(Utilities::iGet()->_('Invalid id'));
999                        $empty = true;
1000                        break;
1001                    }
1002                }
1003
1004                $response = $request->getResponse();
1005                if('error' !== $response->getNext())
1006                {
1007                    $news = $response->getDatas();
1008                    if(empty($news))
1009                    {
1010                        $empty = true;
1011                        break;
1012                    }
1013
1014                    if(!$response->isMultiple()) $news = array($news);
1015                }
1016                else
1017                {
1018                    Logs::iGet()->log($response->getError(), $response->getStatus());
1019                    $empty = true;
1020                    break;
1021                }
1022                unset($response, $request, $result);
1023
1024                $pager = array('nbNews'         => (int) $datas['nbNews'],
1025                                'offset'        => $datas['offset'],
1026                                'sort'          => !empty($datas['sort']) ? $datas['sort'] : null,
1027                                'dir'           => !empty($datas['dir']) ? $datas['dir'] : null,
1028                                'nbNewsByPage'  => $this->_user->getConfig('nbnews'));
1029
1030                if(empty($datas['search']))
1031                {
1032                    $pager = $this->_view->get('news_tools', $pager, $cacheTime);
1033                    $page .= $pager;
1034                }
1035
1036                unset($news['ids']);
1037
1038                foreach($news as $k => $new)
1039                {
1040                    if(isset($datas['searchResults'][$new['id']]))
1041                        $new['search_result'] = (float) $datas['searchResults'][$new['id']];
1042                    $new['pubDate'] = $this->_getDate($new['pubDate']);
1043                    $new['abstract'] = $datas['abstract'];
1044                    $page .= $this->_view->get('new_title', $new, $cacheTime);
1045                }
1046                unset($news);
1047
1048                if(empty($datas['search']))
1049                {
1050                    $page .= $pager;
1051                    unset($pager);
1052                }
1053            break;
1054
1055            case 'index':
1056                if(empty($this->_request->unreads))
1057                    $this->do_getunread(true);
1058                $token = $this->_user->getToken();
1059                $surl = $this->_cfg->get('surl');
1060                $ulang = $this->_user->getLang();
1061                $uid = $this->_user->getUid();
1062                $page .= $this->_view->get('header', array(
1063                                                        'surl'      =>$surl, 
1064                                                        'xmlLang'   =>$this->_user->getXMLLang(),
1065                                                    ), 
1066                                                    $cacheTime,
1067                                                    array(
1068                                                        'token' => $token
1069                                                    ));
1070
1071                $page .= $this->_view->get('board', array(
1072                                                        'lang' => $ulang,
1073                                                        'surl' => $surl,
1074                                                    ), 
1075                                                    $cacheTime,
1076                                                    array(
1077                                                        'userlogin' => htmlentities($this->_user->getLogin(), ENT_COMPAT, 'UTF-8'),
1078                                                        'token'     => $token
1079                                                    ));
1080
1081                $request = new Request(array('id'=>null));
1082                Logic::getCachedLogic('streams_groups')->view($request, array(), 'name');
1083                $response = $request->getResponse();
1084                $groups = array();
1085                $tmpPage = '';
1086                if('error' !== $response->getNext())
1087                {
1088                    $groups = $response->getDatas();
1089                    if(!empty($groups))
1090                    {
1091                        if($response->isMultiple())
1092                        {
1093                            foreach($groups as $group)
1094                            {
1095                                $group['groupid'] = $group['id'];
1096                                $group['gname'] = $group['name'];
1097                                $noCacheDatas['unread'] = isset($this->_request->unreads[$group['id']]) ? $this->_request->unreads[$group['id']] : 0;
1098                                $noCacheDatas['bold'] = $noCacheDatas['unread'] > 0 ? 'bold ' : '';
1099                                $tmpPage .= $this->_view->get('menu_contents', $group, $cacheTime, $noCacheDatas);
1100                            }
1101                        }
1102                        else
1103                        {
1104                            $groups['groupid'] = $groups['id'];
1105                            $groups['gname'] = $groups['name'];
1106                            $noCacheDatas['unread'] = isset($this->_request->unreads[$groups['id']]) ? $this->_request->unreads[$groups['id']] : 0;
1107                            $noCacheDatas['bold'] = $noCacheDatas['unread'] > 0 ? 'bold ' : '';
1108                            $tmpPage .= $this->_view->get('menu_contents', $groups, $cacheTime, $noCacheDatas);
1109                            $groups = array($groups);
1110                        }
1111                    }
1112                }
1113                else
1114                {
1115                    Logs::iGet()->log($response->getError(), $response->getStatus());
1116                    $empty = true;
1117                }
1118                unset($response, $request);
1119                $page .= $this->_view->get('contents_header', array(), $cacheTime);
1120                $page .= $this->_getPage('news', $datas, true);
1121                $page .= $this->_view->get('contents_footer', array(), $cacheTime);
1122                $page .= $this->_view->get('menu_header', array(), $cacheTime, 
1123                                            array(
1124                                                'unread' => $this->_request->unreads[0], 
1125                                                'bold' => $this->_request->unreads[0] > 0 ? ' class="bold"' : ''
1126                                            ));
1127                $page .= $tmpPage;
1128                unset($tmpPage);
1129                $page .= $this->_view->get('menu_tags', array(), $cacheTime);
1130
1131                $page .= $this->_getPage('menu_tags_contents', $datas, true);
1132
1133                $page .= $this->_view->get('menu_footer', array(
1134                                                            'groups'            => $groups, 
1135                                                            'userrights'        => $this->_user->getRights(),
1136                                                            'surl'              => $surl,
1137                                                            'maxuploadfilesize' => $this->_cfg->get('maxUploadFileSize')
1138                                                        ), 
1139                                                        $cacheTime,
1140                                                        array(
1141                                                            'token'             => $token,
1142                                                            'uid'               => $uid,
1143                                                            'groups_select'     => $this->_view->get('menu_selects', array(
1144                                                                        'gid' => 0,
1145                                                                        'groups' => $groups),
1146                                                                        $cacheTime
1147                                                        )));
1148                unset($groups);
1149                $page .= $this->_view->get('footer', array(
1150                                                        'lang'=>$ulang,
1151                                                        'surl'=>$surl
1152                                                        ), 
1153                                                        $cacheTime,
1154                                                    array(
1155                                                        'token'=>$token,
1156                                                        'ttl'=>$this->_cfg->get('defaultMinStreamRefreshTime')*60*1000,
1157                                                        'opensearch'=>(isset($datas['opensearch']) ? $datas['opensearch'] : 0)
1158                                                    ));
1159                break;
1160
1161            case 'menu_tags_contents':
1162                $request = new Request(array('id' => isset($datas['id']) ? $datas['id'] : null, 'ids' => isset($datas['ids']) ? $datas['ids'] : null));
1163                Logic::getCachedLogic('news_tags')->view($request, array(), 'name');
1164                $response = $request->getResponse();
1165                if('error' !== $response->getNext())
1166                {
1167                    $tags = $response->getDatas();
1168                    if(!empty($tags))
1169                    {
1170                        if($response->isMultiple())
1171                        {
1172                            foreach($tags as $tag)
1173                            {
1174                                $tag['groupid'] = $tag['id'];
1175                                $tag['gname'] = $tag['name'];
1176                                $noCacheDatas['unread'] = isset($this->_request->unreads[$tag['id']]) ? $this->_request->unreads[$tag['id']] : 0;
1177                                $noCacheDatas['bold'] = $noCacheDatas['unread'] > 0 ? 'bold ' : '';
1178                                $page .= $this->_view->get('menu_tags_contents', $tag, $cacheTime, $noCacheDatas);
1179                            }
1180                        }
1181                        else
1182                        {
1183                            $tags['groupid'] = $tags['id'];
1184                            $tags['gname'] = $tags['name'];
1185                            $noCacheDatas['unread'] = isset($this->_request->unreads[$tags['id']]) ? $this->_request->unreads[$tags['id']] : 0;
1186                            $noCacheDatas['bold'] = $noCacheDatas['unread'] > 0 ? 'bold ' : '';
1187                            $page .= $this->_view->get('menu_tags_contents', $tags, $cacheTime, $noCacheDatas);
1188                        }
1189                    }
1190                    else $empty = true;
1191                    unset($tags);
1192                }
1193                else
1194                {
1195                    Logs::iGet()->log($response->getError(), $response->getStatus());
1196                    $empty = true;
1197                }
1198                break;
1199
1200            case 'getopensearch':
1201                $datas['surl'] = $this->_cfg->get('surl');
1202                break;
1203
1204            case 'opml':
1205                $datas['userlogin'] = $this->_user->getLogin();
1206                $noCacheDatas['dateCreated'] = $datas['dateCreated'];
1207                unset($datas['dateCreated']);
1208                $datas['streams'] = array();
1209                $request = new Request(array('id'=>null));
1210                Logic::getCachedLogic('streams')->view($request);
1211                $response = $request->getResponse();
1212                if('error' !== $response->getNext())
1213                {
1214                    $streams = $response->getDatas();
1215                    if(empty($streams)) break;
1216
1217                    if($response->isMultiple())
1218                    {
1219                        foreach($streams as $stream)
1220                        {
1221                            if(!isset($datas['groups'][$stream['gid']]))
1222                                $datas['groups'][$stream['gid']] = $stream['gname'];
1223                            $datas['streams'][$stream['gid']][] = $stream;
1224                        }
1225                    }
1226                    else
1227                    {
1228                        $datas['groups'][$streams['gid']] = $streams['gname'];
1229                        $datas['streams'][$streams['gid']][] = $streams;
1230                    }
1231                }
1232                else
1233                {
1234                    Logs::iGet()->log($response->getError(), $response->getStatus());
1235                    $empty = true;
1236                }
1237                unset($response, $request, $streams);
1238                break;
1239
1240            case 'edituser':
1241                $noCacheDatas['token'] = $this->_user->getToken();
1242                if(empty($datas['id']))
1243                { // surely editing a new user
1244                    $datas['surl'] = $this->_cfg->get('surl');
1245                    $datas['timezones'] = $this->_user->getTimeZones();
1246                    $datas['userrights'] = $this->_user->getRights();
1247                    break;
1248                }
1249
1250                $request = new Request(array('id' => $datas['id']));
1251                $datas['surl'] = $this->_cfg->get('surl');
1252                $datas['timezones'] = $this->_user->getTimeZones();
1253                $datas['userrights'] = $this->_user->getRights();
1254                Logic::getCachedLogic('users')->view($request);
1255                $response = $request->getResponse();
1256                if('error' !== $response->getNext())
1257                {
1258                    $datas += $response->getDatas();
1259                }
1260                else
1261                {
1262                    Logs::iGet()->log($response->getError(), $response->getStatus());
1263                    $empty = true;
1264                }
1265                unset($response, $request);
1266                break;
1267
1268            case 'users':
1269                $request = new Request($datas);
1270                $datas['surl'] = $this->_cfg->get('surl');
1271                $noCacheDatas['token'] = $this->_user->getToken();
1272                $datas['users'] = array();
1273                $datas['nbusers'] = 0;
1274                Logic::getCachedLogic('users')->view($request, array(), 'login');
1275                $response = $request->getResponse();
1276                if('error' !== $response->getNext())
1277                {
1278                    if(!$response->isMultiple())
1279                    {
1280                        $datas['users'][] = $response->getDatas();
1281                        $datas['nbusers'] = 1;
1282                    }
1283                    else
1284                    {
1285                        $datas['users'] = $response->getDatas();
1286                        $datas['nbusers'] = count($datas['users']);
1287                    }
1288                }
1289                else
1290                {
1291                    Logs::iGet()->log($response->getError(), $response->getStatus());
1292                    $empty = true;
1293                }
1294                unset($response, $request);
1295                break;
1296
1297            case 'rss':
1298                $request = new Request(array('id'=>null));
1299                $datas['surl'] = $this->_cfg->get('surl');
1300                $datas['userlogin'] = $this->_user->getLogin();
1301                $args = array('status' => 1);
1302                if(!empty($datas['id']))
1303                    $args['rssid'] = $datas['id'];
1304                $datas['news'] = $ids = array();
1305                Logic::getCachedLogic('news')->view($request, $args);
1306                $response = $request->getResponse();
1307                if('error' !== $response->getNext())
1308                {
1309                    $data = $response->getDatas();
1310                    if(empty($data)) break;
1311
1312                    if($response->isMultiple())
1313                    {
1314                        $datas['news'] = $data;
1315                        unset($data);
1316                        foreach($datas['news'] as $k=>$new)
1317                        {
1318                            $ids[] = $new['id'];
1319                            $datas['news'][$k]['pubDate'] = date(DATE_RSS, $new['pubDate']);
1320                        }
1321                    }
1322                    else
1323                    {
1324                        $ids[] = $data['id'];
1325                        $data['pubDate'] = date(DATE_RSS, $data['pubDate']);
1326                        $datas['news'][] = $data;
1327                    }
1328
1329                }
1330                else
1331                {
1332                    Logs::iGet()->log($response->getError(), $response->getStatus());
1333                    $empty = true;
1334                }
1335                unset($response, $request);
1336
1337                if(!empty($ids))
1338                {
1339                    $query = '
1340    UPDATE news_relations
1341        SET status=0
1342        WHERE uid='.$this->_user->getUid().' AND newsid IN ('.join(',', $ids).')';
1343                    $this->_db->set($query);
1344                }
1345                break;
1346
1347            case 'login':
1348                $datas['surl'] = $this->_cfg->get('surl');
1349                $datas['xmlLang'] = $this->_user->getXMLLang();
1350                $noCacheDatas['token'] = $this->_user->getToken();
1351                $noCacheDatas['back'] = $this->_request->back;
1352                break;
1353
1354            default: 
1355                break;
1356        }
1357
1358        if(!empty($page))
1359        {
1360            if($return)
1361                return $page;
1362            else
1363                $this->_request->page .= $page;
1364        }
1365        elseif(!$empty)
1366        {
1367            if($return) 
1368                return $this->_view->get($tpl, $datas, $cacheTime, $noCacheDatas);
1369            else
1370                $this->_request->page .= $this->_view->get($tpl, $datas, $cacheTime, $noCacheDatas);
1371        }
1372    }
1373
1374    /**
1375     * Methods bellow are actions to be executed by $this->execute()
1376     * They all are prefixed with do_*
1377     * @access protected
1378     * @return $this
1379     */
1380
1381    /**
1382     * Now functions that do not require a logic call
1383     */
1384
1385    /**
1386     * Redirects to an external operator
1387     *
1388     * @author Pierre-Alain Mignot <contact@openwebreader.org>
1389     * @access protected
1390     * @return $this
1391     */
1392    protected function do_redirectOperator()
1393    {
1394        if(!$this->_request->id)
1395            throw new Exception('Missing id', Exception::E_OWR_BAD_REQUEST);
1396
1397        if(!$this->_request->operator)
1398            throw new Exception('Missing operator', Exception::E_OWR_BAD_REQUEST);
1399
1400        if('news' !== DAO::getType($this->_request->id))
1401            throw new Exception('Invalid id', Exception::E_OWR_BAD_REQUEST);
1402
1403        $operator = new Operator($this->_request->operator);
1404        $operator->redirect(DAO::getCachedDAO('news')->get($this->_request->id, 'title, link'));
1405
1406        return $this;
1407    }
1408
1409    /**
1410     * Renders the stream template related to the specified id
1411     *
1412     * @author Pierre-Alain Mignot <contact@openwebreader.org>
1413     * @access protected
1414     * @return $this
1415     */
1416    protected function do_getRSS()
1417    {
1418        isset($this->_view) || $this->_view = View::iGet();
1419        $this->_view->addHeaders(array('Content-Type' => 'text/xml; charset=utf-8'));
1420        $this->_getPage('rss', array('id'=>$this->_request->id));
1421        return $this;
1422    }
1423
1424    /**
1425     * Renders the unreads news count
1426     *
1427     * @author Pierre-Alain Mignot <contact@openwebreader.org>
1428     * @access protected
1429     * @return $this
1430     */
1431    protected function do_getLastNews()
1432    {
1433        return $this->do_getunread(true);
1434    }
1435
1436    /**
1437     * Renders the details of a new for a specific id
1438     *
1439     * @author Pierre-Alain Mignot <contact@openwebreader.org>
1440     * @access protected
1441     * @return $this
1442     */
1443    protected function do_getNewDetails()
1444    {
1445        $this->_getPage('new_details', array('id' => $this->_request->id));
1446        return $this;
1447    }
1448
1449    /**
1450     * Renders the category template for a specific id
1451     *
1452     * @author Pierre-Alain Mignot <contact@openwebreader.org>
1453     * @access protected
1454     * @return $this
1455     */
1456    protected function do_getMenuPartGroup()
1457    {
1458        $this->_getPage('menu_part_group', array('id'=>$this->_request->id));
1459        return $this;
1460    }
1461
1462    /**
1463     * Renders the stream template for a specific id
1464     *
1465     * @author Pierre-Alain Mignot <contact@openwebreader.org>
1466     * @access protected
1467     */
1468    protected function do_getMenuPartStream()
1469    {
1470        $this->_getPage('menu_part_stream', array('id'=>$this->_request->id));
1471        return $this;
1472    }
1473
1474    /**
1475     * Renders news template from a specific stream with a specific offset
1476     *
1477     * @author Pierre-Alain Mignot <contact@openwebreader.org>
1478     * @access protected
1479     * @return $this
1480     */
1481    protected function do_getStream()
1482    {
1483        if(0 < $this->_request->id)
1484        {
1485            $type = DAO::getType($this->_request->id);
1486
1487            if('streams' !== $type && 'streams_groups' !== $type && 'news_tags' !== $type)
1488                throw new Exception('Invalid Id', Exception::E_OWR_BAD_REQUEST);
1489        }
1490
1491        $this->_getPage('news', array( 
1492                            'id'        => $this->_request->id, 
1493                            'offset'    => $this->_request->offset,
1494                            'sort'      => $this->_request->sort,
1495                            'dir'       => $this->_request->dir
1496        ));
1497        return $this;
1498    }
1499
1500    /**
1501     * Renders the count of unreads news for a specific id
1502     *
1503     * @author Pierre-Alain Mignot <contact@openwebreader.org>
1504     * @access protected
1505     * @return $this
1506     */
1507    protected function do_getLiveNews()
1508    {
1509        if(!$this->_request->id)
1510        {
1511            $nb = DAO::getCachedDAO('news_relations')->count(array('status' => 1));
1512        }
1513        else
1514        {
1515            $type = DAO::getType($this->_request->id);
1516
1517            if('streams' === $type)
1518            {
1519                $nb = DAO::getCachedDAO('news_relations')->count(array('status' => 1, 'rssid' => $this->_request->id));
1520            }
1521            elseif('streams_groups' === $type)
1522            {
1523                $nb = DAO::getCachedDAO('news_relations')->count(array('status' => 1, 'gid' => $this->_request->id));
1524            }
1525            else throw new Exception('Invalid id', Exception::E_OWR_BAD_REQUEST);
1526        }
1527
1528        $this->_request->page = $nb ? $nb->nb : 0;
1529        return $this;
1530    }
1531
1532    /**
1533     * Renders or sets the unreads news count
1534     *
1535     * @author Pierre-Alain Mignot <contact@openwebreader.org>
1536     * @param boolean $return $return sets instead of rendering
1537     * @access protected
1538     * @return $this
1539     */
1540    protected function do_getUnread($return=false)
1541    {
1542        $unreads = array();
1543        $unreads[0] = 0;
1544
1545        $this->_request->unreads = array();
1546        $nb = DAO::getCachedDAO('news_relations')->count(array('status' => 1, 'FETCH_TYPE' => 'array'), 'newsid', 'rssid', 'rssid,gid');
1547        if($nb)
1548        {
1549            if(is_array($nb[0]))
1550            {
1551                foreach($nb as $count)
1552                {
1553                    $unreads[0] += $count[0];
1554                    $unreads[$count[1]] = $count[0];
1555                    isset($unreads[$count[2]]) || ($unreads[$count[2]] = 0);
1556                    $unreads[$count[2]] += $count[0];
1557                }
1558            }
1559            else
1560            {
1561                $unreads[0] += $nb[0];
1562                $unreads[$nb[1]] = $nb[0];
1563                $unreads[$nb[2]] = $nb[0];
1564            }
1565        }
1566
1567        $nb = DAO::getCachedDAO('news_relations')->count(array('status' => 1, 'FETCH_TYPE' => 'array'), 'newsid', 'tid', 'tid');
1568        if($nb)
1569        {
1570            if(is_array($nb[0]))
1571            {
1572                foreach($nb as $count)
1573                {
1574                    $unreads[$count[1]] = $count[0];
1575                }
1576            }
1577            else
1578            {
1579                $unreads[$nb[1]] = $nb[0];
1580            }
1581        }
1582
1583        if(!$return)
1584            $this->_request->page = $unreads;
1585        else
1586            $this->_request->unreads = $unreads;
1587
1588        return $this;
1589    }
1590
1591    /**
1592     * Renders the index page
1593     *
1594     * @author Pierre-Alain Mignot <contact@openwebreader.org>
1595     * @access protected
1596     * @return $this
1597     */
1598    protected function do_index()
1599    {
1600        $this->_getPage('index');
1601        return $this;
1602    }
1603
1604    /**
1605     * Renders the list of the users
1606     *
1607     * @author Pierre-Alain Mignot <contact@openwebreader.org>
1608     * @access protected.
1609     * @return $this
1610     */
1611    protected function do_getUsers()
1612    {
1613        if(!$this->_user->isAdmin())
1614            throw new Exception("You don't have the rights to do that", Exception::E_OWR_UNAUTHORIZED);
1615
1616        $this->_getPage('users');
1617        return $this;
1618    }
1619
1620    /**
1621     * Renders the open search XML declaration
1622     *
1623     * @author Pierre-Alain Mignot <contact@openwebreader.org>
1624     * @access protected
1625     * @return $this
1626     */
1627    protected function do_getOpenSearch()
1628    {
1629        isset($this->_view) || $this->_view = View::iGet();
1630        $this->_view->addHeaders(array('Content-Type' => 'text/xml; charset=utf-8'));
1631        $this->_getPage('getopensearch');
1632        return $this;
1633    }
1634
1635
1636    /**
1637     * Renders the contents of the news relative to the specified id
1638     *
1639     * @author Pierre-Alain Mignot <contact@openwebreader.org>
1640     * @access protected
1641     * @return $this
1642     */
1643    protected function do_getNewContents()
1644    {
1645        if(!$this->_request->id)
1646            throw new Exception('An id is required', Exception::E_OWR_BAD_REQUEST);
1647
1648        $type = DAO::getType($this->_request->id);
1649        if('news' !== $type) throw new Exception('Invalid id', Exception::E_OWR_BAD_REQUEST);
1650
1651        if($this->_request->live)
1652        {
1653            try
1654            {
1655                $this->do_upNew(false, 'news');
1656            }
1657            catch(Exception $e)
1658            {
1659                switch($e->getCode())
1660                {
1661                    case Exception::E_OWR_NOTICE:
1662                    case Exception::E_OWR_WARNING:
1663                        Logs::iGet()->log($e->getContent(), $e->getCode());
1664                        break;
1665                    default:
1666                        throw new Exception($e->getContent(), $e->getCode());
1667                        break;
1668                }
1669            }
1670        }
1671
1672        $this->_getPage('new_contents', array('id'=>$this->_request->id, 'offset'=>$this->_request->offset));
1673        return $this;
1674    }
1675
1676    /**
1677     * Exports the feeds in OPML format
1678     *
1679     * @author Pierre-Alain Mignot <contact@openwebreader.org>
1680     * @access protected
1681     * @return $this
1682     */
1683    protected function do_getOPML()
1684    {
1685        isset($this->_view) || $this->_view = View::iGet();
1686        if(!empty($this->_request->dl))
1687        {
1688            $opml = $this->_getPage('opml', array('dateCreated'=>date("D, d M Y H:i:s T")), true);
1689            $this->_view->addHeaders(array(
1690                "Pragma" => "public",
1691                "Expires" => "0",
1692                "Cache-Control" => "must-revalidate, post-check=0, pre-check=0",
1693                "Content-Type" => "text/x-opml; charset=UTF-8",
1694                "Content-Transfer-Encoding" => "binary",
1695                "Content-Length" => mb_strlen($opml, 'UTF-8'),
1696                "Content-Disposition" => "attachment; Filename=\"OpenWebReader_Feedlist.opml\""
1697            ));
1698            $this->addToPage($opml);
1699        }
1700        else
1701        {
1702            $this->_view->addHeaders(array('Content-Type' => 'text/xml; charset=UTF-8'));
1703            $this->_getPage('opml', array('dateCreated'=>date("D, d M Y H:i:s T")));
1704        }
1705        return $this;
1706    }
1707
1708    /**
1709     * Do some database cleaning/maintenance
1710     * Must be an administrator
1711     *
1712     * @author Pierre-Alain Mignot <contact@openwebreader.org>
1713     * @access protected
1714     * @return $this
1715     */
1716    protected function do_maintenance()
1717    {
1718        if($this->_user->getRights() < User::LEVEL_ADMIN)
1719            throw new Exception("You don't have the rights to do that", Exception::E_OWR_UNAUTHORIZED);
1720
1721        // remove unused streams
1722        $query = '
1723    DELETE FROM objects
1724        WHERE id IN (
1725            SELECT id FROM streams
1726                WHERE id NOT IN (
1727                    SELECT rssid
1728                        FROM streams_relations
1729                        GROUP BY rssid
1730                )
1731        )';
1732        $this->_db->set($query);
1733
1734        $query = '
1735    DELETE FROM objects
1736        WHERE id NOT IN (
1737            SELECT id FROM streams)
1738        AND id NOT IN (
1739            SELECT id FROM streams_groups)
1740        AND id NOT IN (
1741            SELECT id FROM users)
1742        AND id NOT IN (
1743            SELECT id FROM news)
1744        AND id NOT IN (
1745            SELECT id FROM news_tags)';
1746        $this->_db->set($query);
1747
1748        $query = '
1749    DELETE FROM objects
1750        WHERE id IN (
1751            SELECT id FROM streams
1752                WHERE id NOT IN (
1753                    SELECT rssid
1754                        FROM streams_relations
1755                        GROUP BY rssid))';
1756
1757        $this->_db->set($query);
1758
1759        $query = '
1760    DELETE FROM news_contents
1761        WHERE id NOT IN (
1762            SELECT id
1763                FROM news)';
1764
1765        $this->_db->set($query);
1766
1767        $query = '
1768    OPTIMIZE TABLES
1769        news,
1770        news_tags,
1771        news_relations,
1772        news_relations_tags,
1773        objects,
1774        streams,
1775        streams_groups,
1776        streams_relations,
1777        streams_relations_name,
1778        sessions,
1779        news_contents,
1780        users,
1781        users_tokens';
1782        // PDO bug : need to set method to 'query' else it trows exception
1783        // http://bugs.php.net/bug.php?id=34499
1784        $this->_db->set($query, null, 'query');
1785
1786        // we check we have at least one stream
1787        // if there are none, we remove the crontab if not already empty
1788        $nb = DAO::getCachedDAO('streams')->count(array(), 'id');
1789        if((int) $nb->nb === 0)
1790        {
1791            isset($this->_cron) || $this->_cron = Cron::iGet();
1792            $this->_cron->manage('refreshstream');
1793            $this->_cron->manage('managefavicons');
1794            $this->_cron->manage('checkstreamsavailability');
1795        }
1796
1797        Cache::clear('', true);
1798
1799        return $this;
1800    }
1801
1802    /**
1803     * Tries to auth user against OpenID
1804     *
1805     * @author Pierre-Alain Mignot <contact@openwebreader.org>
1806     * @access protected
1807     * @return $this
1808     */
1809    protected function do_verifyOpenID()
1810    {// openid login
1811        class_exists('Auth_OpenID_FileStore', false) || include HOME_PATH.'libs/openID/Auth/OpenID/SReg.php';
1812        $store = new \Auth_OpenID_FileStore($this->_cfg->get('defaultTmpDir'));
1813        $consumer = new \Auth_OpenID_Consumer($store);
1814
1815        $result = $consumer->complete($this->_cfg->get('openIDReturn'));
1816        if($result->status != Auth_OpenID_SUCCESS)
1817        {
1818            unset($result);
1819            $this->redirect('logout');
1820        }
1821
1822        $this->do_login(false, $result->getDisplayIdentifier());
1823        unset($result);
1824
1825        return $this;
1826    }
1827
1828    /**
1829     * Renders results from a search coming from the search toolbar of your favorite browser
1830     *
1831     * @author Pierre-Alain Mignot <contact@openwebreader.org>
1832     * @access protected
1833     * @return $this
1834     */
1835    protected function do_openSearch()
1836    {
1837        if(empty($this->_request->oskeywords))
1838        {
1839            Logs::iGet()->log(Utilities::iGet()->_('Empty search, please enter at least one keyword'), Exception::E_OWR_BAD_REQUEST);
1840            $datas = array();
1841            $datas['sort'] = $this->_request->sort ?: '';
1842            $datas['dir'] = $this->_request->dir ?: '';
1843            $this->_getPage('index');
1844            return $this;
1845        }
1846
1847        $query = '
1848    SELECT id, MATCH(contents) AGAINST(?) AS result
1849        FROM news_contents
1850        WHERE id IN
1851            (';
1852
1853        if(empty($this->_request->id))
1854            $query .= 'SELECT newsid
1855                FROM news_relations
1856                WHERE uid='.$this->_user->getUid();
1857        else
1858        {
1859            $query .= 'SELECT nr.newsid
1860                FROM news_relations nr
1861                ';
1862            $type = DAO::getType($this->_request->id);
1863            switch($type)
1864            {
1865                case 'streams':
1866                    $query .= '
1867                WHERE nr.uid='.$this->_user->getUid().' AND rssid='.$this->_request->id;
1868                    break;
1869
1870                case 'streams_groups':
1871                    $query .= '
1872                JOIN streams_relations sr ON (nr.rssid=sr.rssid)
1873                WHERE nr.uid='.$this->_user->getUid().' AND sr.uid='.$this->_user->getUid().' AND gid='.$this->_request->id;
1874                    break;
1875
1876                case 'news_tags':
1877                    $query .= '
1878                JOIN news_relations_tags nrt ON (nrt.newsid=nr.newsid)
1879                WHERE nr.uid='.$this->_user->getUid().' AND nrt.uid='.$this->_user->getUid().' AND tid='.$this->_request->id;
1880                    break;
1881
1882                default:
1883                    throw new Exception('Invalid id', Exception::E_OWR_BAD_REQUEST);
1884                    break;
1885            }
1886        }
1887
1888        $query .= ')
1889            AND MATCH(contents) AGAINST(? IN BOOLEAN MODE)
1890        ORDER BY result DESC
1891        LIMIT 50'; // limit here, 50 is just enough.
1892
1893        $results = $this->_db->getAllP($query, 
1894                    new DBRequest(array($this->_request->oskeywords, $this->_request->oskeywords)));
1895        $datas = array('id' => array(), 'opensearch' => htmlspecialchars($this->_request->oskeywords, ENT_COMPAT, 'UTF-8', false));
1896        if($results->count())
1897        {
1898            while($results->next())
1899            {
1900                $results->id = (int)$results->id;
1901                $datas['id'][] = $results->id;
1902                $datas['searchResults'][$results->id] = $results->result;
1903            }
1904            unset($results);
1905            $datas['sort'] = $this->_request->sort ?: '';
1906            $datas['dir'] = $this->_request->dir ?: '';
1907            $this->_getPage('index', $datas);
1908        }
1909        else
1910        {
1911            Logs::iGet()->log(Utilities::iGet()->_('No results found. Try again by simplifying the request'), 204);
1912            $datas['sort'] = $this->_request->sort ?: '';
1913            $datas['dir'] = $this->_request->dir ?: '';
1914            $this->_getPage('index', $datas);
1915        }
1916        return $this;
1917    }
1918
1919    /**
1920     * Renders results from a search
1921     *
1922     * @author Pierre-Alain Mignot <contact@openwebreader.org>
1923     * @access protected
1924     * @return $this
1925     */
1926    protected function do_search()
1927    {
1928        if(empty($this->_request->keywords))
1929        {
1930            throw new Exception('Empty search, please enter at least one keyword', Exception::E_OWR_BAD_REQUEST);
1931            return $this;
1932        }
1933
1934        $query = '
1935    SELECT id, MATCH(contents) AGAINST(?) AS result
1936        FROM news_contents
1937        WHERE id IN
1938            (';
1939
1940        if(empty($this->_request->id))
1941            $query .= 'SELECT newsid
1942                FROM news_relations
1943                WHERE uid='.$this->_user->getUid();
1944        else
1945        {
1946            $query .= 'SELECT nr.newsid
1947                FROM news_relations nr
1948                ';
1949            $type = DAO::getType($this->_request->id);
1950            switch($type)
1951            {
1952                case 'streams':
1953                    $query .= '
1954                WHERE nr.uid='.$this->_user->getUid().' AND rssid='.$this->_request->id;
1955                    break;
1956
1957                case 'streams_groups':
1958                    $query .= '
1959                JOIN streams_relations sr ON (nr.rssid=sr.rssid)
1960                WHERE nr.uid='.$this->_user->getUid().' AND sr.uid='.$this->_user->getUid().' AND gid='.$this->_request->id;
1961                    break;
1962
1963                case 'news_tags':
1964                    $query .= '
1965                JOIN news_relations_tags nrt ON (nrt.newsid=nr.newsid)
1966                WHERE nr.uid='.$this->_user->getUid().' AND nrt.uid='.$this->_user->getUid().' AND tid='.$this->_request->id;
1967                    break;
1968
1969                default:
1970                    throw new Exception('Invalid id', Exception::E_OWR_BAD_REQUEST);
1971                    break;
1972            }
1973        }
1974
1975        $query .= ')
1976            AND MATCH(contents) AGAINST(? IN BOOLEAN MODE)
1977        ORDER BY result DESC
1978        LIMIT 50'; // limit here, 50 is just enough.
1979
1980        $results = $this->_db->getAllP($query, 
1981                    new DBRequest(array($this->_request->keywords, $this->_request->keywords)));
1982
1983        if($results->count())
1984        {
1985            $datas = array('search' => true);
1986            while($results->next())
1987            {
1988                $results->id = (int)$results->id;
1989                $datas['id'][] = $results->id;
1990                $datas['searchResults'][$results->id] = $results->result;
1991            }
1992            unset($results);
1993            $datas['offset'] = $this->_request->offset;
1994            $datas['sort'] = $this->_request->sort ?: '';
1995            $datas['dir'] = $this->_request->dir ?: '';
1996            $this->_getPage('news', $datas);
1997        }
1998        else
1999        {
2000            Logs::iGet()->log(Utilities::iGet()->_('No results found. Try again by simplifying the request'), 204);
2001        }
2002        return $this;
2003    }
2004
2005    /**
2006     * Renders tags from a new
2007     *
2008     * @author Pierre-Alain Mignot <contact@openwebreader.org>
2009     * @access protected
2010     * @return $this
2011     */
2012    protected function do_getTags()
2013    {
2014        if(empty($this->_request->id))
2015            throw new Exception('Missing id', Exception::E_OWR_BAD_REQUEST);
2016
2017        $this->_getPage('news_tags_contents', array('id' => $this->_request->id));
2018        return $this;
2019    }
2020
2021    /**
2022     * Requires a call to a logic from here
2023     */
2024
2025    /**
2026     * Changes the user interface language
2027     *
2028     * @author Pierre-Alain Mignot <contact@openwebreader.org>
2029     * @access protected
2030     * @return $this
2031     */
2032    protected function do_changeLang()
2033    {
2034        Logic::getCachedLogic('users')->changeLang($this->_request);
2035        $this->processResponse($this->_request->getResponse());
2036        return $this;
2037    }
2038
2039    /**
2040     * Returns a few statistics for current user
2041     *
2042     * @author Pierre-Alain Mignot <contact@openwebreader.org>
2043     * @access protected
2044     * @return $this
2045     */
2046    protected function do_stats()
2047    {
2048        Logic::getCachedLogic('users')->stat($this->_request);
2049        $this->processResponse($this->_request->getResponse());
2050        return $this;
2051    }
2052
2053    /**
2054     * Tries to auth user
2055     *
2056     * @author Pierre-Alain Mignot <contact@openwebreader.org>
2057     * @param boolean $auto automatic auth (gateway mode)
2058     * @param string $openid OpenID authentication, optionnal
2059     * @access protected
2060     * @return $this
2061     */
2062    protected function do_login($auto=false, $openid=null)
2063    {
2064        $exists = DAO::getCachedDAO('users')->get(null, 'id', null, null, 1);
2065
2066        if(!$exists)
2067        {
2068            $this->_user->reset();
2069            $this->_getPage('edituser', array('id'=>0));
2070            return $this;
2071        }
2072        unset($exists);
2073
2074        if(!$auto && empty($_POST) && !isset($openid) && empty($this->_request->identifier))
2075        {
2076            $datas = array();
2077            if(isset($this->_request->timeout)) $datas['error'] = Utilities::iGet()->_('Session timeout');
2078            if(isset($this->_request->back)) $datas['back'] = $this->_request->back;
2079            $this->_user->reset();
2080            $this->_getPage('login', $datas);
2081            return $this;
2082        }
2083
2084        $uid = 0;
2085
2086        if($auto)
2087        {
2088            if(!$this->_user->checkToken(true, $this->_request->uid, $this->_request->tlogin, $this->_request->key, $this->_request->do))
2089            {
2090                $this->_user->reset();
2091                $this->_getPage('login', array('error' => Utilities::iGet()->_('Invalid token')));
2092                return $this;
2093            }
2094        }
2095        elseif($openid)
2096        {
2097            $token = $this->_user->getToken();
2098            // check HTTP User-Agent and token
2099            if(($this->_user->getAgent() !== md5($token.
2100            (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : 'X'))) ||
2101            $this->_request->token !== $token)
2102            {
2103                $this->_user->reset();
2104                $this->_getPage('login', array('error' => Utilities::iGet()->_('Invalid token')));
2105                return $this;
2106            }
2107            $this->_user->openIdAuth($openid);
2108        }
2109        elseif(!empty($this->_request->identifier))
2110        {
2111            $this->_user->checkToken();
2112            $login = $this->_request->identifier;
2113            if(0 !== mb_strpos($login, 'http://', 0, 'UTF-8'))
2114                $login = 'http://'.$login;
2115            if('/' !== mb_substr($login, -1, 1, 'UTF-8'))
2116                    $login .= '/'; 
2117
2118            class_exists('Auth_OpenID_FileStore', false) || include HOME_PATH.'libs/openID/Auth/OpenID/SReg.php';
2119            $store = new \Auth_OpenID_FileStore($this->_cfg->get('defaultTmpDir'));
2120            $consumer = new \Auth_OpenID_Consumer($store);
2121            $authRequest = $consumer->begin($login);
2122            $sreg = \Auth_OpenID_SRegRequest::build(array('nickname'), array('fullname', 'email'));
2123            $authRequest->addExtension($sreg);
2124            $redirectURL = $authRequest->redirectURL($this->_cfg->get('openIDUrl'), $this->_cfg->get('openIDReturn').'&token='.$this->_user->getToken().
2125                (!empty($this->_request->back) ? '&back='.urlencode($this->_request->back) : ''));
2126            if($redirectURL != null)
2127            {
2128                header('Location: '.$redirectURL); // Redirection vers l'OP
2129                exit;
2130            }
2131
2132            throw new Exception('Internal error while redirecting to your OP');
2133        }
2134        else
2135        {
2136            $isLogged = $this->_user->isLogged();
2137            if(!$this->_user->checkToken())
2138            {
2139                $this->_user->reset();
2140                $this->_getPage('login', array('error' => Utilities::iGet()->_('Invalid token')));
2141                return $this;
2142            }
2143
2144            if(empty($this->_request->login) || empty($this->_request->passwd))
2145            {
2146                $this->_user->reset();
2147                $this->_getPage('login', array('error'=> Utilities::iGet()->_('Please fill all the fields.')));
2148                return $this;
2149            }
2150            elseif(mb_strlen($this->_request->login, 'UTF-8') > 55)
2151            {
2152                $this->_user->reset();
2153                $this->_getPage('login', array('error' => Utilities::iGet()->_('Invalid login or password. Please try again.')));
2154                return $this;
2155            }
2156
2157            $this->_user->auth($this->_request->login, md5($this->_request->login.$this->_request->passwd));
2158
2159            unset($this->_request->passwd);
2160        }
2161
2162        $uid = $this->_user->getUid();
2163
2164        if(!$uid)
2165        {
2166            $this->_user->reset();
2167            $this->_getPage('login', array('error' => Utilities::iGet()->_('Invalid login or password. Please try again.')));
2168            return $this;
2169        }
2170
2171        if(!$auto)
2172        { // we set the session only if it is NOT a token login
2173        // because actions for this type of login is restricted and will always need
2174        // token and key passed by get or post
2175        // Also, we do not regenerate session id for case that the user already is logged
2176        // and is trying to log in again (for opensearch by example)
2177            if(!isset($isLogged) || !$isLogged)
2178            {
2179                $this->_sh->regenerateSessionId(true);
2180                $this->_user->reg(); // need to link back $_SESSION['User'] and the current user
2181                $this->_user->regenerateToken();
2182            }
2183            $this->redirect(isset($this->_request->back) ? $this->_request->back : null);
2184        }
2185        return $this;
2186    }
2187
2188    /**
2189     * Logout the user
2190     *
2191     * @author Pierre-Alain Mignot <contact@openwebreader.org>
2192     * @param boolean $redirect redirects the user to the login page
2193     * @access protected
2194     * @return $this
2195     */
2196    protected function do_logout($redirect=true)
2197    {
2198        $this->_user->reset();
2199        $_SESSION = array();
2200
2201        $session = session_name();
2202        $sessid = session_id();
2203
2204        foreach(array('uid', 'tlogin', 'key', $session) as $name)
2205        {
2206            if(isset($_COOKIE[$name])) 
2207            {
2208                setcookie($name, '', $this->_request->begintime - 42000, $this->_cfg->get('path'), $this->_cfg->get('url'), $this->_cfg->get('httpsecure'), true);
2209            }
2210        }
2211
2212        if($sessid) session_destroy();
2213
2214        unset($sessid);
2215        if($redirect)
2216            $this->redirect('login');
2217        return $this;
2218    }
2219
2220    /**
2221     * Moves a stream into another category
2222     *
2223     * @author Pierre-Alain Mignot <contact@openwebreader.org>
2224     * @access protected
2225     * @return $this
2226     */
2227    protected function do_move()
2228    {
2229        Logic::getCachedLogic('streams')->move($this->_request);
2230        $this->processResponse($this->_request->getResponse());
2231        return $this;
2232    }
2233
2234    /**
2235     * Deletes object(s)
2236     * If no id is specified, we deletes everything related to the user but not the user himself
2237     *
2238     * @author Pierre-Alain Mignot <contact@openwebreader.org>
2239     * @access protected
2240     * @return $this
2241     */
2242    protected function do_delete()
2243    {
2244        if(!$this->_request->id)
2245        {
2246            Logic::getCachedLogic('users')->deleteRelated($this->_request);
2247            if(!$this->processResponse($this->_request->getResponse())) return $this;
2248        }
2249        else
2250        {
2251            $type = DAO::getType($this->_request->id);
2252
2253            switch($type)
2254            {
2255                case 'users':
2256                    Logic::getCachedLogic('users')->delete($this->_request);
2257                    if(!$this->processResponse($this->_request->getResponse())) return $this;
2258                    $escape = true;
2259                    break;
2260
2261                case 'news':
2262                case 'streams':
2263                case 'streams_groups':
2264                case 'news_tags':
2265                    Logic::getCachedLogic($type)->delete($this->_request);
2266                    if(!$this->processResponse($this->_request->getResponse())) return $this;
2267                    break;
2268
2269                default:
2270                    throw new Exception('Invalid id', Exception::E_OWR_BAD_REQUEST);
2271                    break;
2272            }
2273        }
2274
2275        if(!isset($escape) && (!$this->_request->currentid || $this->_request->id === $this->_request->currentid))
2276        {
2277            $this->_getPage('news', array('id' => 0, 'sort' => $this->_request->sort ?: '', 'dir' => $this->_request->dir ?: ''));
2278        }
2279
2280        return $this;
2281    }
2282
2283    /**
2284     * Adds a stream and redirects the user to the index
2285     * Used by externals call
2286     *
2287     * @author Pierre-Alain Mignot <contact@openwebreader.org>
2288     * @access protected
2289     * @return $this
2290     */
2291    protected function do_add()
2292    {
2293        $this->do_editstream();
2294
2295        $this->redirect();
2296        return $this;
2297    }
2298
2299    /**
2300     * Adds a stream
2301     *
2302     * @author Pierre-Alain Mignot <contact@openwebreader.org>
2303     * @param string $url the url of the stream, optionnal
2304     * @param boolean $escapeNews must-we insert the parsed news ?
2305     * @access protected
2306     * @return $this
2307     */
2308    protected function do_editStream($url = null, $escapeNews = false)
2309    {
2310        $this->_request->url = $url ?: $this->_request->url;
2311        $this->_request->escapeNews = $escapeNews;
2312        $this->_request->escape = isset($url);
2313
2314        Logic::getCachedLogic('streams')->edit($this->_request);
2315        $this->processResponse($this->_request->getResponse());
2316
2317        return $this;
2318    }
2319
2320    /**
2321     * Adds/Edits a category
2322     *
2323     * @author Pierre-Alain Mignot <contact@openwebreader.org>
2324     * @param string $name the name of the category, optionnal
2325     * @access protected
2326     * @return $this
2327     */
2328    protected function do_editStreamGroup($name = null)
2329    {
2330        $this->_request->name = $name ?: $this->_request->name;
2331        $this->_request->new = false;
2332        $this->_request->escape = isset($name);
2333
2334        Logic::getCachedLogic('streams_groups')->edit($this->_request);
2335        if(!$this->processResponse($this->_request->getResponse())) return $this;
2336
2337        if(!isset($name))
2338        {
2339            $contents = array('id' => $this->_request->id);
2340            if($this->_request->new)
2341                $contents['menu'] = $this->_getPage('menu_part_category', array('gid'=>$this->_request->id, 'name'=>$this->_request->name), true);
2342            $this->_request->page = array();
2343            $this->addToPage($contents);
2344        }
2345
2346        return $this;
2347    }
2348
2349    /**
2350     * Adds streams from OPML input
2351     * If an url is passed, we'll try to get the remote opml file
2352     * else it is an uploaded file
2353     *
2354     * @author Pierre-Alain Mignot <contact@openwebreader.org>
2355     * @param $url the url of the OPML file, optional
2356     * @access protected
2357     * @return $this
2358     */
2359    protected function do_editOPML($url = null)
2360    {
2361        $this->_isFrame = true;
2362        $this->_request->url = $url ?: $this->_request->url;
2363        $this->_request->escape = isset($url);
2364
2365        Logic::getCachedLogic('streams')->editOPML($this->_request);
2366        if(!$this->processResponse($this->_request->getResponse())) return $this;
2367
2368        return $this;
2369    }
2370
2371    /**
2372     * Renders REST auth tokens
2373     * We'll generate it if it does not exists
2374     *
2375     * @author Pierre-Alain Mignot <contact@openwebreader.org>
2376     * @access protected
2377     * @return $this
2378     */
2379    protected function do_regenerateRESTAuthToken()
2380    {
2381        $tokensObj = DAO::getCachedDAO('users_tokens')->get('restauth', 'token AS tlogin, token_key AS tlogin_key');
2382        if(!$tokensObj)
2383        {
2384            $tokens = $this->_user->regenerateActionToken('restauth');
2385        }
2386        else $tokens = (array)$tokensObj;
2387
2388        unset($tokensObj);
2389        $return = 'uid:'.$this->_user->getUid().';tlogin:'.$tokens['tlogin'].';key:'.$tokens['tlogin_key'];
2390        unset($tokens);
2391        $this->addToPage($return);
2392        return $this;
2393    }
2394
2395    /**
2396     * Renders the stream gateway token
2397     * We'll generate it if it does not exists
2398     *
2399     * @author Pierre-Alain Mignot <contact@openwebreader.org>
2400     * @access protected
2401     * @return $this
2402     */
2403    protected function do_regenerateRSSToken()
2404    {
2405        $tokensObj = DAO::getCachedDAO('users_tokens')->get($this->_request->do, 'token AS tlogin, token_key AS tlogin_key');
2406        if(!$tokensObj)
2407        {
2408            $tokens = $this->_user->regenerateActionToken('getrss');
2409        }
2410        else $tokens = (array)$tokensObj;
2411
2412        unset($tokensObj);
2413       
2414        $url = $this->_cfg->get('surl').'?do=getrss&uid='.$this->_user->getUid().'&tlogin='.$tokens['tlogin'].'&key='.$tokens['tlogin_key'];
2415        unset($tokens);
2416        $this->addToPage($url);
2417        return $this;
2418    }
2419
2420    /**
2421     * Renders an OPML gateway token
2422     * We'll generate it if it does not exists
2423     *
2424     * @author Pierre-Alain Mignot <contact@openwebreader.org>
2425     * @access protected
2426     * @return $this
2427     */
2428    protected function do_regenerateOPMLToken()
2429    {
2430        $tokensObj = DAO::getCachedDAO('users_tokens')->get($this->_request->do, 'token AS tlogin, token_key AS tlogin_key');
2431        if(!$tokensObj)
2432        {
2433            $tokens = $this->_user->regenerateActionToken('getopml');
2434        }
2435        else $tokens = (array)$tokensObj;
2436       
2437        unset($tokensObj);
2438       
2439        $url = $this->_cfg->get('surl').'?do=getopml&uid='.$this->_user->getUid().'&tlogin='.$tokens['tlogin'].'&key='.$tokens['tlogin_key'];
2440        unset($tokens); 
2441        $this->addToPage($url);
2442        return $this;
2443    }
2444
2445    /**
2446     * Tries to refresh stream(s)
2447     *
2448     * @author Pierre-Alain Mignot <contact@openwebreader.org>
2449     * @access protected
2450     * @return $this
2451     */
2452    protected function do_refreshStream()
2453    {
2454        Logic::getCachedLogic('streams')->refresh($this->_request);
2455        $this->processResponse($this->_request->getResponse());
2456
2457        return $this;
2458    }
2459
2460    /**
2461     * Update new(s) status (read/unread)
2462     *
2463     * @author Pierre-Alain Mignot <contact@openwebreader.org>
2464     * @access protected
2465     * @return $this
2466     */
2467    protected function do_upNew()
2468    {
2469        Logic::getCachedLogic('news')->update($this->_request);
2470        $this->processResponse($this->_request->getResponse());
2471
2472        return $this;
2473    }
2474
2475    /**
2476     * Delete all news relations between the user and a specified stream/category/tag
2477     *
2478     * @author Pierre-Alain Mignot <contact@openwebreader.org>
2479     * @access protected
2480     * @return $this
2481     */
2482    protected function do_clearStream()
2483    {
2484        Logic::getCachedLogic('streams')->clear($this->_request);
2485        $this->processResponse($this->_request->getResponse());
2486
2487        return $this;
2488    }
2489
2490    /**
2491     * Adds/Edits a user
2492     * Must be an administrator to add or edit another user
2493     * If no users are detected, we set the user automaticly as an administrator
2494     *
2495     * @author Pierre-Alain Mignot <contact@openwebreader.org>
2496     * @access protected
2497     * @return $this
2498     */
2499    protected function do_editUser()
2500    {
2501        Logic::getCachedLogic('users')->edit($this->_request);
2502        $this->processResponse($this->_request->getResponse());
2503
2504        return $this;
2505    }
2506
2507    /**
2508     * Adds/Edits a tag
2509     *
2510     * @author Pierre-Alain Mignot <contact@openwebreader.org>
2511     * @access protected
2512     * @return $this
2513     */
2514    protected function do_editTag()
2515    {
2516        Logic::getCachedLogic('news_tags')->edit($this->_request);
2517        $this->processResponse($this->_request->getResponse());
2518
2519        return $this;
2520    }
2521
2522    /**
2523     * Adds/removes tag(s) to new(s)
2524     *
2525     * @author Pierre-Alain Mignot <contact@openwebreader.org>
2526     * @access protected
2527     * @return $this
2528     */
2529    protected function do_editTagsRelations()
2530    {
2531        Logic::getCachedLogic('news_tags')->editRelations($this->_request);
2532        $this->processResponse($this->_request->getResponse());
2533
2534        return $this;
2535    }
2536
2537    /**
2538     * Renames a stream/category/tag
2539     *
2540     * @author Pierre-Alain Mignot <contact@openwebreader.org>
2541     * @access protected
2542     * @return $this
2543     */
2544    protected function do_rename()
2545    {
2546        if(!$this->_request->id)
2547        {
2548            $this->processResponse(new LogicResponse(array(
2549                'do'        => 'error',
2550                'error'     => 'Invalid id',
2551                'status'    => Exception::E_OWR_BAD_REQUEST
2552            )));
2553            return $this;
2554        }
2555
2556        $type = DAO::getType($this->_request->id);
2557        $obj = null;
2558        switch($type)
2559        {
2560            case 'streams':
2561            case 'streams_groups':
2562            case 'news_tags':
2563                Logic::getCachedLogic($type)->rename($this->_request);
2564                if(!$this->processResponse($this->_request->getResponse())) return $this;
2565                break;
2566
2567            default:
2568                $this->processResponse(new LogicResponse(array(
2569                    'do'        => 'error',
2570                    'error'     => 'Invalid id',
2571                    'status'    => Exception::E_OWR_BAD_REQUEST
2572                )));
2573                break;
2574        }
2575
2576        return $this;
2577    }
2578}
Note: See TracBrowser for help on using the repository browser.