mirror of
https://github.com/FreshRSS/FreshRSS.git
synced 2026-04-24 00:07:59 -04:00
Add feed visibility filter to unread dates view (#8489)
* Add feed visibility filter to unread dates view * Date field sanitize
This commit is contained in:
committed by
GitHub
parent
6b5304b825
commit
f17ed2f7c8
@@ -257,7 +257,8 @@ class FreshRSS_stats_Controller extends FreshRSS_ActionController {
|
||||
if (!in_array($granularity, ['day', 'month', 'year'], true)) {
|
||||
$granularity = 'day';
|
||||
}
|
||||
$dates = $statsDAO->getMaxUnreadDates($field, $granularity, Minz_Request::paramInt('max') ?: 100);
|
||||
$dates = $statsDAO->getMaxUnreadDates($field, $granularity, Minz_Request::paramInt('max') ?: 100,
|
||||
Minz_Request::paramIntNull('min_priority') ?? FreshRSS_Feed::PRIORITY_HIDDEN);
|
||||
$this->view->unreadDates = $dates;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ class FreshRSS_StatsDAO extends Minz_ModelPdo {
|
||||
* @param 'day'|'month'|'year' $granularity of the date intervals
|
||||
*/
|
||||
protected function sqlDateToIsoGranularity(string $field, int $precision, string $granularity): string {
|
||||
if (!preg_match('/^[a-zA-Z0-9_]+$/', $field)) {
|
||||
if (!preg_match('/^[a-zA-Z0-9_.]+$/', $field)) {
|
||||
throw new InvalidArgumentException('Invalid date field!');
|
||||
}
|
||||
$offset = $this->getTimezoneOffset();
|
||||
@@ -388,19 +388,28 @@ SQL;
|
||||
* @param 'day'|'month'|'year' $granularity of the date intervals
|
||||
* @return list<array{'granularity':string,'unread_count':int}>
|
||||
*/
|
||||
public function getMaxUnreadDates(string $field, string $granularity, int $max = 100): array {
|
||||
public function getMaxUnreadDates(string $field, string $granularity, int $max = 100, int $minPriority = FreshRSS_Feed::PRIORITY_HIDDEN): array {
|
||||
$sql = <<<SQL
|
||||
SELECT
|
||||
{$this->sqlDateToIsoGranularity($field, precision: $field === 'id' ? 1000000 : 1, granularity: $granularity)} AS granularity,
|
||||
COUNT(*) AS unread_count
|
||||
FROM `_entry`
|
||||
WHERE is_read = 0
|
||||
GROUP BY granularity
|
||||
ORDER BY unread_count DESC, granularity DESC
|
||||
LIMIT $max;
|
||||
SQL;
|
||||
$res = $this->fetchAssoc($sql);
|
||||
/** @var list<array{granularity:string,unread_count:int}>|null $res */
|
||||
return is_array($res) ? $res : [];
|
||||
SELECT
|
||||
{$this->sqlDateToIsoGranularity('e.' . $field, precision: $field === 'id' ? 1000000 : 1, granularity: $granularity)} AS granularity,
|
||||
COUNT(*) AS unread_count
|
||||
FROM `_entry` e
|
||||
INNER JOIN `_feed` f ON e.id_feed = f.id
|
||||
WHERE e.is_read = 0 AND f.priority >= :min_priority
|
||||
GROUP BY granularity
|
||||
ORDER BY unread_count DESC, granularity DESC
|
||||
LIMIT :max
|
||||
SQL;
|
||||
if (($stm = $this->pdo->prepare($sql)) !== false &&
|
||||
$stm->bindValue(':min_priority', $minPriority, PDO::PARAM_INT) &&
|
||||
$stm->bindValue(':max', $max, PDO::PARAM_INT) &&
|
||||
$stm->execute() && is_array($res = $stm->fetchAll(PDO::FETCH_ASSOC))) {
|
||||
/** @var list<array{granularity:string,unread_count:int}> $res */
|
||||
return $res;
|
||||
} else {
|
||||
$info = $stm === false ? $this->pdo->errorInfo() : $stm->errorInfo();
|
||||
Minz_Log::error('SQL error ' . __METHOD__ . json_encode($info));
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,9 @@ class FreshRSS_StatsDAOPGSQL extends FreshRSS_StatsDAO {
|
||||
|
||||
#[\Override]
|
||||
protected function sqlDateToIsoGranularity(string $field, int $precision, string $granularity): string {
|
||||
if (!preg_match('/^[a-zA-Z0-9_.]+$/', $field)) {
|
||||
throw new InvalidArgumentException('Invalid date field!');
|
||||
}
|
||||
$offset = $this->getTimezoneOffset();
|
||||
return match ($granularity) {
|
||||
'day' => "to_char(to_timestamp(($field / $precision) + $offset), 'YYYY-MM-DD')",
|
||||
|
||||
@@ -5,6 +5,9 @@ class FreshRSS_StatsDAOSQLite extends FreshRSS_StatsDAO {
|
||||
|
||||
#[\Override]
|
||||
protected function sqlDateToIsoGranularity(string $field, int $precision, string $granularity): string {
|
||||
if (!preg_match('/^[a-zA-Z0-9_.]+$/', $field)) {
|
||||
throw new InvalidArgumentException('Invalid date field!');
|
||||
}
|
||||
$offset = $this->getTimezoneOffset();
|
||||
return match ($granularity) {
|
||||
'day' => "strftime('%Y-%m-%d', ($field / $precision) + $offset, 'unixepoch')",
|
||||
|
||||
@@ -18,6 +18,14 @@
|
||||
<option value="month" <?= Minz_Request::paramString('granularity') === 'month' ? 'selected="selected"' : '' ?>><?= _t('gen.period.months') ?></option>
|
||||
<option value="year" <?= Minz_Request::paramString('granularity') === 'year' ? 'selected="selected"' : '' ?>><?= _t('gen.period.years') ?></option>
|
||||
</select>
|
||||
<select name="min_priority" id="min_priority">
|
||||
<?php $currentPriority = Minz_Request::paramIntNull('min_priority'); ?>
|
||||
<option value=""><?= _t('sub.feed.priority._') ?></option>
|
||||
<option value="<?= FreshRSS_Feed::PRIORITY_IMPORTANT ?>" <?= $currentPriority === FreshRSS_Feed::PRIORITY_IMPORTANT ? 'selected="selected"' : '' ?>><?= _t('sub.feed.priority.important') ?></option>
|
||||
<option value="<?= FreshRSS_Feed::PRIORITY_MAIN_STREAM ?>" <?= $currentPriority === FreshRSS_Feed::PRIORITY_MAIN_STREAM ? 'selected="selected"' : '' ?>><?= _t('sub.feed.priority.main_stream') ?></option>
|
||||
<option value="<?= FreshRSS_Feed::PRIORITY_CATEGORY ?>" <?= $currentPriority === FreshRSS_Feed::PRIORITY_CATEGORY ? 'selected="selected"' : '' ?>><?= _t('sub.feed.priority.category') ?></option>
|
||||
<option value="<?= FreshRSS_Feed::PRIORITY_FEED ?>" <?= $currentPriority === FreshRSS_Feed::PRIORITY_FEED ? 'selected="selected"' : '' ?>><?= _t('sub.feed.priority.feed') ?></option>
|
||||
</select>
|
||||
<button type="submit" class="btn btn-important"><?= _t('gen.action.submit') ?></button>
|
||||
</form>
|
||||
<table>
|
||||
|
||||
Reference in New Issue
Block a user