mirror of https://github.com/FreshRSS/FreshRSS.git
Merge branch 'edge' into feature/http-response-code
This commit is contained in:
commit
c27359ff65
|
@ -202,7 +202,7 @@ class FreshRSS_index_Controller extends FreshRSS_ActionController {
|
|||
$type = (string)$get[0];
|
||||
$id = (int)$get[1];
|
||||
|
||||
$this->view->excludeMutedFeeds = true;
|
||||
$this->view->excludeMutedFeeds = $type !== 'f'; // Exclude muted feeds except when we focus on a feed
|
||||
|
||||
switch ($type) {
|
||||
case 'a':
|
||||
|
|
|
@ -389,7 +389,8 @@ final class FreshRSS_Context {
|
|||
|
||||
if (empty(self::$categories)) {
|
||||
$catDAO = FreshRSS_Factory::createCategoryDao();
|
||||
self::$categories = $catDAO->listCategories(true);
|
||||
$details = $type === 'f'; // Load additional feed details in the case of feed view
|
||||
self::$categories = $catDAO->listCategories(true, $details);
|
||||
}
|
||||
|
||||
switch($type) {
|
||||
|
|
|
@ -232,8 +232,29 @@ SQL;
|
|||
$catDAO->resetDefaultCategoryName();
|
||||
|
||||
include_once(APP_PATH . '/SQL/install.sql.' . $this->pdo->dbType() . '.php');
|
||||
if (!empty($GLOBALS['SQL_UPDATE_MINOR']) && $this->pdo->exec($GLOBALS['SQL_UPDATE_MINOR']) === false) {
|
||||
Minz_Log::error('SQL error ' . __METHOD__ . json_encode($this->pdo->errorInfo()));
|
||||
if (!empty($GLOBALS['SQL_UPDATE_MINOR'])) {
|
||||
$sql = $GLOBALS['SQL_UPDATE_MINOR'];
|
||||
$isMariaDB = false;
|
||||
|
||||
if ($this->pdo->dbType() === 'mysql') {
|
||||
$dbVersion = $this->fetchValue('SELECT version()') ?? '';
|
||||
$isMariaDB = stripos($dbVersion, 'MariaDB') !== false; // MariaDB includes its name in version, but not MySQL
|
||||
if (!$isMariaDB) {
|
||||
// MySQL does not support `DROP INDEX IF EXISTS` yet https://dev.mysql.com/doc/refman/8.3/en/drop-index.html
|
||||
// but MariaDB does https://mariadb.com/kb/en/drop-index/
|
||||
$sql = str_replace('DROP INDEX IF EXISTS', 'DROP INDEX', $sql);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->pdo->exec($sql) === false) {
|
||||
$info = $this->pdo->errorInfo();
|
||||
if ($this->pdo->dbType() === 'mysql' &&
|
||||
!$isMariaDB && !empty($info[2]) && (stripos($info[2], "Can't DROP ") !== false)) {
|
||||
// Too bad for MySQL, but ignore error
|
||||
return;
|
||||
}
|
||||
Minz_Log::error('SQL error ' . __METHOD__ . json_encode($this->pdo->errorInfo()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -299,6 +320,7 @@ SQL;
|
|||
|
||||
try {
|
||||
$sqlite = new Minz_PdoSqlite('sqlite:' . $filename);
|
||||
$sqlite->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
|
||||
} catch (Exception $e) {
|
||||
$error = 'Error while initialising SQLite copy: ' . $e->getMessage();
|
||||
return self::stdError($error);
|
||||
|
|
|
@ -304,13 +304,19 @@ SELECT id, url, kind, category, name, website, description, `lastUpdate`,
|
|||
FROM `_feed`
|
||||
SQL;
|
||||
$stm = $this->pdo->query($sql);
|
||||
if ($stm === false) {
|
||||
return;
|
||||
}
|
||||
while ($row = $stm->fetch(PDO::FETCH_ASSOC)) {
|
||||
/** @var array{'id':int,'url':string,'kind':int,'category':int,'name':string,'website':string,'description':string,'lastUpdate':int,'priority'?:int,
|
||||
* 'pathEntries'?:string,'httpAuth':string,'error':int|bool,'ttl'?:int,'attributes'?:string} $row */
|
||||
yield $row;
|
||||
if ($stm !== false) {
|
||||
while ($row = $stm->fetch(PDO::FETCH_ASSOC)) {
|
||||
/** @var array{'id':int,'url':string,'kind':int,'category':int,'name':string,'website':string,'description':string,'lastUpdate':int,'priority'?:int,
|
||||
* 'pathEntries'?:string,'httpAuth':string,'error':int|bool,'ttl'?:int,'attributes'?:string} $row */
|
||||
yield $row;
|
||||
}
|
||||
} else {
|
||||
$info = $this->pdo->errorInfo();
|
||||
if ($this->autoUpdateDb($info)) {
|
||||
yield from $this->selectAll();
|
||||
} else {
|
||||
Minz_Log::error(__method__ . ' error: ' . json_encode($info));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -115,6 +115,7 @@ SQL;
|
|||
|
||||
$GLOBALS['SQL_UPDATE_MINOR'] = <<<'SQL'
|
||||
ALTER TABLE `_feed`
|
||||
MODIFY COLUMN `website` TEXT CHARACTER SET latin1 COLLATE latin1_bin,
|
||||
MODIFY COLUMN `lastUpdate` BIGINT DEFAULT 0,
|
||||
MODIFY COLUMN `pathEntries` VARCHAR(4096),
|
||||
MODIFY COLUMN `httpAuth` VARCHAR(1024) CHARACTER SET latin1 COLLATE latin1_bin DEFAULT NULL;
|
||||
|
@ -136,4 +137,7 @@ ALTER TABLE `_entrytmp`
|
|||
MODIFY COLUMN `tags` VARCHAR(2048);
|
||||
ALTER TABLE `_tag`
|
||||
MODIFY COLUMN `name` VARCHAR(191) NOT NULL;
|
||||
ALTER TABLE `_feed`
|
||||
DROP INDEX IF EXISTS `url`, -- IF EXISTS works with MariaDB but not with MySQL, so needs PHP workaround
|
||||
MODIFY COLUMN `url` VARCHAR(32768) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL;
|
||||
SQL;
|
||||
|
|
|
@ -106,7 +106,10 @@ $GLOBALS['SQL_UPDATE_MINOR'] = <<<'SQL'
|
|||
ALTER TABLE `_category`
|
||||
ALTER COLUMN "name" SET DATA TYPE VARCHAR(191);
|
||||
ALTER TABLE `_feed`
|
||||
DROP CONSTRAINT IF EXISTS `_feed_url_key`,
|
||||
ALTER COLUMN "url" SET DATA TYPE VARCHAR(32768),
|
||||
ALTER COLUMN "name" SET DATA TYPE VARCHAR(191),
|
||||
ALTER COLUMN "website" SET DATA TYPE VARCHAR(32768),
|
||||
ALTER COLUMN "lastUpdate" SET DATA TYPE BIGINT,
|
||||
ALTER COLUMN "pathEntries" SET DATA TYPE VARCHAR(4096),
|
||||
ALTER COLUMN "httpAuth" SET DATA TYPE VARCHAR(1024);
|
||||
|
|
|
@ -284,7 +284,7 @@ class FreshRSS_Import_Service {
|
|||
$curl_params[CURLOPT_PROXY] = $feed_elt['frss:CURLOPT_PROXY'];
|
||||
}
|
||||
if (isset($feed_elt['frss:CURLOPT_PROXYTYPE'])) {
|
||||
$curl_params[CURLOPT_PROXYTYPE] = $feed_elt['frss:CURLOPT_PROXYTYPE'];
|
||||
$curl_params[CURLOPT_PROXYTYPE] = (int)$feed_elt['frss:CURLOPT_PROXYTYPE'];
|
||||
}
|
||||
if (isset($feed_elt['frss:CURLOPT_USERAGENT'])) {
|
||||
$curl_params[CURLOPT_USERAGENT] = $feed_elt['frss:CURLOPT_USERAGENT'];
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
?></li><?php
|
||||
endif; ?>
|
||||
<li class="item titleAuthorSummaryDate">
|
||||
<span class="item-element title<?= (($topline_thumbnail !== 'none') || $topline_summary) ? ' multiline' : '' ?>" dir="auto"><a target="_blank" rel="noreferrer" href="<?= $this->entry->link() ?>"><?= $this->entry->title() ?><?php
|
||||
<a target="_blank" rel="noreferrer" href="<?= $this->entry->link() ?>" class="item-element title<?= (($topline_thumbnail !== 'none') || $topline_summary) ? ' multiline' : '' ?>" dir="auto"><?= $this->entry->title() ?><?php
|
||||
if ($topline_display_authors):
|
||||
?><span class="author"><?php
|
||||
$authors = $this->entry->authors();
|
||||
|
@ -65,7 +65,7 @@
|
|||
}
|
||||
?></span><?php
|
||||
endif;
|
||||
?></a></span>
|
||||
?></a>
|
||||
<?php
|
||||
if ($topline_summary):
|
||||
?><div class="summary"><?= trim(mb_substr(strip_tags($this->entry->content(false)), 0, 500, 'UTF-8')) ?></div><?php
|
||||
|
|
|
@ -238,4 +238,19 @@ class Minz_ModelPdo {
|
|||
public function fetchColumn(string $sql, int $column, array $values = []): ?array {
|
||||
return $this->fetchAny($sql, $values, PDO::FETCH_COLUMN, $column);
|
||||
}
|
||||
|
||||
/** For retrieving a single value without prepared statement such as `SELECT version()` */
|
||||
public function fetchValue(string $sql): ?string {
|
||||
$stm = $this->pdo->query($sql);
|
||||
if ($stm === false) {
|
||||
Minz_Log::error('SQL error ' . json_encode($this->pdo->errorInfo()) . ' during ' . $sql);
|
||||
return null;
|
||||
}
|
||||
$columns = $stm->fetchAll(PDO::FETCH_COLUMN, 0);
|
||||
if ($columns === false) {
|
||||
Minz_Log::error('SQL error ' . json_encode($stm->errorInfo()) . ' during ' . $sql);
|
||||
return null;
|
||||
}
|
||||
return isset($columns[0]) ? (string)$columns[0] : null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1081,7 +1081,7 @@ function init_stream(stream) {
|
|||
return true;
|
||||
}
|
||||
|
||||
el = ev.target.closest('.item .title > a');
|
||||
el = ev.target.closest('.item a.title');
|
||||
if (el) { // Allow default control/command-click behaviour such as open in background-tab
|
||||
return ev.ctrlKey || ev.metaKey;
|
||||
}
|
||||
|
@ -1189,7 +1189,7 @@ function init_stream(stream) {
|
|||
return;
|
||||
}
|
||||
|
||||
let el = ev.target.closest('.item .title > a');
|
||||
let el = ev.target.closest('.item a.title');
|
||||
if (el) {
|
||||
if (ev.which == 1) {
|
||||
if (ev.ctrlKey) { // Control+click
|
||||
|
|
|
@ -759,7 +759,7 @@ kbd {
|
|||
background: var(--background-color-hover);
|
||||
}
|
||||
|
||||
.flux .flux_header .item .title a {
|
||||
.flux .flux_header .item .title {
|
||||
color: var(--font-color-light);
|
||||
}
|
||||
|
||||
|
|
|
@ -759,7 +759,7 @@ kbd {
|
|||
background: var(--background-color-hover);
|
||||
}
|
||||
|
||||
.flux .flux_header .item .title a {
|
||||
.flux .flux_header .item .title {
|
||||
color: var(--font-color-light);
|
||||
}
|
||||
|
||||
|
|
|
@ -184,7 +184,6 @@
|
|||
color: variables.$grey-dark;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.nav-form {
|
||||
|
|
|
@ -606,7 +606,6 @@ th {
|
|||
color: #766556;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
.nav-list .nav-form {
|
||||
padding: 3px;
|
||||
|
|
|
@ -606,7 +606,6 @@ th {
|
|||
color: #766556;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
.nav-list .nav-form {
|
||||
padding: 3px;
|
||||
|
|
|
@ -267,7 +267,6 @@ button.as-link[disabled] {
|
|||
|
||||
.nav-list .nav-header {
|
||||
background-color: var(--dark-background-color1);
|
||||
border-bottom: 1px solid var(--dark-border-color3);
|
||||
}
|
||||
|
||||
/*=== Dropdown */
|
||||
|
@ -452,7 +451,7 @@ button.as-link[disabled] {
|
|||
background-color: var(--dark-background-color1);
|
||||
}
|
||||
|
||||
.flux .flux_header .item .title a {
|
||||
.flux .flux_header .item .title {
|
||||
color: var(--dark-font-color8);
|
||||
}
|
||||
|
||||
|
|
|
@ -267,7 +267,6 @@ button.as-link[disabled] {
|
|||
|
||||
.nav-list .nav-header {
|
||||
background-color: var(--dark-background-color1);
|
||||
border-bottom: 1px solid var(--dark-border-color3);
|
||||
}
|
||||
|
||||
/*=== Dropdown */
|
||||
|
@ -452,7 +451,7 @@ button.as-link[disabled] {
|
|||
background-color: var(--dark-background-color1);
|
||||
}
|
||||
|
||||
.flux .flux_header .item .title a {
|
||||
.flux .flux_header .item .title {
|
||||
color: var(--dark-font-color8);
|
||||
}
|
||||
|
||||
|
|
|
@ -183,7 +183,6 @@
|
|||
color: variables.$grey-dark;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.nav-form {
|
||||
|
|
|
@ -620,7 +620,6 @@ th {
|
|||
color: #5b6871;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
.nav-list .nav-form {
|
||||
padding: 3px;
|
||||
|
|
|
@ -620,7 +620,6 @@ th {
|
|||
color: #5b6871;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
.nav-list .nav-form {
|
||||
padding: 3px;
|
||||
|
|
|
@ -661,7 +661,7 @@ img.favicon {
|
|||
}
|
||||
|
||||
.aside_feed .tree-folder-items.active {
|
||||
padding-bottom: 2rem;
|
||||
padding-bottom: 1rem;
|
||||
background-color: var(--main-background);
|
||||
}
|
||||
|
||||
|
@ -810,7 +810,7 @@ li.item.active {
|
|||
transition: .3s;
|
||||
}
|
||||
|
||||
.flux .flux_header .item .title a {
|
||||
.flux .flux_header .item .title {
|
||||
color: var(--text-default);
|
||||
}
|
||||
|
||||
|
@ -1114,7 +1114,7 @@ optgroup::before {
|
|||
}
|
||||
|
||||
.nav-list .nav-header {
|
||||
padding: 1rem 1rem 0 1rem;
|
||||
padding: 0 1rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
|
|
@ -661,7 +661,7 @@ img.favicon {
|
|||
}
|
||||
|
||||
.aside_feed .tree-folder-items.active {
|
||||
padding-bottom: 2rem;
|
||||
padding-bottom: 1rem;
|
||||
background-color: var(--main-background);
|
||||
}
|
||||
|
||||
|
@ -810,7 +810,7 @@ li.item.active {
|
|||
transition: .3s;
|
||||
}
|
||||
|
||||
.flux .flux_header .item .title a {
|
||||
.flux .flux_header .item .title {
|
||||
color: var(--text-default);
|
||||
}
|
||||
|
||||
|
@ -1114,7 +1114,7 @@ optgroup::before {
|
|||
}
|
||||
|
||||
.nav-list .nav-header {
|
||||
padding: 1rem 1rem 0 1rem;
|
||||
padding: 0 1rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
|
|
@ -404,7 +404,6 @@ a:hover .icon {
|
|||
.nav-list .nav-header {
|
||||
background-color: var(--background-color-grey);
|
||||
color: var(--font-color-grey);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
|
|
@ -404,7 +404,6 @@ a:hover .icon {
|
|||
.nav-list .nav-header {
|
||||
background-color: var(--background-color-grey);
|
||||
color: var(--font-color-grey);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
|
|
@ -328,7 +328,6 @@ th {
|
|||
padding: 0 1rem;
|
||||
background-color: var(--background-color-grey);
|
||||
color: var(--font-color-grey);
|
||||
border-bottom: 1px solid var(--border-color-grey-light);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
@ -803,7 +802,7 @@ a.signin {
|
|||
background-color: var(--background-color-grey-hover);
|
||||
}
|
||||
|
||||
.flux .flux_header:hover .title a {
|
||||
.flux .flux_header:hover .title {
|
||||
color: var(--font-color-hover);
|
||||
}
|
||||
|
||||
|
|
|
@ -328,7 +328,6 @@ th {
|
|||
padding: 0 1rem;
|
||||
background-color: var(--background-color-grey);
|
||||
color: var(--font-color-grey);
|
||||
border-bottom: 1px solid var(--border-color-grey-light);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
@ -803,7 +802,7 @@ a.signin {
|
|||
background-color: var(--background-color-grey-hover);
|
||||
}
|
||||
|
||||
.flux .flux_header:hover .title a {
|
||||
.flux .flux_header:hover .title {
|
||||
color: var(--font-color-hover);
|
||||
}
|
||||
|
||||
|
|
|
@ -641,6 +641,10 @@ input[type="checkbox"]:focus-visible {
|
|||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.nav-list .item.nav-section > ul {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
/*=== Horizontal-list */
|
||||
.horizontal-list {
|
||||
margin: 0;
|
||||
|
@ -1294,11 +1298,6 @@ a.website:hover .favicon {
|
|||
vertical-align: top;
|
||||
}
|
||||
|
||||
.flux .flux_header .item .title a {
|
||||
color: var(--frss-font-color-dark);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.flux .flux_header .item.thumbnail {
|
||||
line-height: 0;
|
||||
padding: var(--frss-padding-top-bottom) var(--frss-padding-flux-items);
|
||||
|
@ -1353,13 +1352,16 @@ a.website:hover .favicon {
|
|||
}
|
||||
|
||||
.flux .flux_header .item .title {
|
||||
display: inline-block;
|
||||
max-width: 100%;
|
||||
min-width: calc(100% - 155px);
|
||||
color: var(--frss-font-color-dark);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
max-width: 100%;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.flux .flux_header .item .title:has(~.date) {
|
||||
|
|
|
@ -641,6 +641,10 @@ input[type="checkbox"]:focus-visible {
|
|||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.nav-list .item.nav-section > ul {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
/*=== Horizontal-list */
|
||||
.horizontal-list {
|
||||
margin: 0;
|
||||
|
@ -1294,11 +1298,6 @@ a.website:hover .favicon {
|
|||
vertical-align: top;
|
||||
}
|
||||
|
||||
.flux .flux_header .item .title a {
|
||||
color: var(--frss-font-color-dark);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.flux .flux_header .item.thumbnail {
|
||||
line-height: 0;
|
||||
padding: var(--frss-padding-top-bottom) var(--frss-padding-flux-items);
|
||||
|
@ -1353,13 +1352,16 @@ a.website:hover .favicon {
|
|||
}
|
||||
|
||||
.flux .flux_header .item .title {
|
||||
display: inline-block;
|
||||
max-width: 100%;
|
||||
min-width: calc(100% - 155px);
|
||||
color: var(--frss-font-color-dark);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
max-width: 100%;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.flux .flux_header .item .title:has(~.date) {
|
||||
|
|
Loading…
Reference in New Issue