Fix muting of feeds gone with HTTP 410 (#9391)

* Fix muting of feeds gone with HTTP 410

A feed answering HTTP 410 Gone is meant to be muted (#3561), but:

* Since #6037, FreshRSS_Feed_Exception extends Minz_Exception, which
  resets any code other than its own error levels to 0, so the check for
  410 never matched. FreshRSS_Feed_Exception now keeps the HTTP status
  code it is given.
* FreshRSS_FeedDAO::mute() mutes by negating the TTL, which leaves a feed
  with the default TTL (0) unmuted. Mute the feed the way the feed
  settings and dynamic OPML categories do instead.

* A bit of cleaning

---------

Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
This commit is contained in:
Nikolai ShcheglovandAlexandre Alapetite authored and GitHub committed 2026-10-03 09:59:51 +02:00
1 parent a4dbc4240d
commit a93bd27b7d
4 files changed
+23 -20

No files matched your search

+2 -2
View File
@@ -606,8 +606,8 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController {
if ($e->getCode() === 410) {
// HTTP 410 Gone
Minz_Log::warning('Muting gone feed: ' . $feed->url(false));
$feedDAO->mute($feed->id(), true);
$feed->_ttl(-abs($feed->ttl())); // Replicate behavior of line above which acts directly into the DB
$feed->_mute(true);
$feedDAO->updateFeed($feed->id(), ['ttl' => $feed->ttl(raw: true)]); // Also when the feed has the default TTL (0)
}
$feed->unlock();
continue;
+7
View File
@@ -3,4 +3,11 @@ declare(strict_types=1);
class FreshRSS_Feed_Exception extends Minz_Exception {
/**
* @param int $code The HTTP status code when known, e.g. 410 Gone, which mutes the feed
*/
public function __construct(string $message = '', int $code = 0, ?Throwable $previous = null) {
parent::__construct($message, previous: $previous);
$this->code = $code; // Minz_Exception would reset it, keeping only its own error levels
}
}
-18
View File
@@ -261,24 +261,6 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo {
}
}
public function mute(int $id, bool $value = true): int|false {
$sign = $value ? '-' : '';
$sql = <<<SQL
UPDATE `_feed`
SET ttl = {$sign}ABS(ttl)
WHERE id = :id
SQL;
$stm = $this->pdo->prepare($sql);
if ($stm !== false &&
$stm->bindValue(':id', $id, PDO::PARAM_INT) &&
$stm->execute()) {
return $stm->rowCount();
}
$info = $stm === false ? $this->pdo->errorInfo() : $stm->errorInfo();
Minz_Log::error('SQL error ' . __METHOD__ . json_encode($info));
return false;
}
public function changeCategory(int $idOldCat, int $idNewCat): int|false {
$catDAO = FreshRSS_Factory::createCategoryDao();
$newCat = $catDAO->searchById($idNewCat);
@@ -0,0 +1,14 @@
<?php
declare(strict_types=1);
final class FeedExceptionTest extends \PHPUnit\Framework\TestCase {
public function test_keepsHttpStatusCode(): void {
$previous = new RuntimeException('previous');
$e = new FreshRSS_Feed_Exception('Gone', 410, $previous);
self::assertSame(410, $e->getCode()); // feedController mutes a feed on HTTP 410 Gone
self::assertSame('Gone', $e->getMessage());
self::assertSame($previous, $e->getPrevious());
self::assertSame(0, (new FreshRSS_Feed_Exception())->getCode());
}
}