]> git.immae.eu Git - github/wallabag/wallabag.git/commitdiff
import without cron
authorMaryana Rozhankivska <mariroz@mr.lviv.ua>
Wed, 2 Apr 2014 19:33:06 +0000 (22:33 +0300)
committerMaryana Rozhankivska <mariroz@mr.lviv.ua>
Wed, 2 Apr 2014 19:33:06 +0000 (22:33 +0300)
1  2 
inc/poche/Database.class.php
inc/poche/Poche.class.php
themes/baggy/config.twig
themes/baggy/css/main.css
themes/baggy/layout.twig
themes/default/home.twig

index 9adb16440dfc0acaf5b4b9ee81b700c8d4bc9e42,2257f28177e8d4abed9fe743142f3a9e82b05537..6244df887f1e3b590596319ad40ea9c68a593ac5
@@@ -18,7 -18,7 +18,7 @@@ class Database 
        'default' => 'ORDER BY entries.id'
      );
  
 -    function __construct() 
 +    function __construct()
      {
          switch (STORAGE) {
              case 'sqlite':
                  break;
              case 'mysql':
                  $db_path = 'mysql:host=' . STORAGE_SERVER . ';dbname=' . STORAGE_DB;
 -                $this->handle = new PDO($db_path, STORAGE_USER, STORAGE_PASSWORD); 
 +                $this->handle = new PDO($db_path, STORAGE_USER, STORAGE_PASSWORD);
                  break;
              case 'postgres':
                  $db_path = 'pgsql:host=' . STORAGE_SERVER . ';dbname=' . STORAGE_DB;
 -                $this->handle = new PDO($db_path, STORAGE_USER, STORAGE_PASSWORD); 
 +                $this->handle = new PDO($db_path, STORAGE_USER, STORAGE_PASSWORD);
                  break;
          }
  
@@@ -51,7 -51,7 +51,7 @@@
          }
          $hasAdmin = count($query->fetchAll());
  
 -        if ($hasAdmin == 0) 
 +        if ($hasAdmin == 0)
              return false;
  
          return true;
          $sql = 'INSERT INTO users_config ( user_id, name, value ) VALUES (?, ?, ?)';
          $params = array($id_user, 'language', LANG);
          $query = $this->executeQuery($sql, $params);
 -        
 +
          $sql = 'INSERT INTO users_config ( user_id, name, value ) VALUES (?, ?, ?)';
          $params = array($id_user, 'theme', DEFAULT_THEME);
          $query = $this->executeQuery($sql, $params);
          $query = $this->executeQuery($sql, array($id));
          $result = $query->fetchAll();
          $user_config = array();
 -        
 +
          foreach ($result as $key => $value) {
              $user_config[$value['name']] = $value['value'];
          }
          $params_update = array($password, $userId);
          $query = $this->executeQuery($sql_update, $params_update);
      }
 -    
 +
      public function updateUserConfig($userId, $key, $value) {
          $config = $this->getConfigUser($userId);
 -        
 +
          if (! isset($config[$key])) {
              $sql = "INSERT INTO users_config (value, user_id, name) VALUES (?, ?, ?)";
          }
          return $entries;
      }
  
 +    public function retrieveUnfetchedEntriesCount($user_id) {
 +      $sql        = "SELECT count(*) FROM entries WHERE (content = '' OR content IS NULL) AND user_id=?";
 +      $query      = $this->executeQuery($sql, array($user_id));
 +      list($count) = $query->fetch();
 +
 +      return $count;
 +    }
 +
      public function retrieveAll($user_id) {
 -        $sql        = "SELECT * FROM entries WHERE content <> '' AND user_id=? ORDER BY id";
 +        $sql        = "SELECT * FROM entries WHERE user_id=? ORDER BY id";
          $query      = $this->executeQuery($sql, array($user_id));
          $entries    = $query->fetchAll();
  
  
      public function retrieveOneByURL($url, $user_id) {
          $entry  = NULL;
 -        $sql    = "SELECT * FROM entries WHERE content <> '' AND url=? AND user_id=?";
 +        $sql    = "SELECT * FROM entries WHERE url=? AND user_id=?";
          $params = array($url, $user_id);
          $query  = $this->executeQuery($sql, $params);
          $entry  = $query->fetchAll();
      public function getEntriesByView($view, $user_id, $limit = '', $tag_id = 0) {
          switch ($view) {
              case 'archive':
 -                $sql    = "SELECT * FROM entries WHERE content <> '' AND user_id=? AND is_read=? ";
 +                $sql    = "SELECT * FROM entries WHERE user_id=? AND is_read=? ";
                  $params = array($user_id, 1);
                  break;
              case 'fav' :
 -                $sql    = "SELECT * FROM entries WHERE content <> '' AND user_id=? AND is_fav=? ";
 +                $sql    = "SELECT * FROM entries WHERE user_id=? AND is_fav=? ";
                  $params = array($user_id, 1);
                  break;
              case 'tag' :
                  $sql    = "SELECT entries.* FROM entries
                  LEFT JOIN tags_entries ON tags_entries.entry_id=entries.id
 -                WHERE entries.content <> '' AND
 -                entries.user_id=? AND tags_entries.tag_id = ? ";
 +                WHERE entries.user_id=? AND tags_entries.tag_id = ? ";
                  $params = array($user_id, $tag_id);
                  break;
              default:
 -                $sql    = "SELECT * FROM entries WHERE content <> '' AND user_id=? AND is_read=? ";
 +                $sql    = "SELECT * FROM entries WHERE user_id=? AND is_read=? ";
                  $params = array($user_id, 0);
                  break;
          }
      public function getEntriesByViewCount($view, $user_id, $tag_id = 0) {
          switch ($view) {
              case 'archive':
 -                    $sql    = "SELECT count(*) FROM entries WHERE content <> '' AND user_id=? AND is_read=? ";
 +                    $sql    = "SELECT count(*) FROM entries WHERE user_id=? AND is_read=? ";
                  $params = array($user_id, 1);
                  break;
              case 'fav' :
 -                    $sql    = "SELECT count(*) FROM entries WHERE content <> '' AND user_id=? AND is_fav=? ";
 +                    $sql    = "SELECT count(*) FROM entries WHERE user_id=? AND is_fav=? ";
                  $params = array($user_id, 1);
                  break;
              case 'tag' :
                  $sql    = "SELECT count(*) FROM entries
                      LEFT JOIN tags_entries ON tags_entries.entry_id=entries.id
 -                    WHERE entries.content <> '' AND
 -                    entries.user_id=? AND tags_entries.tag_id = ? ";
 +                    WHERE entries.user_id=? AND tags_entries.tag_id = ? ";
                  $params = array($user_id, $tag_id);
                  break;
              default:
 -                $sql    = "SELECT count(*) FROM entries WHERE content <> '' AND user_id=? AND is_read=? ";
 +                $sql    = "SELECT count(*) FROM entries WHERE user_id=? AND is_read=? ";
                  $params = array($user_id, 0);
                  break;
          }
          return $query;
      }
  
 -    public function add($url, $title, $content, $user_id) {
 -        $sql_action = 'INSERT INTO entries ( url, title, content, user_id ) VALUES (?, ?, ?, ?)';
 -        $params_action = array($url, $title, $content, $user_id);
 -        $query = $this->executeQuery($sql_action, $params_action);
 -        return $query;
 +    /**
 +     *
 +     * @param string $url
 +     * @param string $title
 +     * @param string $content
 +     * @param integer $user_id
 +     * @return integer $id of inserted record
 +     */
 +    public function add($url, $title, $content, $user_id, $isFavorite=0, $isRead=0) {
 +        $sql_action = 'INSERT INTO entries ( url, title, content, user_id, is_fav, is_read ) VALUES (?, ?, ?, ?, ?, ?)';
 +        $params_action = array($url, $title, $content, $user_id, $isFavorite, $isRead);
 +        if ( !$this->executeQuery($sql_action, $params_action) ) {
 +          $id = null;
 +        }
 +        else {
 +          $id = intval($this->getLastId( (STORAGE == 'postgres') ? 'users_id_seq' : '' ));
 +        }
 +        return $id;
      }
  
      public function deleteById($id, $user_id) {
      public function getLastId($column = '') {
          return $this->getHandle()->lastInsertId($column);
      }
-       public function search($term){
-               $search = '%'.$term.'%';
-               $query = $this->getHandle()->prepare("SELECT * FROM entries WHERE content LIKE ? OR title LIKE ? OR url LIKE ?"); //searches in content, title and URL
-               $query->execute(array($search,$search,$search));
-               $entries = $query->fetchAll();
-               return $entries;
-       }
+       
 -   public function search($term,$id,$limit = ''){
 -      $search = '%'.$term.'%';
 -      $sql_action     = ("SELECT * FROM entries WHERE user_id=? AND (content LIKE ? OR title LIKE ? OR url LIKE ?) "); //searches in content, title and URL
 -      $sql_action .= $this->getEntriesOrder().' ' . $limit;
 -      $params_action  = array($id,$search,$search,$search);
 -      $query          = $this->executeQuery($sql_action, $params_action);
 -      return $query->fetchAll();
 -      }
++    public function search($term, $user_id, $limit = '') {
++        $search = '%'.$term.'%';
++        $sql_action = "SELECT * FROM entries WHERE user_id=? AND (content LIKE ? OR title LIKE ? OR url LIKE ?) "; //searches in content, title and URL
++        $sql_action .= $this->getEntriesOrder().' ' . $limit;
++        $params_action = array($user_id, $search, $search, $search);
++        $query = $this->executeQuery($sql_action, $params_action);
++        return $query->fetchAll();
++      }
  
      public function retrieveAllTags($user_id, $term = null) {
          $sql = "SELECT DISTINCT tags.*, count(entries.id) AS entriescount FROM tags
            LEFT JOIN tags_entries ON tags_entries.tag_id=tags.id
            LEFT JOIN entries ON tags_entries.entry_id=entries.id
 -          WHERE entries.content <> '' AND entries.user_id=?
 +          WHERE entries.user_id=?
              ". (($term) ? "AND lower(tags.value) LIKE ?" : '') ."
            GROUP BY tags.id, tags.value
            ORDER BY tags.value";
          $sql    = "SELECT DISTINCT tags.* FROM tags
            LEFT JOIN tags_entries ON tags_entries.tag_id=tags.id
            LEFT JOIN entries ON tags_entries.entry_id=entries.id
 -          WHERE entries.content <> '' AND tags.id=? AND entries.user_id=?";
 +          WHERE tags.id=? AND entries.user_id=?";
          $params = array(intval($id), $user_id);
          $query  = $this->executeQuery($sql, $params);
          $tag  = $query->fetchAll();
      }
  
      public function retrieveEntriesByTag($tag_id, $user_id) {
 -        $sql = 
 +        $sql =
              "SELECT entries.* FROM entries
              LEFT JOIN tags_entries ON tags_entries.entry_id=entries.id
 -            WHERE entries.content <> '' AND
 -            tags_entries.tag_id = ? AND entries.user_id=?";
 +            WHERE tags_entries.tag_id = ? AND entries.user_id=?";
          $query = $this->executeQuery($sql, array($tag_id, $user_id));
          $entries = $query->fetchAll();
  
      }
  
      public function retrieveTagsByEntry($entry_id) {
 -        $sql = 
 +        $sql =
              "SELECT tags.* FROM tags
              LEFT JOIN tags_entries ON tags_entries.tag_id=tags.id
              WHERE tags_entries.entry_id = ?";
index d1b0c945b7f780396019b60f40be4cd2a8feb397,42a2dd9a2fa73a76de1aa9d576a37a65abe8cf34..ee3b2ac265b49b802bf6f27a23e372d81ac46fd0
@@@ -18,7 -18,7 +18,7 @@@ class Poch
      public $tpl;
      public $messages;
      public $pagination;
 -    
 +
      private $currentTheme = '';
      private $currentLanguage = '';
      private $notInstalledMessage = array();
          if ($this->configFileIsAvailable()) {
              $this->init();
          }
 -        
 +
          if ($this->themeIsInstalled()) {
              $this->initTpl();
          }
 -        
 +
          if ($this->systemIsInstalled()) {
              $this->store = new Database();
              $this->messages = new Messages();
@@@ -57,8 -57,8 +57,8 @@@
              $this->store->checkTags();
          }
      }
 -    
 -    private function init() 
 +
 +    private function init()
      {
          Tools::initPhp();
  
          $language = $this->user->getConfigValue('language');
          putenv('LC_ALL=' . $language);
          setlocale(LC_ALL, $language);
 -        bindtextdomain($language, LOCALE); 
 -        textdomain($language); 
 +        bindtextdomain($language, LOCALE);
 +        textdomain($language);
  
          # Pagination
          $this->pagination = new Paginator($this->user->getConfigValue('pager'), 'p');
 -        
 +
          # Set up theme
          $themeDirectory = $this->user->getConfigValue('theme');
 -        
 +
          if ($themeDirectory === false) {
              $themeDirectory = DEFAULT_THEME;
          }
 -        
 +
          $this->currentTheme = $themeDirectory;
  
          # Set up language
          $languageDirectory = $this->user->getConfigValue('language');
 -        
 +
          if ($languageDirectory === false) {
              $languageDirectory = DEFAULT_THEME;
          }
 -        
 +
          $this->currentLanguage = $languageDirectory;
      }
  
  
          return true;
      }
 -    
 +
      public function themeIsInstalled() {
          $passTheme = TRUE;
          # Twig is an absolute requirement for Poche to function. Abort immediately if the Composer installer hasn't been run yet
              self::$canRenderTemplates = false;
  
              $passTheme = FALSE;
 -        } 
 -        
 +        }
 +
          # Check if the selected theme and its requirements are present
          $theme = $this->getTheme();
  
          if ($theme != '' && ! is_dir(THEME . '/' . $theme)) {
              $this->notInstalledMessage[] = 'The currently selected theme (' . $theme . ') does not seem to be properly installed (Missing directory: ' . THEME . '/' . $theme . ')';
 -            
 +
              self::$canRenderTemplates = false;
 -            
 +
              $passTheme = FALSE;
          }
 -        
 +
          $themeInfo = $this->getThemeInfo($theme);
          if (isset($themeInfo['requirements']) && is_array($themeInfo['requirements'])) {
              foreach ($themeInfo['requirements'] as $requiredTheme) {
                  if (! is_dir(THEME . '/' . $requiredTheme)) {
                      $this->notInstalledMessage[] = 'The required "' . $requiredTheme . '" theme is missing for the current theme (' . $theme . ')';
 -                
 +
                      self::$canRenderTemplates = false;
 -                
 +
                      $passTheme = FALSE;
                  }
              }
              return FALSE;
          }
  
 -        
 +
          return true;
      }
 -    
 +
      /**
       * all checks before installation.
       * @todo move HTML to template
 -     * @return boolean 
 +     * @return boolean
       */
      public function systemIsInstalled()
      {
          $msg = TRUE;
 -        
 +
          $configSalt = defined('SALT') ? constant('SALT') : '';
 -        
 +
          if (empty($configSalt)) {
              $this->notInstalledMessage[] = 'You have not yet filled in the SALT value in the config.inc.php file.';
              $msg = FALSE;
  
          return true;
      }
 -    
 +
      public function getNotInstalledMessage() {
          return $this->notInstalledMessage;
      }
      {
          $loaderChain = new Twig_Loader_Chain();
          $theme = $this->getTheme();
 -       
 +
          # add the current theme as first to the loader chain so Twig will look there first for overridden template files
          try {
              $loaderChain->addLoader(new Twig_Loader_Filesystem(THEME . '/' . $theme));
              # @todo isInstalled() should catch this, inject Twig later
              die('The currently selected theme (' . $theme . ') does not seem to be properly installed (' . THEME . '/' . $theme .' is missing)');
          }
 -        
 +
          # add all required themes to the loader chain
          $themeInfo = $this->getThemeInfo($theme);
          if (isset($themeInfo['requirements']) && is_array($themeInfo['requirements'])) {
                  }
              }
          }
 -        
 +
          if (DEBUG_POCHE) {
              $twigParams = array();
          } else {
              $twigParams = array('cache' => CACHE);
          }
 -        
 +
          $this->tpl = new Twig_Environment($loaderChain, $twigParams);
          $this->tpl->addExtension(new Twig_Extensions_Extension_I18n());
 -        
 +
          # filter to display domain name of an url
          $filter = new Twig_SimpleFilter('getDomain', 'Tools::getDomain');
          $this->tpl->addFilter($filter);
              'poche_url' => Tools::getPocheUrl()
          ));
          if (isset($_GET['install'])) {
 -            if (($_POST['password'] == $_POST['password_repeat']) 
 +            if (($_POST['password'] == $_POST['password_repeat'])
                  && $_POST['password'] != "" && $_POST['login'] != "") {
                  # let's rock, install poche baby !
                  if ($this->store->install($_POST['login'], Tools::encodeString($_POST['password'] . $_POST['login'])))
          }
          exit();
      }
 -    
 +
      public function getTheme() {
          return $this->currentTheme;
      }
          if (is_file($themeIniFile) && is_readable($themeIniFile)) {
              $themeInfo = parse_ini_file($themeIniFile);
          }
 -        
 +
          if ($themeInfo === false) {
              $themeInfo = array();
          }
  
          return $themeInfo;
      }
 -    
 +
      public function getInstalledThemes() {
          $handle = opendir(THEME);
          $themes = array();
      public function getInstalledLanguages() {
          $handle = opendir(LOCALE);
          $languages = array();
 -        
 +
          while (($language = readdir($handle)) !== false) {
              # Languages are stored in a directory, so all directory names are languages
              # @todo move language installation data to database
              if (! is_dir(LOCALE . '/' . $language) || in_array($language, array('..', '.', 'tools'))) {
                  continue;
              }
 -            
 +
              $current = false;
 -            
 +
              if ($language === $this->getLanguage()) {
                  $current = true;
              }
 -            
 +
              $languages[] = array('name' => (isset($this->language_names[$language]) ? $this->language_names[$language] : $language), 'value' => $language, 'current' => $current);
          }
 -        
 +
          return $languages;
      }
  
      public function getDefaultConfig()
 -    {   
 +    {
          return array(
              'pager' => PAGINATION,
              'language' => LANG,
                      $body = '';
                  }
  
 -                //search for possible duplicate if not in import mode
 +                //search for possible duplicate
                  $duplicate = NULL;
                  if (!$import) {
 -                    $duplicate = $this->store->retrieveOneByURL($url->getUrl(), $this->user->getId());
 +                  $duplicate = $this->store->retrieveOneByURL($url->getUrl(), $this->user->getId());
                  }
  
 -                if ($this->store->add($url->getUrl(), $title, $body, $this->user->getId())) {
 +                $last_id = $this->store->add($url->getUrl(), $title, $body, $this->user->getId());
 +                if ( $last_id && !$import ) {
                      Tools::logm('add link ' . $url->getUrl());
 -                    $sequence = '';
 -                    if (STORAGE == 'postgres') {
 -                        $sequence = 'entries_id_seq';
 -                    }
 -                    $last_id = $this->store->getLastId($sequence);
                      if (DOWNLOAD_PICTURES) {
                          $content = filtre_picture($body, $url->getUrl(), $last_id);
                          Tools::logm('updating content article');
                          }
                      }
  
 -                    if (!$import) {
 -                        $this->messages->add('s', _('the link has been added successfully'));
 -                    }
 +                    $this->messages->add('s', _('the link has been added successfully'));
                  }
                  else {
                      if (!$import) {
                      'tags' => $tags,
                  );
                  break;
-                       case 'search':
-                               if (isset($_GET['search'])){
-                                       $search = $_GET['search'];
-                                       $tpl_vars['entries'] = $this->store->search($search);
-                                       $tpl_vars['nb_results'] = count($tpl_vars['entries']);
-                               }
 -                              
 -         case 'search':
 -            if (isset($_GET['search'])){
 -               $search = filter_var($_GET['search'], FILTER_SANITIZE_STRING);
 -               $tpl_vars['entries'] = $this->store->search($search,$this->user->getId());
 -               $count = count($tpl_vars['entries']);
 -               $this->pagination->set_total($count);
 -               $page_links = str_replace(array('previous', 'next'), array(_('previous'), _('next')),
 -                        $this->pagination->page_links('?view=' . $view . '?search=' . $search . '&sort=' . $_SESSION['sort'] . '&' ));
 -               $tpl_vars['page_links'] = $page_links;
 -               $tpl_vars['nb_results'] = $count;
 -               $tpl_vars['search_term'] = $search;
 -            }
--                              break;
++            case 'search':
++                if (isset($_GET['search'])) {
++                   $search = filter_var($_GET['search'], FILTER_SANITIZE_STRING);
++                   $tpl_vars['entries'] = $this->store->search($search, $this->user->getId());
++                   $count = count($tpl_vars['entries']);
++                   $this->pagination->set_total($count);
++                   $page_links = str_replace(array('previous', 'next'), array(_('previous'), _('next')),
++                            $this->pagination->page_links('?view=' . $view . '?search=' . $search . '&sort=' . $_SESSION['sort'] . '&' ));
++                   $tpl_vars['page_links'] = $page_links;
++                   $tpl_vars['nb_results'] = $count;
++                   $tpl_vars['search_term'] = $search;
++                }
++                break;
              case 'view':
                  $entry = $this->store->retrieveOneById($id, $this->user->getId());
                  if ($entry != NULL) {
                      'nb_results' => '',
                      'listmode' => (isset($_COOKIE['listmode']) ? true : false),
                  );
 -                
 +
                  //if id is given - we retrive entries by tag: id is tag id
                  if ($id) {
                    $tpl_vars['tag'] = $this->store->retrieveTag($id, $this->user->getId());
      }
  
      /**
 -     * update the password of the current user. 
 -     * if MODE_DEMO is TRUE, the password can't be updated. 
 +     * update the password of the current user.
 +     * if MODE_DEMO is TRUE, the password can't be updated.
       * @todo add the return value
       * @todo set the new password in function header like this updatePassword($newPassword)
       * @return boolean
              }
          }
      }
 -    
 +
      public function updateTheme()
      {
          # no data
          if (empty($_POST['theme'])) {
          }
 -        
 +
          # we are not going to change it to the current theme...
          if ($_POST['theme'] == $this->getTheme()) {
              $this->messages->add('w', _('still using the "' . $this->getTheme() . '" theme!'));
              Tools::redirect('?view=config');
          }
 -        
 +
          $themes = $this->getInstalledThemes();
          $actualTheme = false;
 -        
 +
          foreach (array_keys($themes) as $theme) {
              if ($theme == $_POST['theme']) {
                  $actualTheme = true;
                  break;
              }
          }
 -        
 +
          if (! $actualTheme) {
              $this->messages->add('e', _('that theme does not seem to be installed'));
              Tools::redirect('?view=config');
          }
 -        
 +
          $this->store->updateUserConfig($this->user->getId(), 'theme', $_POST['theme']);
          $this->messages->add('s', _('you have changed your theme preferences'));
 -        
 +
          $currentConfig = $_SESSION['poche_user']->config;
          $currentConfig['theme'] = $_POST['theme'];
 -        
 +
          $_SESSION['poche_user']->setConfig($currentConfig);
  
          $this->emptyCache();
 -        
 +
          Tools::redirect('?view=config');
      }
  
          # no data
          if (empty($_POST['language'])) {
          }
 -        
 +
          # we are not going to change it to the current language...
          if ($_POST['language'] == $this->getLanguage()) {
              $this->messages->add('w', _('still using the "' . $this->getLanguage() . '" language!'));
              Tools::redirect('?view=config');
          }
 -        
 +
          $languages = $this->getInstalledLanguages();
          $actualLanguage = false;
 -        
 +
          foreach ($languages as $language) {
              if ($language['value'] == $_POST['language']) {
                  $actualLanguage = true;
                  break;
              }
          }
 -        
 +
          if (! $actualLanguage) {
              $this->messages->add('e', _('that language does not seem to be installed'));
              Tools::redirect('?view=config');
          }
 -        
 +
          $this->store->updateUserConfig($this->user->getId(), 'language', $_POST['language']);
          $this->messages->add('s', _('you have changed your language preferences'));
 -        
 +
          $currentConfig = $_SESSION['poche_user']->config;
          $currentConfig['language'] = $_POST['language'];
 -        
 +
          $_SESSION['poche_user']->setConfig($currentConfig);
  
          $this->emptyCache();
 -        
 +
          Tools::redirect('?view=config');
 -    } 
 +    }
      /**
       * get credentials from differents sources
       * it redirects the user to the $referer link
      /**
       * log out the poche user. It cleans the session.
       * @todo add the return value
 -     * @return boolean 
 +     * @return boolean
       */
      public function logout()
      {
       * import from Pocket. poche needs a ./ril_export.html file
       * @todo add the return value
       * @param string $targetFile the file used for importing
 -     * @return boolean 
 +     * @return boolean
       */
      private function importFromPocket($targetFile)
      {
                      $this->action('add_tag',$url,$last_id,true,false,$tags);
                  }
              }
 -            
 +
              # the second <ul> is for read links
              $read = 1;
          }
       * import from Readability. poche needs a ./readability file
       * @todo add the return value
       * @param string $targetFile the file used for importing
 -     * @return boolean 
 +     * @return boolean
       */
      private function importFromReadability($targetFile)
      {
      /**
       * import from Poche exported file
       * @param string $targetFile the file used for importing
 -     * @return boolean 
 +     * @return boolean
       */
      private function importFromPoche($targetFile)
      {
              $url = new Url(base64_encode($value['url']));
              $favorite = ($value['is_fav'] == -1);
              $archive = ($value['is_read'] == -1);
 -    
 +
              # we can add the url
              if (!is_null($url) && $url->isCorrect()) {
 -                
 +
                  $this->action('add', $url, 0, TRUE);
 -                
 +
                  $count++;
                  if ($favorite) {
                      $last_id = $this->store->getLastId($sequence);
                      $this->action('toggle_archive', $url, $last_id, TRUE);
                  }
              }
 -            
 +
          }
  
          unlink($targetFile);
  
      /**
       * import datas into your poche
 -     * @param  string $from name of the service to import : pocket, instapaper or readability
 -     * @todo add the return value
 -     * @return boolean       
 +     * @return boolean
       */
 -    public function import($from)
 -    {
 -        $providers = array(
 -            'pocket' => 'importFromPocket',
 -            'readability' => 'importFromReadability',
 -            'instapaper' => 'importFromInstapaper',
 -            'poche' => 'importFromPoche',
 -        );
 -        
 -        if (! isset($providers[$from])) {
 -            $this->messages->add('e', _('Unknown import provider.'));
 -            Tools::redirect();
 +    public function import() {
 +
 +      if ( isset($_FILES['file']) ) {
 +        // assume, that file is in json format
 +        $str_data = file_get_contents($_FILES['file']['tmp_name']);
 +        $data = json_decode($str_data, true);
 +
 +        if ( $data === null ) {
 +          //not json - assume html
 +          $html = new simple_html_dom();
 +          $html->load_file($_FILES['file']['tmp_name']);
 +          $data = array();
 +          $read = 0;
 +          foreach (array('ol','ul') as $list) {
 +            foreach ($html->find($list) as $ul) {
 +              foreach ($ul->find('li') as $li) {
 +                $tmpEntry = array();
 +                      $a = $li->find('a');
 +                      $tmpEntry['url'] = $a[0]->href;
 +                      $tmpEntry['tags'] = $a[0]->tags;
 +                      $tmpEntry['is_read'] = $read;
 +                      if ($tmpEntry['url']) {
 +                        $data[] = $tmpEntry;
 +                      }
 +              }
 +              # the second <ol/ul> is for read links
 +              $read = ((sizeof($data) && $read)?0:1);
 +            }
 +          }
          }
 -        
 -        $targetFile = CACHE . '/' . constant(strtoupper($from) . '_FILE');
 -        
 -        if (! file_exists($targetFile)) {
 -            $this->messages->add('e', _('Could not find required "' . $targetFile . '" import file.'));
 -            Tools::redirect();
 +
 +        $i = 0; //counter for articles inserted
 +        foreach ($data as $record) {
 +          //echo '<pre>';
 +          //var_dump($record);
 +  //         foreach ($record as $key=>$val) {
 +  //           echo "\n=================\n$i: $key: $val\n";
 +  //         }
 +  //         exit;
 +
 +          $url = trim($record['url']);
 +          if ( $url ) {
 +            $title = (isset($record['title']) ? $record['title'] :  _('Untitled - Import - ').'</a> <a href="./?import">'._('click to finish import').'</a><a>');
 +            $body = (isset($record['content']) ? $record['content'] : '');
 +            $isRead = (isset($record['is_read']) ? intval($record['is_read']) : 0);
 +            $isFavorite = (isset($record['is_fav']) ? intval($record['is_fav']) : 0);
 +            //insert new record
 +            $id = $this->store->add($url, $title, $body, $this->user->getId(), $isFavorite, $isRead);
 +            if ( $id ) {
 +              //increment no of records inserted
 +              $i++;
 +              if ( isset($record['tags']) && trim($record['tags']) ) {
 +                      //@TODO: set tags
 +
 +              }
 +            }
 +          }
 +        }
 +
 +        if ( $i > 0 ) {
 +          $this->messages->add('s', _('Articles inserted: ').$i._('. Please note, that some may be marked as "read".'));
          }
 -        
 -        $this->$providers[$from]($targetFile);
 +      }
 +      //file parsing finished here
 +
 +      //now download article contents if any
 +
 +      //check if we need to download any content
 +      $recordsDownloadRequired = $this->store->retrieveUnfetchedEntriesCount($this->user->getId());
 +      if ( $recordsDownloadRequired == 0 ) {
 +        //nothing to download
 +        $this->messages->add('s', _('Import finished.'));
 +        Tools::redirect();
 +      }
 +      else {
 +        //if just inserted - don't download anything, download will start in next reload
 +        if ( !isset($_FILES['file']) ) {
 +          //download next batch
 +          $items = $this->store->retrieveUnfetchedEntries($this->user->getId(), IMPORT_LIMIT);
 +
 +          $config = HTMLPurifier_Config::createDefault();
 +          $config->set('Cache.SerializerPath', CACHE);
 +          $purifier = new HTMLPurifier($config);
 +
 +          foreach ($items as $item) {
 +              $url = new Url(base64_encode($item['url']));
 +              $content = Tools::getPageContent($url);
 +
 +              $title = (($content['rss']['channel']['item']['title'] != '') ? $content['rss']['channel']['item']['title'] : _('Untitled'));
 +              $body = (($content['rss']['channel']['item']['description'] != '') ? $content['rss']['channel']['item']['description'] : _('Undefined'));
 +
 +              //clean content to prevent xss attack
 +              $title = $purifier->purify($title);
 +              $body = $purifier->purify($body);
 +
 +              $this->store->updateContentAndTitle($item['id'], $title, $body, $this->user->getId());
 +          }
 +
 +        }
 +      }
 +
 +      return array('includeImport'=>true, 'import'=>array('recordsDownloadRequired'=>$recordsDownloadRequired, 'recordsUnderDownload'=> IMPORT_LIMIT, 'delay'=> IMPORT_DELAY * 1000) );
      }
  
      public function uploadFile() {
 -        if(isset($_FILES['file']))
 -        { 
 +        if (isset($_FILES['file']))
 +        {
              $dir = CACHE . '/';
              $file = basename($_FILES['file']['name']);
              if(move_uploaded_file($_FILES['file']['tmp_name'], $dir . $file)) {
                  $this->messages->add('e', _('Error while importing file. Do you have access to upload it?'));
              }
          }
 -        
 +
          Tools::redirect('?view=config');
      }
  
      {
                $filename = "wallabag-export-".$this->user->getId()."-".date("Y-m-d").".json";
                header('Content-Disposition: attachment; filename='.$filename);
 -              
 +
          $entries = $this->store->retrieveAll($this->user->getId());
          echo $this->tpl->render('export.twig', array(
              'export' => Tools::renderJson($entries),
diff --combined themes/baggy/config.twig
index a13af0c810acec71ed822c7cbf56f918337851b1,a13af0c810acec71ed822c7cbf56f918337851b1..fc7890ec9a7e560cf1c57948d9f16486917c6614
mode 100644,100644..100755
              {% endif %}
  
              <h2>{% trans "Import" %}</h2>
--            <p>{% trans "Importing from other services can be quite long, and webservers default configuration often prevents long scripts execution time, so it must be done in multiple parts." %}</p>
--            <p>1. {% trans "First, select the export file on your computer and upload it." %}</p>
--            <form method="post" action="?uploadfile" name="uploadfile" enctype="multipart/form-data">
++            <p>{% trans "You can import your Pocket, Readability, Instapaper, Wallabag or any data in appropriate json or html format." %}</p>
++            <p>{% trans "Please select export file on your computer:" %}</p>
++            <form method="post" action="?import" name="uploadfile" enctype="multipart/form-data">
                  <fieldset class="w500p">
                      <div class="row">
                          <label class="col w150p" for="file">{% trans "File:" %}</label>
                          <input class="col" type="file" id="file" name="file" tabindex="4">
                      </div>
                      <div class="row mts txtcenter">
--                        <button class="bouton" type="submit" tabindex="4">{% trans "Upload" %}</button>
++                        <button class="bouton" type="submit" tabindex="4">{% trans "Import" %}</button>
                      </div>
                  </fieldset>
--                <input type="hidden" name="MAX_FILE_SIZE" value="1048576">
--                <input type="hidden" name="returnurl" value="{{ referer }}">
              </form>
--            <p>2. {% trans "Then, click on the right link below." %}</p>
--            <ul>
--                <li><a href="./?import&amp;from=pocket">{% trans "Import from Pocket" %}</a> {{ '(after uploaded %s file)'|trans|format(constant('POCKET_FILE')) }}</li>
--                <li><a href="./?import&amp;from=readability">{% trans "Import from Readability" %}</a> {{ '(after uploaded %s file)'|trans|format(constant('READABILITY_FILE')) }}</li>
--                <li><a href="./?import&amp;from=instapaper">{% trans "Import from Instapaper" %}</a> {{ '(after uploaded %s file)'|trans|format(constant('INSTAPAPER_FILE')) }}</li>
--                <li><a href="./?import&amp;from=poche">{% trans "Import from wallabag" %}</a> {{ '(after uploaded %s file)'|trans|format(constant('POCHE_FILE')) }}</li>
--            </ul>
--
--            {% if token == '' %}
--                <p>{% trans "3. Your feed token is currently empty and must first be generated to fetch content. Click <a href='?feed&amp;action=generate'>here to generate it</a>." %}</p>
--            {% else %}
--            <p>3. {% trans "Finally, you have to fetch content for imported items." %} <a href="cron.php?limit=10&amp;user-id={{ user_id }}&amp;token={{token}}" target="_blank">{% trans "Click here" %}</a> {% trans "to fetch content for 10 articles" %}.</p>
--            <p>{% trans "If you have console access to your server, you can also create a cron task:" %}</p>
--            <pre><code>0 */4 * * *  cd /path/to/wallabag && php cron.php --limit=10 --user-id={{user_id}} --token={{token}} >/dev/null 2>&1</code></pre>
--            {% endif %}
--
++            
              <h2>{% trans "Export your wallabag data" %}</h2>
              {% if constant('STORAGE') == 'sqlite' %}
              <p><a href="?download" target="_blank">{% trans "Click here" %}</a> {% trans "to download your database." %}</p>{% endif %}
index 6e328ba1e4addd810571cac3e736824e0432b80c,6e328ba1e4addd810571cac3e736824e0432b80c..9a45544beedb147dc2599f508f05dc52e260b7f7
@@@ -777,7 -777,7 +777,7 @@@ margin-top:1em
    }
  
  .warning {
--  font-size: 3em;
++  /* font-size: 3em;
    color: #999;
    font-style: italic;
    position: absolute;
    width: 100%;
    text-align: center;
    padding-right: 5%;
--  margin-top: -2em;
++  margin-top: -2em;*/
++  font-weight: bold;
++  display: block;
++  width: 100%;
  }
  
  /* ==========================================================================
diff --combined themes/baggy/layout.twig
index dfebc3eacff6abe6538968fd995f3e3011c9eee2,dfebc3eacff6abe6538968fd995f3e3011c9eee2..8de12749f6d2c71e1bf8064e0930c9243e106192
mode 100644,100644..100755
@@@ -21,6 -21,6 +21,9 @@@
              {% block precontent %}{% endblock %}
              {% block messages %}
              {% include '_messages.twig' %}
++            {% if includeImport %}
++                                                              {% include '_import.twig' %}
++                                              {% endif %}
              {% endblock %}
              <div id="content" class="w600p center">
              {% block content %}{% endblock %}
diff --combined themes/default/home.twig
index e06d65ab4abf553f05715fceb2b4e17e0459972b,7bee883b649d2c7f1ee3f4c47724b8389f15779f..d6cb98e8f165fffa59a4cd6ccc6f56e610a47061
  {% include '_sorting.twig' %}
  {% endblock %}
  {% block content %}
 +
 +                                              {% if includeImport %}
 +                                                              {% include '_import.twig' %}
 +                                              {% endif %}
 +
              {% if tag %}
                  <h3>{% trans "Tag" %}: <b>{{ tag.value }}</b></h3>
              {% endif %}
                  {% block pager %}
                      {% if nb_results > 1 %}
                  <div class="results">
-                     <div class="nb-results">{{ nb_results }} {% trans "results" %}</div>
+                     <div class="nb-results">{{ nb_results }} {% trans "results" %}{% if search_term is defined %}{% trans " found for « " %} {{ search_term }} »{% endif %}</div>
                          {{ page_links | raw }}
                  </div>
+                     {% elseif nb_results == 1 %}
+                         {% if search_term is defined %}
+                      <div class="results">
+                         <div class="nb-results">{% trans "Only one result found for " %} « {{ search_term }} »</div>
+                      </div>
+                         {% endif %}
                      {% endif %}
                  {% endblock %}
                  {% for entry in entries %}