aboutsummaryrefslogtreecommitdiff
path: root/app/Models
diff options
context:
space:
mode:
authorGravatar Marien Fressinaud <dev@marienfressinaud.fr> 2014-05-13 21:03:32 +0200
committerGravatar Marien Fressinaud <dev@marienfressinaud.fr> 2014-05-13 21:03:32 +0200
commita86a51cca69b7256d3a8dcf1c68447b6d5abe917 (patch)
treeb461e144d54656fb3c2c95aee96d6303cf6fa12c /app/Models
parent88fa624a02d0346c2eb9173b1e9a02fc38b56d50 (diff)
parente763cd407a57e4829c2b6ffbddb164e5676670d7 (diff)
Merge branch 'dev' into 320-template
Diffstat (limited to 'app/Models')
-rw-r--r--app/Models/CategoryDAO.php19
-rw-r--r--app/Models/Configuration.php77
-rw-r--r--app/Models/Entry.php5
-rw-r--r--app/Models/EntryDAO.php286
-rw-r--r--app/Models/Feed.php15
-rw-r--r--app/Models/FeedDAO.php56
-rw-r--r--app/Models/Share.php44
-rw-r--r--app/Models/Themes.php2
8 files changed, 401 insertions, 103 deletions
diff --git a/app/Models/CategoryDAO.php b/app/Models/CategoryDAO.php
index 5355228a5..6a9b839b9 100644
--- a/app/Models/CategoryDAO.php
+++ b/app/Models/CategoryDAO.php
@@ -18,6 +18,19 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo {
}
}
+ public function addCategoryObject($category) {
+ $cat = $this->searchByName($category->name());
+ if (!$cat) {
+ // Category does not exist yet in DB so we add it before continue
+ $values = array(
+ 'name' => $category->name(),
+ );
+ return $this->addCategory($values);
+ }
+
+ return $cat->id();
+ }
+
public function updateCategory ($id, $valuesTmp) {
$sql = 'UPDATE `' . $this->prefix . 'category` SET name=? WHERE id=?';
$stm = $this->bd->prepare ($sql);
@@ -64,7 +77,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo {
if (isset ($cat[0])) {
return $cat[0];
} else {
- return false;
+ return null;
}
}
public function searchByName ($name) {
@@ -80,7 +93,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo {
if (isset ($cat[0])) {
return $cat[0];
} else {
- return false;
+ return null;
}
}
@@ -120,7 +133,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo {
public function checkDefault () {
$def_cat = $this->searchById (1);
- if ($def_cat === false) {
+ if ($def_cat == null) {
$cat = new FreshRSS_Category (Minz_Translate::t ('default_category'));
$cat->_id (1);
diff --git a/app/Models/Configuration.php b/app/Models/Configuration.php
index 2b719c370..8d3e69a1c 100644
--- a/app/Models/Configuration.php
+++ b/app/Models/Configuration.php
@@ -10,13 +10,15 @@ class FreshRSS_Configuration {
'mail_login' => '',
'token' => '',
'passwordHash' => '', //CRYPT_BLOWFISH
+ 'apiPasswordHash' => '', //CRYPT_BLOWFISH
'posts_per_page' => 20,
'view_mode' => 'normal',
- 'default_view' => 'not_read',
+ 'default_view' => FreshRSS_Entry::STATE_NOT_READ,
'auto_load_more' => true,
'display_posts' => false,
'onread_jump_next' => true,
'lazyload' => true,
+ 'sticky_post' => true,
'sort_order' => 'DESC',
'anon_access' => false,
'mark_when' => array(
@@ -37,6 +39,7 @@ class FreshRSS_Configuration {
'collapse_entry' => 'c',
'load_more' => 'm',
'auto_share' => 's',
+ 'focus_search' => 'a',
),
'topline_read' => true,
'topline_favorite' => true,
@@ -48,16 +51,7 @@ class FreshRSS_Configuration {
'bottomline_tags' => true,
'bottomline_date' => true,
'bottomline_link' => true,
- 'sharing' => array(
- 'shaarli' => '',
- 'wallabag' => '',
- 'diaspora' => '',
- 'twitter' => true,
- 'g+' => true,
- 'facebook' => true,
- 'email' => true,
- 'print' => true,
- ),
+ 'sharing' => array(),
);
private $available_languages = array(
@@ -65,8 +59,10 @@ class FreshRSS_Configuration {
'fr' => 'Français',
);
- public function __construct ($user) {
- $this->filename = DATA_PATH . '/' . $user . '_user.php';
+ private $shares;
+
+ public function __construct($user) {
+ $this->filename = DATA_PATH . DIRECTORY_SEPARATOR . $user . '_user.php';
$data = @include($this->filename);
if (!is_array($data)) {
@@ -80,10 +76,20 @@ class FreshRSS_Configuration {
}
}
$this->data['user'] = $user;
+
+ $this->shares = DATA_PATH . DIRECTORY_SEPARATOR . 'shares.php';
+
+ $shares = @include($this->shares);
+ if (!is_array($shares)) {
+ throw new Minz_PermissionDeniedException($this->shares);
+ }
+
+ $this->data['shares'] = $shares;
}
public function save() {
@rename($this->filename, $this->filename . '.bak.php');
+ unset($this->data['shares']); // Remove shares because it is not intended to be stored in user configuration
if (file_put_contents($this->filename, "<?php\n return " . var_export($this->data, true) . ';', LOCK_EX) === false) {
throw new Minz_PermissionDeniedException($this->filename);
}
@@ -104,16 +110,6 @@ class FreshRSS_Configuration {
}
}
- public function sharing($key = false) {
- if ($key === false) {
- return $this->data['sharing'];
- }
- if (isset($this->data['sharing'][$key])) {
- return $this->data['sharing'][$key];
- }
- return false;
- }
-
public function availableLanguages() {
return $this->available_languages;
}
@@ -136,7 +132,7 @@ class FreshRSS_Configuration {
}
}
public function _default_view ($value) {
- $this->data['default_view'] = $value === 'all' ? 'all' : 'not_read';
+ $this->data['default_view'] = $value === FreshRSS_Entry::STATE_ALL ? FreshRSS_Entry::STATE_ALL : FreshRSS_Entry::STATE_NOT_READ;
}
public function _display_posts ($value) {
$this->data['display_posts'] = ((bool)$value) && $value !== 'no';
@@ -147,6 +143,9 @@ class FreshRSS_Configuration {
public function _lazyload ($value) {
$this->data['lazyload'] = ((bool)$value) && $value !== 'no';
}
+ public function _sticky_post($value) {
+ $this->data['sticky_post'] = ((bool)$value) && $value !== 'no';
+ }
public function _sort_order ($value) {
$this->data['sort_order'] = $value === 'ASC' ? 'ASC' : 'DESC';
}
@@ -168,6 +167,9 @@ class FreshRSS_Configuration {
public function _passwordHash ($value) {
$this->data['passwordHash'] = ctype_graph($value) && (strlen($value) >= 60) ? $value : '';
}
+ public function _apiPasswordHash ($value) {
+ $this->data['apiPasswordHash'] = ctype_graph($value) && (strlen($value) >= 60) ? $value : '';
+ }
public function _mail_login ($value) {
$value = filter_var($value, FILTER_VALIDATE_EMAIL);
if ($value) {
@@ -187,24 +189,33 @@ class FreshRSS_Configuration {
}
}
public function _sharing ($values) {
- $are_url = array ('shaarli', 'wallabag', 'diaspora');
- foreach ($values as $key => $value) {
- if (in_array($key, $are_url)) {
+ $this->data['sharing'] = array();
+ foreach ($values as $value) {
+ if (!is_array($value)) {
+ continue;
+ }
+
+ // Verify URL and add default value when needed
+ if (isset($value['url'])) {
$is_url = (
- filter_var ($value, FILTER_VALIDATE_URL) ||
+ filter_var ($value['url'], FILTER_VALIDATE_URL) ||
(version_compare(PHP_VERSION, '5.3.3', '<') &&
(strpos($value, '-') > 0) &&
($value === filter_var($value, FILTER_SANITIZE_URL)))
); //PHP bug #51192
-
if (!$is_url) {
- $value = '';
+ continue;
}
- } elseif (!is_bool($value)) {
- $value = true;
+ } else {
+ $value['url'] = null;
+ }
+
+ // Add a default name
+ if (empty($value['name'])) {
+ $value['name'] = $value['type'];
}
- $this->data['sharing'][$key] = $value;
+ $this->data['sharing'][] = $value;
}
}
public function _theme($value) {
diff --git a/app/Models/Entry.php b/app/Models/Entry.php
index a6c67221b..fa9066d5b 100644
--- a/app/Models/Entry.php
+++ b/app/Models/Entry.php
@@ -1,6 +1,11 @@
<?php
class FreshRSS_Entry extends Minz_Model {
+ const STATE_ALL = 0;
+ const STATE_READ = 1;
+ const STATE_NOT_READ = 2;
+ const STATE_FAVORITE = 4;
+ const STATE_NOT_FAVORITE = 8;
private $id = 0;
private $guid;
diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php
index aaf4dcf6a..73893a88d 100644
--- a/app/Models/EntryDAO.php
+++ b/app/Models/EntryDAO.php
@@ -35,11 +35,45 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo {
}
}
- public function markFavorite ($id, $is_favorite = true) {
+ public function addEntryObject($entry, $conf, $feedHistory) {
+ $existingGuids = array_fill_keys(
+ $this->listLastGuidsByFeed($entry->feed(), 20), 1
+ );
+
+ $nb_month_old = max($conf->old_entries, 1);
+ $date_min = time() - (3600 * 24 * 30 * $nb_month_old);
+
+ $eDate = $entry->date(true);
+
+ if ($feedHistory == -2) {
+ $feedHistory = $conf->keep_history_default;
+ }
+
+ if (!isset($existingGuids[$entry->guid()]) &&
+ ($feedHistory != 0 || $eDate >= $date_min)) {
+ $values = $entry->toArray();
+
+ $useDeclaredDate = empty($existingGuids);
+ $values['id'] = ($useDeclaredDate || $eDate < $date_min) ?
+ min(time(), $eDate) . uSecString() :
+ uTimeString();
+
+ return $this->addEntry($values);
+ }
+
+ // We don't return Entry object to avoid a research in DB
+ return -1;
+ }
+
+ public function markFavorite($ids, $is_favorite = true) {
+ if (!is_array($ids)) {
+ $ids = array($ids);
+ }
$sql = 'UPDATE `' . $this->prefix . 'entry` e '
. 'SET e.is_favorite = ? '
- . 'WHERE e.id=?';
- $values = array ($is_favorite ? 1 : 0, $id);
+ . 'WHERE e.id IN (' . str_repeat('?,', count($ids) - 1). '?)';
+ $values = array ($is_favorite ? 1 : 0);
+ $values = array_merge($values, $ids);
$stm = $this->bd->prepare ($sql);
if ($stm && $stm->execute ($values)) {
return $stm->rowCount();
@@ -49,30 +83,79 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo {
return false;
}
}
- public function markRead ($id, $is_read = true) {
- $sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id '
- . 'SET e.is_read = ?,'
- . 'f.cache_nbUnreads=f.cache_nbUnreads' . ($is_read ? '-' : '+') . '1 '
- . 'WHERE e.id=?';
- $values = array ($is_read ? 1 : 0, $id);
- $stm = $this->bd->prepare ($sql);
- if ($stm && $stm->execute ($values)) {
- return $stm->rowCount();
+
+ public function markRead($ids, $is_read = true) {
+ if (is_array($ids)) {
+ if (count($ids) < 6) { //Speed heuristics
+ $affected = 0;
+ foreach ($ids as $id) {
+ $affected += $this->markRead($id, $is_read);
+ }
+ return $affected;
+ }
+
+ $this->bd->beginTransaction();
+ $sql = 'UPDATE `' . $this->prefix . 'entry` e '
+ . 'SET e.is_read = ? '
+ . 'WHERE e.id IN (' . str_repeat('?,', count($ids) - 1). '?)';
+ $values = array($is_read ? 1 : 0);
+ $values = array_merge($values, $ids);
+ $stm = $this->bd->prepare($sql);
+ if (!($stm && $stm->execute($values))) {
+ $info = $stm->errorInfo();
+ Minz_Log::record('SQL error : ' . $info[2], Minz_Log::ERROR);
+ $this->bd->rollBack();
+ return false;
+ }
+ $affected = $stm->rowCount();
+
+ if ($affected > 0) {
+ $sql = 'UPDATE `' . $this->prefix . 'feed` f '
+ . 'INNER JOIN ('
+ . 'SELECT e.id_feed, '
+ . 'COUNT(CASE WHEN e.is_read = 0 THEN 1 END) AS nbUnreads, '
+ . 'COUNT(e.id) AS nbEntries '
+ . 'FROM `' . $this->prefix . 'entry` e '
+ . 'GROUP BY e.id_feed'
+ . ') x ON x.id_feed=f.id '
+ . 'SET f.cache_nbEntries=x.nbEntries, f.cache_nbUnreads=x.nbUnreads';
+ $stm = $this->bd->prepare($sql);
+ if (!($stm && $stm->execute())) {
+ $info = $stm->errorInfo();
+ Minz_Log::record('SQL error : ' . $info[2], Minz_Log::ERROR);
+ $this->bd->rollBack();
+ return false;
+ }
+ }
+
+ $this->bd->commit();
+ return $affected;
} else {
- $info = $stm->errorInfo();
- Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR);
- return false;
+ $sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id '
+ . 'SET e.is_read = ?,'
+ . 'f.cache_nbUnreads=f.cache_nbUnreads' . ($is_read ? '-' : '+') . '1 '
+ . 'WHERE e.id=?';
+ $values = array($is_read ? 1 : 0, $ids);
+ $stm = $this->bd->prepare($sql);
+ if ($stm && $stm->execute($values)) {
+ return $stm->rowCount();
+ } else {
+ $info = $stm->errorInfo();
+ Minz_Log::record('SQL error : ' . $info[2], Minz_Log::ERROR);
+ return false;
+ }
}
}
- public function markReadEntries ($idMax = 0, $favorites = false) {
- if ($idMax === 0) {
+
+ public function markReadEntries ($idMax = 0, $onlyFavorites = false, $priorityMin = 0) {
+ if ($idMax == 0) {
$sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id '
. 'SET e.is_read = 1, f.cache_nbUnreads=0 '
- . 'WHERE e.is_read = 0 AND ';
- if ($favorites) {
- $sql .= 'e.is_favorite = 1';
- } else {
- $sql .= 'f.priority > 0';
+ . 'WHERE e.is_read = 0';
+ if ($onlyFavorites) {
+ $sql .= ' AND e.is_favorite = 1';
+ } elseif ($priorityMin >= 0) {
+ $sql .= ' AND f.priority > ' . intval($priorityMin);
}
$stm = $this->bd->prepare ($sql);
if ($stm && $stm->execute ()) {
@@ -87,11 +170,11 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo {
$sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id '
. 'SET e.is_read = 1 '
- . 'WHERE e.is_read = 0 AND e.id <= ? AND ';
- if ($favorites) {
- $sql .= 'e.is_favorite = 1';
- } else {
- $sql .= 'f.priority > 0';
+ . 'WHERE e.is_read = 0 AND e.id <= ?';
+ if ($onlyFavorites) {
+ $sql .= ' AND e.is_favorite = 1';
+ } elseif ($priorityMin >= 0) {
+ $sql .= ' AND f.priority > ' . intval($priorityMin);
}
$values = array ($idMax);
$stm = $this->bd->prepare ($sql);
@@ -126,8 +209,9 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo {
return $affected;
}
}
+
public function markReadCat ($id, $idMax = 0) {
- if ($idMax === 0) {
+ if ($idMax == 0) {
$sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id '
. 'SET e.is_read = 1, f.cache_nbUnreads=0 '
. 'WHERE f.category = ? AND e.is_read = 0';
@@ -181,8 +265,70 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo {
return $affected;
}
}
+
+ public function markReadCatName($name, $idMax = 0) {
+ if ($idMax == 0) {
+ $sql = 'UPDATE `' . $this->prefix . 'entry` e '
+ . 'INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id '
+ . 'INNER JOIN `' . $this->prefix . 'category` c ON c.id = f.category '
+ . 'SET e.is_read = 1, f.cache_nbUnreads=0 '
+ . 'WHERE c.name = ?';
+ $values = array($name);
+ $stm = $this->bd->prepare($sql);
+ if ($stm && $stm->execute($values)) {
+ return $stm->rowCount();
+ } else {
+ $info = $stm->errorInfo();
+ Minz_Log::record('SQL error : ' . $info[2], Minz_Log::ERROR);
+ return false;
+ }
+ } else {
+ $this->bd->beginTransaction();
+
+ $sql = 'UPDATE `' . $this->prefix . 'entry` e '
+ . 'INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id '
+ . 'INNER JOIN `' . $this->prefix . 'category` c ON c.id = f.category '
+ . 'SET e.is_read = 1 '
+ . 'WHERE c.name = ? AND e.id <= ?';
+ $values = array($name, $idMax);
+ $stm = $this->bd->prepare($sql);
+ if (!($stm && $stm->execute($values))) {
+ $info = $stm->errorInfo();
+ Minz_Log::record('SQL error : ' . $info[2], Minz_Log::ERROR);
+ $this->bd->rollBack();
+ return false;
+ }
+ $affected = $stm->rowCount();
+
+ if ($affected > 0) {
+ $sql = 'UPDATE `' . $this->prefix . 'feed` f '
+ . 'LEFT OUTER JOIN ('
+ . 'SELECT e.id_feed, '
+ . 'COUNT(*) AS nbUnreads '
+ . 'FROM `' . $this->prefix . 'entry` e '
+ . 'WHERE e.is_read = 0 '
+ . 'GROUP BY e.id_feed'
+ . ') x ON x.id_feed=f.id '
+ . 'INNER JOIN `' . $this->prefix . 'category` c ON c.id = f.category '
+ . 'SET f.cache_nbUnreads=COALESCE(x.nbUnreads, 0) '
+ . 'WHERE c.name = ?';
+ $values = array($name);
+ $stm = $this->bd->prepare($sql);
+ if (!($stm && $stm->execute($values))) {
+ $info = $stm->errorInfo();
+ Minz_Log::record('SQL error : ' . $info[2], Minz_Log::ERROR);
+ $this->bd->rollBack();
+ return false;
+ }
+ }
+
+ $this->bd->commit();
+ return $affected;
+ }
+ }
+
public function markReadFeed ($id, $idMax = 0) {
- if ($idMax === 0) {
+ if ($idMax == 0) {
$sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id '
. 'SET e.is_read = 1, f.cache_nbUnreads=0 '
. 'WHERE f.id=? AND e.is_read = 0';
@@ -244,7 +390,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo {
$stm->execute ($values);
$res = $stm->fetchAll (PDO::FETCH_ASSOC);
$entries = self::daoToEntry ($res);
- return isset ($entries[0]) ? $entries[0] : false;
+ return isset ($entries[0]) ? $entries[0] : null;
}
public function searchById ($id) {
@@ -257,10 +403,13 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo {
$stm->execute ($values);
$res = $stm->fetchAll (PDO::FETCH_ASSOC);
$entries = self::daoToEntry ($res);
- return isset ($entries[0]) ? $entries[0] : false;
+ return isset ($entries[0]) ? $entries[0] : null;
}
- public function listWhere($type = 'a', $id = '', $state = 'all', $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0, $keepHistoryDefault = 0) {
+ private function sqlListWhere($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0, $showOlderUnreadsorFavorites = false, $keepHistoryDefault = 0) {
+ if (!$state) {
+ $state = FreshRSS_Entry::STATE_ALL;
+ }
$where = '';
$joinFeed = false;
$values = array();
@@ -269,7 +418,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo {
$where .= 'f.priority > 0 ';
$joinFeed = true;
break;
- case 's':
+ case 's': //Deprecated: use $state instead
$where .= 'e1.is_favorite = 1 ';
break;
case 'c':
@@ -281,24 +430,30 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo {
$where .= 'e1.id_feed = ? ';
$values[] = intval($id);
break;
+ case 'A':
+ $where .= '1 ';
+ break;
default:
throw new FreshRSS_EntriesGetter_Exception ('Bad type in Entry->listByType: [' . $type . ']!');
}
- switch ($state) {
- case 'all':
- break;
- case 'not_read':
+
+ if ($state & FreshRSS_Entry::STATE_NOT_READ) {
+ if (!($state & FreshRSS_Entry::STATE_READ)) {
$where .= 'AND e1.is_read = 0 ';
- break;
- case 'read':
- $where .= 'AND e1.is_read = 1 ';
- break;
- case 'favorite':
+ }
+ }
+ elseif ($state & FreshRSS_Entry::STATE_READ) {
+ $where .= 'AND e1.is_read = 1 ';
+ }
+ if ($state & FreshRSS_Entry::STATE_FAVORITE) {
+ if (!($state & FreshRSS_Entry::STATE_NOT_FAVORITE)) {
$where .= 'AND e1.is_favorite = 1 ';
- break;
- default:
- throw new FreshRSS_EntriesGetter_Exception ('Bad state in Entry->listByType: [' . $state . ']!');
+ }
+ }
+ elseif ($state & FreshRSS_Entry::STATE_NOT_FAVORITE) {
+ $where .= 'AND e1.is_favorite = 0 ';
}
+
switch ($order) {
case 'DESC':
case 'ASC':
@@ -310,11 +465,15 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo {
$where .= 'AND e1.id ' . ($order === 'DESC' ? '<=' : '>=') . $firstId . ' ';
}
if (($date_min > 0) && ($type !== 's')) {
- $where .= 'AND (e1.id >= ' . $date_min . '000000 OR e1.is_read = 0 OR e1.is_favorite = 1 OR (f.keep_history <> 0';
- if (intval($keepHistoryDefault) === 0) {
- $where .= ' AND f.keep_history <> -2'; //default
+ $where .= 'AND (e1.id >= ' . $date_min . '000000';
+ if ($showOlderUnreadsorFavorites) { //Lax date constraint
+ $where .= ' OR e1.is_read = 0 OR e1.is_favorite = 1 OR (f.keep_history <> 0';
+ if (intval($keepHistoryDefault) === 0) {
+ $where .= ' AND f.keep_history <> -2'; //default
+ }
+ $where .= ')';
}
- $where .= ')) ';
+ $where .= ') ';
$joinFeed = true;
}
$search = '';
@@ -366,14 +525,22 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo {
}
}
+ return array($values,
+ 'SELECT e1.id FROM `' . $this->prefix . 'entry` e1 '
+ . ($joinFeed ? 'INNER JOIN `' . $this->prefix . 'feed` f ON e1.id_feed = f.id ' : '')
+ . 'WHERE ' . $where
+ . $search
+ . 'ORDER BY e1.id ' . $order
+ . ($limit > 0 ? ' LIMIT ' . $limit : '')); //TODO: See http://explainextended.com/2009/10/23/mysql-order-by-limit-performance-late-row-lookups/
+ }
+
+ public function listWhere($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0, $showOlderUnreadsorFavorites = false, $keepHistoryDefault = 0) {
+ list($values, $sql) = $this->sqlListWhere($type, $id, $state, $order, $limit, $firstId, $filter, $date_min, $showOlderUnreadsorFavorites, $keepHistoryDefault);
+
$sql = 'SELECT e.id, e.guid, e.title, e.author, UNCOMPRESS(e.content_bin) AS content, e.link, e.date, e.is_read, e.is_favorite, e.id_feed, e.tags '
. 'FROM `' . $this->prefix . 'entry` e '
- . 'INNER JOIN (SELECT e1.id FROM `' . $this->prefix . 'entry` e1 '
- . ($joinFeed ? 'INNER JOIN `' . $this->prefix . 'feed` f ON e1.id_feed = f.id ' : '')
- . 'WHERE ' . $where
- . $search
- . 'ORDER BY e1.id ' . $order
- . ($limit > 0 ? ' LIMIT ' . $limit : '') //TODO: See http://explainextended.com/2009/10/23/mysql-order-by-limit-performance-late-row-lookups/
+ . 'INNER JOIN ('
+ . $sql
. ') e2 ON e2.id = e.id '
. 'ORDER BY e.id ' . $order;
@@ -383,6 +550,15 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo {
return self::daoToEntry ($stm->fetchAll (PDO::FETCH_ASSOC));
}
+ public function listIdsWhere($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0, $showOlderUnreadsorFavorites = false, $keepHistoryDefault = 0) { //For API
+ list($values, $sql) = $this->sqlListWhere($type, $id, $state, $order, $limit, $firstId, $filter, $date_min, $showOlderUnreadsorFavorites, $keepHistoryDefault);
+
+ $stm = $this->bd->prepare($sql);
+ $stm->execute($values);
+
+ return $stm->fetchAll(PDO::FETCH_COLUMN, 0);
+ }
+
public function listLastGuidsByFeed($id, $n) {
$sql = 'SELECT guid FROM `' . $this->prefix . 'entry` WHERE id_feed=? ORDER BY id DESC LIMIT ' . intval($n);
$stm = $this->bd->prepare ($sql);
diff --git a/app/Models/Feed.php b/app/Models/Feed.php
index 73f9c32fb..13d3dfe88 100644
--- a/app/Models/Feed.php
+++ b/app/Models/Feed.php
@@ -210,8 +210,8 @@ class FreshRSS_Feed extends Minz_Model {
}
if ($loadDetails) {
- $title = htmlspecialchars(html_only_entity_decode($feed->get_title()), ENT_COMPAT, 'UTF-8');
- $this->_name ($title === null ? $this->url : $title);
+ $title = strtr(html_only_entity_decode($feed->get_title()), array('<' => '&lt;', '>' => '&gt;', '"' => '&quot;')); //HTML to HTML-PRE //ENT_COMPAT except &
+ $this->_name ($title == '' ? $this->url : $title);
$this->_website(html_only_entity_decode($feed->get_link()));
$this->_description(html_only_entity_decode($feed->get_description()));
@@ -254,11 +254,12 @@ class FreshRSS_Feed extends Minz_Model {
$elinks = array();
foreach ($item->get_enclosures() as $enclosure) {
$elink = $enclosure->get_link();
- if (array_key_exists($elink, $elinks)) continue;
- $elinks[$elink] = '1';
- $mime = strtolower($enclosure->get_type());
- if (strpos($mime, 'image/') === 0) {
- $content .= '<br /><img src="' . $elink . '" alt="" />';
+ if (empty($elinks[$elink])) {
+ $elinks[$elink] = '1';
+ $mime = strtolower($enclosure->get_type());
+ if (strpos($mime, 'image/') === 0) {
+ $content .= '<br /><img src="' . $elink . '" alt="" />';
+ }
}
}
diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php
index 7ebe68d2b..b65ff4af0 100644
--- a/app/Models/FeedDAO.php
+++ b/app/Models/FeedDAO.php
@@ -24,6 +24,36 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo {
}
}
+ public function addFeedObject($feed) {
+ // TODO: not sure if we should write this method in DAO since DAO
+ // should not be aware about feed class
+
+ // Add feed only if we don't find it in DB
+ $feed_search = $this->searchByUrl($feed->url());
+ if (!$feed_search) {
+ $values = array(
+ 'id' => $feed->id(),
+ 'url' => $feed->url(),
+ 'category' => $feed->category(),
+ 'name' => $feed->name(),
+ 'website' => $feed->website(),
+ 'description' => $feed->description(),
+ 'lastUpdate' => 0,
+ 'httpAuth' => $feed->httpAuth()
+ );
+
+ $id = $this->addFeed($values);
+ if ($id) {
+ $feed->_id($id);
+ $feed->faviconPrepare();
+ }
+
+ return $id;
+ }
+
+ return $feed_search->id();
+ }
+
public function updateFeed ($id, $valuesTmp) {
$set = '';
foreach ($valuesTmp as $key => $v) {
@@ -170,7 +200,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo {
if (isset ($feed[$id])) {
return $feed[$id];
} else {
- return false;
+ return null;
}
}
public function searchByUrl ($url) {
@@ -186,7 +216,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo {
if (isset ($feed)) {
return $feed;
} else {
- return false;
+ return null;
}
}
@@ -198,6 +228,22 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo {
return self::daoToFeed ($stm->fetchAll (PDO::FETCH_ASSOC));
}
+ public function arrayFeedCategoryNames() { //For API
+ $sql = 'SELECT f.id, f.name, c.name as c_name FROM `' . $this->prefix . 'feed` f '
+ . 'INNER JOIN `' . $this->prefix . 'category` c ON c.id = f.category';
+ $stm = $this->bd->prepare ($sql);
+ $stm->execute ();
+ $res = $stm->fetchAll(PDO::FETCH_ASSOC);
+ $feedCategoryNames = array();
+ foreach ($res as $line) {
+ $feedCategoryNames[$line['id']] = array(
+ 'name' => $line['name'],
+ 'c_name' => $line['c_name'],
+ );
+ }
+ return $feedCategoryNames;
+ }
+
public function listFeedsOrderUpdate ($cacheDuration = 1500) {
$sql = 'SELECT id, name, url, lastUpdate, pathEntries, httpAuth, keep_history '
. 'FROM `' . $this->prefix . 'feed` '
@@ -229,6 +275,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo {
return $res[0]['count'];
}
+
public function countNotRead ($id) {
$sql = 'SELECT COUNT(*) AS count FROM `' . $this->prefix . 'entry` WHERE id_feed=? AND is_read=0';
$stm = $this->bd->prepare ($sql);
@@ -238,6 +285,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo {
return $res[0]['count'];
}
+
public function updateCachedValues () { //For one single feed, call updateLastUpdate($id)
$sql = 'UPDATE `' . $this->prefix . 'feed` f '
. 'INNER JOIN ('
@@ -250,9 +298,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo {
. 'SET f.cache_nbEntries=x.nbEntries, f.cache_nbUnreads=x.nbUnreads';
$stm = $this->bd->prepare ($sql);
- $values = array ($feed_id);
-
- if ($stm && $stm->execute ($values)) {
+ if ($stm && $stm->execute()) {
return $stm->rowCount();
} else {
$info = $stm->errorInfo();
diff --git a/app/Models/Share.php b/app/Models/Share.php
new file mode 100644
index 000000000..b146db722
--- /dev/null
+++ b/app/Models/Share.php
@@ -0,0 +1,44 @@
+<?php
+
+class FreshRSS_Share {
+
+ static public function generateUrl($options, $selected, $link, $title) {
+ $share = $options[$selected['type']];
+ $matches = array(
+ '~URL~',
+ '~TITLE~',
+ '~LINK~',
+ );
+ $replaces = array(
+ $selected['url'],
+ self::transformData($title, self::getTransform($share, 'title')),
+ self::transformData($link, self::getTransform($share, 'link')),
+ );
+ $url = str_replace($matches, $replaces, $share['url']);
+ return $url;
+ }
+
+ static private function transformData($data, $transform) {
+ if (!is_array($transform)) {
+ return $data;
+ }
+ if (count($transform) === 0) {
+ return $data;
+ }
+ foreach ($transform as $action) {
+ $data = call_user_func($action, $data);
+ }
+ return $data;
+ }
+
+ static private function getTransform($options, $type) {
+ $transform = $options['transform'];
+
+ if (array_key_exists($type, $transform)) {
+ return $transform[$type];
+ }
+
+ return $transform;
+ }
+
+}
diff --git a/app/Models/Themes.php b/app/Models/Themes.php
index c7099a1df..17b95bb9e 100644
--- a/app/Models/Themes.php
+++ b/app/Models/Themes.php
@@ -77,6 +77,7 @@ class FreshRSS_Themes extends Minz_Model {
'down' => '▽',
'favorite' => '★',
'help' => 'ⓘ',
+ 'key' => '⚿',
'link' => '↗',
'login' => '🔒',
'logout' => '🔓',
@@ -84,6 +85,7 @@ class FreshRSS_Themes extends Minz_Model {
'non-starred' => '☆',
'prev' => '⏪',
'read' => '☑',
+ 'rss' => '☄',
'unread' => '☐',
'refresh' => '🔃', //↻
'search' => '🔍',