Skip to content

Commit

Permalink
imp: Display links grouped by sources in news
Browse files Browse the repository at this point in the history
  • Loading branch information
marienfressinaud committed Apr 1, 2024
1 parent 4a7ed7c commit f983561
Show file tree
Hide file tree
Showing 13 changed files with 295 additions and 11 deletions.
Binary file modified locales/fr_FR/LC_MESSAGES/main.mo
Binary file not shown.
20 changes: 10 additions & 10 deletions locales/fr_FR/LC_MESSAGES/main.po
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
msgid ""
msgstr ""
"Project-Id-Version: flusio\n"
"POT-Creation-Date: 2024-04-01 18:20+0200\n"
"PO-Revision-Date: 2024-04-01 18:20+0200\n"
"POT-Creation-Date: 2024-04-01 20:59+0200\n"
"PO-Revision-Date: 2024-04-01 20:59+0200\n"
"Last-Translator: Marien Fressinaud <dev@marienfressinaud.fr>\n"
"Language-Team: \n"
"Language: fr_FR\n"
Expand Down Expand Up @@ -2135,37 +2135,37 @@ msgstr ""
msgid "Never see the links again"
msgstr "Ne plus revoir les liens"

#: views/news/index.phtml:109
#: views/news/index.phtml:137
msgid ""
"Fill your news feed with the content published by the feeds that you follow."
msgstr ""
"Remplissez votre journal avec le contenu publié par les flux que vous suivez."

#: views/news/index.phtml:123
#: views/news/index.phtml:151
msgid "Refresh the news"
msgstr "Rafraichir le journal"

#: views/news/index.phtml:128
#: views/news/index.phtml:156
msgid "Fill the news with…"
msgstr "Remplissez votre journal avec…"

#: views/news/index.phtml:151
#: views/news/index.phtml:179
msgid "the latest publications"
msgstr "les dernières publications"

#: views/news/index.phtml:152
#: views/news/index.phtml:180
msgid "from your followed feeds"
msgstr "depuis vos flux suivis"

#: views/news/index.phtml:167
#: views/news/index.phtml:195
msgid "3 links of -10 minutes"
msgstr "3 liens de -10 minutes"

#: views/news/index.phtml:168 views/news/index.phtml:184
#: views/news/index.phtml:196 views/news/index.phtml:212
msgid "from your bookmarks"
msgstr "depuis vos signets"

#: views/news/index.phtml:183
#: views/news/index.phtml:211
msgid "1 link of +10 minutes"
msgstr "1 lien de +10 minutes"

Expand Down
22 changes: 22 additions & 0 deletions src/assets/stylesheets/custom/news.css
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,25 @@
background-color: var(--color-purple-1);
border-color: var(--color-purple-4);
}

.news__source-group {
margin-top: var(--space-medium);
margin-bottom: var(--space-medium);
}

@media (min-width: 800px) {
.news__source-group {
margin-left: var(--space-small);
padding-right: var(--space-smaller);
padding-left: var(--space-smaller);

border-left: var(--width-border-bold) solid var(--color-purple-1);
}
}

.news__source-title {
margin: 0;
padding: var(--space-small);

font-size: var(--size-normal);
}
6 changes: 6 additions & 0 deletions src/controllers/News.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,18 @@ public function create(Request $request): Response
$link->source_resource_id = $news_link->source_news_resource_id;
}

// Make sure to reset this value: it will be set to true later with
// Link::groupLinksBySources
$link->group_by_source = false;

$link->save();

// And don't forget to add the link to the news collection!
models\LinkToCollection::attach([$link->id], [$news->id], $news_link->published_at);
}

models\Link::groupLinksBySources($news->id);

if (!$links) {
\Minz\Flash::set('no_news', true);
}
Expand Down
30 changes: 30 additions & 0 deletions src/migrations/Migration202404010002AddGroupBySourceToLinks.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace flusio\migrations;

class Migration202404010002AddGroupBySourceToLinks
{
public function migrate(): bool
{
$database = \Minz\Database::get();

$database->exec(<<<'SQL'
ALTER TABLE links
ADD COLUMN group_by_source BOOLEAN NOT NULL DEFAULT false;
SQL);

return true;
}

public function rollback(): bool
{
$database = \Minz\Database::get();

$database->exec(<<<'SQL'
ALTER TABLE links
DROP COLUMN group_by_source;
SQL);

return true;
}
}
14 changes: 14 additions & 0 deletions src/models/Link.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ class Link
#[Database\Column]
public ?string $source_resource_id = null;

#[Database\Column]
public bool $group_by_source = false;

#[Database\Column(computed: true)]
public ?string $source_news_type = null;

Expand Down Expand Up @@ -189,6 +192,17 @@ public function sourceUser(): ?User
return User::find($this->source_resource_id);
}

public function source(): User|Collection|null
{
if ($this->source_type == 'user') {
return $this->sourceUser();
} elseif ($this->source_type == 'collection') {
return $this->sourceCollection();
} else {
return null;
}
}

/**
* Return whether or not the given user has the link URL in its bookmarks.
*/
Expand Down
55 changes: 55 additions & 0 deletions src/models/dao/links/NewsQueries.php
Original file line number Diff line number Diff line change
Expand Up @@ -156,4 +156,59 @@ public static function listFromFollowedCollectionsForNews(

return self::fromDatabaseRows($statement->fetchAll());
}

/**
* Mark the relevant links to be grouped by sources in the given collection.
*
* Links are grouped if there are several links in the given collection
* corresponding to the same source and the same day.
*
* The passed collection_id must correspond to a "news" collection. For
* now, it's passed this way to improve performance and to simplify a bit
* the SQL request.
*/
public static function groupLinksBySources(string $collection_id): bool
{
$sql = <<<SQL
UPDATE links
SET group_by_source = true
WHERE links.id IN (
-- Create a "temporary table" to select the available sources
-- from the given collection (e.g. sources that are
-- referenced by more than 1 link).
WITH sources AS (
SELECT date_trunc('day', slc.created_at) AS published_day,
sl.source_type,
sl.source_resource_id
FROM links sl, links_to_collections slc
WHERE sl.id = slc.link_id
AND slc.collection_id = :collection_id
GROUP BY published_day, sl.source_type, sl.source_resource_id
HAVING COUNT(sl.id) > 1
)
-- Select the ids of links which have a source corresponding to
-- one of the selected sources.
SELECT l.id
FROM links l, links_to_collections lc, sources s
WHERE l.id = lc.link_id
AND lc.collection_id = :collection_id
AND l.source_type = s.source_type
AND l.source_resource_id = s.source_resource_id
AND date_trunc('day', lc.created_at) = s.published_day
);
SQL;

$parameters = [
':collection_id' => $collection_id,
];

$database = Database::get();
$statement = $database->prepare($sql);
return $statement->execute($parameters);
}
}
1 change: 1 addition & 0 deletions src/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ CREATE TABLE links (

source_type TEXT NOT NULL DEFAULT '',
source_resource_id TEXT,
group_by_source BOOLEAN NOT NULL DEFAULT false,

search_index TSVECTOR GENERATED ALWAYS AS (to_tsvector('french', title || ' ' || url)) STORED,
url_lookup TEXT GENERATED ALWAYS AS (simplify_url(url)) STORED,
Expand Down
2 changes: 1 addition & 1 deletion src/utils/LinksTimeline.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public function __construct(array $links)
$this->dates_groups[$date_key] = $date_group;
}

$date_group->links[] = $link;
$date_group->addLink($link);
}
}

Expand Down
38 changes: 38 additions & 0 deletions src/utils/LinksTimeline/DateGroup.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace flusio\utils\LinksTimeline;

use flusio\models;
use flusio\utils;

/**
* @author Marien Fressinaud <dev@marienfressinaud.fr>
Expand All @@ -15,11 +16,38 @@ class DateGroup
/** @var models\Link[] */
public array $links = [];

/** @var array<string, SourceGroup> */
public array $source_groups = [];

public function __construct(\DateTimeImmutable $date)
{
$this->date = $date;
}

public function addLink(models\Link $link): void
{
if ($link->group_by_source) {
$source_key = $link->source_type . '#' . $link->source_resource_id;
if (isset($this->source_groups[$source_key])) {
$source_group = $this->source_groups[$source_key];
} else {
$source = $link->source();

if (!$source) {
$this->links[] = $link;
return;
}

$source_group = new SourceGroup($source);
$this->source_groups[$source_key] = $source_group;
}

$source_group->links[] = $link;
} else {
$this->links[] = $link;
}
}

public function isToday(): bool
{
$today = \Minz\Time::now();
Expand All @@ -31,4 +59,14 @@ public function isYesterday(): bool
$yesterday = \Minz\Time::ago(1, 'day');
return $this->date->format('Y-m-d') === $yesterday->format('Y-m-d');
}

/**
* Return the source groups sorted by titles.
*
* @return SourceGroup[]
*/
public function sourceGroups(): array
{
return utils\Sorter::localeSort($this->source_groups, 'title');
}
}
34 changes: 34 additions & 0 deletions src/utils/LinksTimeline/SourceGroup.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace flusio\utils\LinksTimeline;

use flusio\models;

/**
* @author Marien Fressinaud <dev@marienfressinaud.fr>
* @license http://www.gnu.org/licenses/agpl-3.0.en.html AGPL
*/
class SourceGroup
{
/** @var models\Collection|models\User */
public mixed $source;

public string $title;

/** @var models\Link[] */
public array $links = [];

/**
* @param models\Collection|models\User $source
**/
public function __construct(mixed $source)
{
$this->source = $source;

if ($this->source instanceof models\Collection) {
$this->title = $this->source->name();
} else {
$this->title = $this->source->username;
}
}
}
28 changes: 28 additions & 0 deletions src/views/news/index.phtml
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,34 @@
]); ?>
<?php endforeach; ?>
</div>

<?php foreach ($date_group->sourceGroups() as $source_group): ?>
<div class="news__source-group">
<h3 class="news__source-title">
<?= protect($source_group->title) ?>

<small class="text--secondary">
<?= _nf('%s link', '%s links', count($source_group->links), count($source_group->links)) ?>
</small>
</h3>

<div class="cards">
<?php foreach ($source_group->links as $link): ?>
<?= $this->include('links/_link.phtml', [
'link' => $link,
'from' => \Minz\Url::for('news'),
'display_edit' => true,
'display_repair' => true,
'display_source' => true,
'display_read_later' => true,
'display_mark_as_read' => true,
'display_never' => true,
'storing_must_mark_as_read' => true,
]); ?>
<?php endforeach; ?>
</div>
</div>
<?php endforeach; ?>
</section>
<?php endforeach; ?>
<?php elseif ($beta_enabled): ?>
Expand Down

0 comments on commit f983561

Please sign in to comment.